diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 00000000..75472f35 --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,31 @@ +name: Python Linting + +on: [push, pull_request] + +jobs: + ruff: + name: Run Ruff + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - name: Install Ruff + run: pip install ruff + + - name: Run Ruff (Check) + run: ruff check . --exclude "**/problem.py,**/solution.py,**" + + - name: Run Ruff (Format Check) + run: ruff format --check . --exclude "**/problem.py,**/solution.py,**" + + - name: Run Ruff (Fix Check) + run: ruff check . --fix --exclude "**/problem.py,**/solution.py,**" + + - name: Run Ruff (Fix) + run: ruff format . --exclude "**/problem.py,**/solution.py,**" \ No newline at end of file diff --git a/old_repo/Problems/100_Softsign/solution.py b/old_repo/Problems/100_Softsign/solution.py index 7069a041..4f274e7d 100644 --- a/old_repo/Problems/100_Softsign/solution.py +++ b/old_repo/Problems/100_Softsign/solution.py @@ -1,31 +1,33 @@ def softsign(x: float) -> float: """ Implements the Softsign activation function. - + Args: x (float): Input value - + Returns: float: The Softsign of the input, calculated as x/(1 + |x|) """ return x / (1 + abs(x)) + def test_softsign(): # Test case 1: x = 0 assert abs(softsign(0) - 0) < 1e-7, "Test case 1 failed" - + # Test case 2: x = 1 assert abs(softsign(1) - 0.5) < 1e-7, "Test case 2 failed" - + # Test case 3: x = -1 assert abs(softsign(-1) - (-0.5)) < 1e-7, "Test case 3 failed" - + # Test case 4: large positive number assert abs(softsign(100) - 0.9901) < 1e-4, "Test case 4 failed" - + # Test case 5: large negative number assert abs(softsign(-100) - (-0.9901)) < 1e-4, "Test case 5 failed" + if __name__ == "__main__": test_softsign() print("All Softsign tests passed.") diff --git a/old_repo/Problems/102_Swish/solution.py b/old_repo/Problems/102_Swish/solution.py index c0c31b72..057002b4 100644 --- a/old_repo/Problems/102_Swish/solution.py +++ b/old_repo/Problems/102_Swish/solution.py @@ -1,37 +1,39 @@ import math + def swish(x: float) -> float: """ Implements the Swish activation function. - + Args: x: Input value - + Returns: The Swish activation value """ return x * (1 / (1 + math.exp(-x))) + def test_swish(): # Test case 1: x = 0 assert abs(swish(0) - 0) < 1e-6, "Test case 1 failed" - + # Test case 2: x = 1 expected = 1 * (1 / (1 + math.exp(-1))) assert abs(swish(1) - expected) < 1e-6, "Test case 2 failed" - + # Test case 3: x = -1 expected = -1 * (1 / (1 + math.exp(1))) assert abs(swish(-1) - expected) < 1e-6, "Test case 3 failed" - + # Test case 4: large positive number x = 10.0 assert abs(swish(x) - x) < 0.01, "Test case 4 failed" # Should be close to x - + # Test case 5: large negative number assert abs(swish(-10.0)) < 0.01, "Test case 5 failed" # Should be close to 0 + if __name__ == "__main__": test_swish() print("All Swish tests passed.") - \ No newline at end of file diff --git a/old_repo/Problems/103_SELU/solution.py b/old_repo/Problems/103_SELU/solution.py index 589a8230..6331e319 100644 --- a/old_repo/Problems/103_SELU/solution.py +++ b/old_repo/Problems/103_SELU/solution.py @@ -1,39 +1,42 @@ import math + def selu(x: float) -> float: """ Implements the SELU (Scaled Exponential Linear Unit) activation function. - + Args: x: Input value - + Returns: SELU activation value """ # Standard SELU parameters alpha = 1.6732632423543772848170429916717 scale = 1.0507009873554804934193349852946 - + if x > 0: return scale * x return scale * alpha * (math.exp(x) - 1) + def test_selu(): # Test positive input assert abs(selu(1.0) - 1.0507009873554804) < 1e-7, "Test case 1 failed" - + # Test zero input assert abs(selu(0.0) - 0.0) < 1e-7, "Test case 2 failed" - + # Test negative input assert abs(selu(-1.0) - (-1.1113307)) < 1e-6, "Test case 3 failed" - + # Test large positive input assert abs(selu(5.0) - 5.2535049) < 1e-6, "Test case 4 failed" - + # Test large negative input assert abs(selu(-5.0) - (-1.7462534)) < 1e-6, "Test case 5 failed" + if __name__ == "__main__": test_selu() - print("All SELU tests passed.") \ No newline at end of file + print("All SELU tests passed.") diff --git a/old_repo/Problems/104_logistic_regression/solution.py b/old_repo/Problems/104_logistic_regression/solution.py index 473320a6..035d950a 100644 --- a/old_repo/Problems/104_logistic_regression/solution.py +++ b/old_repo/Problems/104_logistic_regression/solution.py @@ -1,12 +1,13 @@ import numpy as np -def predict_logistic(X: np.ndarray, weights: np.ndarray, bias: float) -> np.ndarray: +def predict_logistic(X: np.ndarray, weights: np.ndarray, bias: float) -> np.ndarray: z = np.dot(X, weights) + bias z = np.clip(z, -500, 500) # Prevent overflow in exp probabilities = 1 / (1 + np.exp(-z)) return (probabilities >= 0.5).astype(int) + def test_predict_logistic(): # Test case 1: Simple linearly separable case X1 = np.array([[1, 1], [2, 2], [-1, -1], [-2, -2]]) @@ -29,20 +30,21 @@ def test_predict_logistic(): expected3 = np.array([1, 0, 0]) assert np.array_equal(predict_logistic(X3, w3, b3), expected3), "Test case 3 failed" -# # Test case 4: Single feature + # # Test case 4: Single feature X4 = np.array([[1], [2], [-1], [-2]]).reshape(-1, 1) w4 = np.array([2]) b4 = 0 expected4 = np.array([1, 1, 0, 0]) assert np.array_equal(predict_logistic(X4, w4, b4), expected4), "Test case 4 failed" -# # Test case 5: Numerical stability test with large values + # # Test case 5: Numerical stability test with large values X6 = np.array([[1000, 2000], [-1000, -2000]]) w6 = np.array([0.1, 0.1]) b6 = 0 result6 = predict_logistic(X6, w6, b6) assert result6[0] == 1 and result6[1] == 0, "Test case 5 failed" + if __name__ == "__main__": test_predict_logistic() - print("All test cases passed!") \ No newline at end of file + print("All test cases passed!") diff --git a/old_repo/Problems/105_train_softmaxreg/solution.py b/old_repo/Problems/105_train_softmaxreg/solution.py index 581a788b..6d41a79c 100644 --- a/old_repo/Problems/105_train_softmaxreg/solution.py +++ b/old_repo/Problems/105_train_softmaxreg/solution.py @@ -1,9 +1,10 @@ import numpy as np -def train_softmaxreg(X: np.ndarray, y: np.ndarray, - learning_rate: float, iterations: int) -> tuple[list[float], ...]: - """ +def train_softmaxreg( + X: np.ndarray, y: np.ndarray, learning_rate: float, iterations: int +) -> tuple[list[float], ...]: + """ Gradient-descent training algorithm for softmax regression, that collects mean-reduced CE losses, accuracies. Returns @@ -18,14 +19,16 @@ def softmax(z): return np.exp(z) / np.sum(np.exp(z), axis=1, keepdims=True) def accuracy(y_pred, y_true): - return (np.argmax(y_true, axis=1) == np.argmax(y_pred, axis=1)).sum() / len(y_true) + return (np.argmax(y_true, axis=1) == np.argmax(y_pred, axis=1)).sum() / len( + y_true + ) def ce_loss(y_pred, y_true): true_labels_idx = np.argmax(y_true, axis=1) - return -np.sum(np.log(y_pred)[list(range(len(y_pred))),true_labels_idx]) - + return -np.sum(np.log(y_pred)[list(range(len(y_pred))), true_labels_idx]) + y = y.astype(int) - C = y.max()+1 # we assume that classes start from 0 + C = y.max() + 1 # we assume that classes start from 0 y = np.eye(C)[y] X = np.hstack((np.ones((X.shape[0], 1)), X)) B = np.zeros((X.shape[1], C)) @@ -42,50 +45,72 @@ def ce_loss(y_pred, y_true): def test_train_softmaxreg(): # Test 1 - X = np.array([[ 2.52569869, 2.33335813, 1.77303921, 0.41061103, -1.66484491], - [ 1.51013861, 1.30237106, 1.31989315, 1.36087958, 0.46381252], - [-2.09699866, -1.35960405, -1.04035503, -2.25481082, -0.32359947], - [-0.96660088, -0.60680633, -0.72017167, -1.73257187, -1.12811486], - [-0.38096611, -0.24852455, 0.18789426, 0.52359424, 1.30725962], - [ 0.54828787, 0.33156614, 0.10676247, 0.30694669, -0.37555384], - [-3.03393135, -2.01966141, -0.6546858 , -0.90330912, 2.89185791], - [ 0.28602304, -0.1265 , -0.52209915, 0.28309144, -0.5865882 ], - [-0.26268117, 0.76017979, 1.84095557, -0.23245038, 1.80716891], - [ 0.30283562, -0.40231495, -1.29550644, -0.1422727 , -1.78121713]]) + X = np.array( + [ + [2.52569869, 2.33335813, 1.77303921, 0.41061103, -1.66484491], + [1.51013861, 1.30237106, 1.31989315, 1.36087958, 0.46381252], + [-2.09699866, -1.35960405, -1.04035503, -2.25481082, -0.32359947], + [-0.96660088, -0.60680633, -0.72017167, -1.73257187, -1.12811486], + [-0.38096611, -0.24852455, 0.18789426, 0.52359424, 1.30725962], + [0.54828787, 0.33156614, 0.10676247, 0.30694669, -0.37555384], + [-3.03393135, -2.01966141, -0.6546858, -0.90330912, 2.89185791], + [0.28602304, -0.1265, -0.52209915, 0.28309144, -0.5865882], + [-0.26268117, 0.76017979, 1.84095557, -0.23245038, 1.80716891], + [0.30283562, -0.40231495, -1.29550644, -0.1422727, -1.78121713], + ] + ) y = np.array([2, 3, 0, 0, 1, 3, 0, 1, 2, 1]) learning_rate = 3e-2 iterations = 10 - expected_b = [[-0.0841, -0.5693, -0.3651, -0.2423, -0.5344, 0.0339], - [0.2566, 0.0535, -0.2104, -0.4004, 0.2709, -0.1461], - [-0.1318, 0.2109, 0.3998, 0.523, -0.1001, 0.0545], - [-0.0407, 0.3049, 0.1757, 0.1197, 0.3637, 0.0576]] - expected_losses = [13.8629, 10.7201, 9.3163, 8.4942, 7.9132, - 7.4598, 7.0854, 6.7653, 6.4851, 6.2358] + expected_b = [ + [-0.0841, -0.5693, -0.3651, -0.2423, -0.5344, 0.0339], + [0.2566, 0.0535, -0.2104, -0.4004, 0.2709, -0.1461], + [-0.1318, 0.2109, 0.3998, 0.523, -0.1001, 0.0545], + [-0.0407, 0.3049, 0.1757, 0.1197, 0.3637, 0.0576], + ] + expected_losses = [ + 13.8629, + 10.7201, + 9.3163, + 8.4942, + 7.9132, + 7.4598, + 7.0854, + 6.7653, + 6.4851, + 6.2358, + ] b, ce = train_softmaxreg(X, y, learning_rate, iterations) - assert b == expected_b and ce == expected_losses, 'Test case 1 failed' + assert b == expected_b and ce == expected_losses, "Test case 1 failed" # Test 2 - X = np.array([[-0.55605887, -0.74922526, -0.1913345 , 0.41584056], - [-1.05481124, -1.13763371, -1.28685937, -1.0710115 ], - [-1.17111877, -1.46866663, -0.75898143, 0.15915148], - [-1.21725723, -1.55590285, -0.69318542, 0.3580615 ], - [-1.90316075, -2.06075824, -2.2952422 , -1.87885386], - [-0.79089629, -0.98662696, -0.52955027, 0.07329079], - [ 1.97170638, 2.65609694, 0.6802377 , -1.47090364], - [ 1.46907396, 1.61396429, 1.69602021, 1.29791351], - [ 0.03095068, 0.15148081, -0.34698116, -0.74306029], - [-1.40292946, -1.99308861, -0.1478281 , 1.72332995]]) - y = np.array([1., 0., 0., 1., 0., 1., 0., 1., 0., 1.]) + X = np.array( + [ + [-0.55605887, -0.74922526, -0.1913345, 0.41584056], + [-1.05481124, -1.13763371, -1.28685937, -1.0710115], + [-1.17111877, -1.46866663, -0.75898143, 0.15915148], + [-1.21725723, -1.55590285, -0.69318542, 0.3580615], + [-1.90316075, -2.06075824, -2.2952422, -1.87885386], + [-0.79089629, -0.98662696, -0.52955027, 0.07329079], + [1.97170638, 2.65609694, 0.6802377, -1.47090364], + [1.46907396, 1.61396429, 1.69602021, 1.29791351], + [0.03095068, 0.15148081, -0.34698116, -0.74306029], + [-1.40292946, -1.99308861, -0.1478281, 1.72332995], + ] + ) + y = np.array([1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0]) learning_rate = 1e-2 iterations = 7 - expected_b = [[-0.0052, 0.0148, 0.0562, -0.113, -0.2488], - [0.0052, -0.0148, -0.0562, 0.113, 0.2488]] + expected_b = [ + [-0.0052, 0.0148, 0.0562, -0.113, -0.2488], + [0.0052, -0.0148, -0.0562, 0.113, 0.2488], + ] expected_losses = [6.9315, 6.4544, 6.0487, 5.7025, 5.4055, 5.1493, 4.9269] b, ce = train_softmaxreg(X, y, learning_rate, iterations) - assert b == expected_b and ce == expected_losses, 'Test case 2 failed' + assert b == expected_b and ce == expected_losses, "Test case 2 failed" - print('All tests passed') + print("All tests passed") -if __name__ == '__main__': - test_train_softmaxreg() \ No newline at end of file +if __name__ == "__main__": + test_train_softmaxreg() diff --git a/old_repo/Problems/106_train_logreg/solution.py b/old_repo/Problems/106_train_logreg/solution.py index dc50ff52..efb2970c 100644 --- a/old_repo/Problems/106_train_logreg/solution.py +++ b/old_repo/Problems/106_train_logreg/solution.py @@ -1,9 +1,10 @@ import numpy as np -def train_logreg(X: np.ndarray, y: np.ndarray, - learning_rate: float, iterations: int) -> tuple[list[float], ...]: - """ +def train_logreg( + X: np.ndarray, y: np.ndarray, learning_rate: float, iterations: int +) -> tuple[list[float], ...]: + """ Gradient-descent training algorithm for logistic regression, that collects sum-reduced BCE losses, accuracies. Assigns label "0" if the P(x_i)<=0.5 and "1" otherwise. @@ -20,7 +21,7 @@ def sigmoid(x): def accuracy(y_pred, y_true): return (y_true == np.rint(y_pred)).sum() / len(y_true) - + def bce_loss(y_pred, y_true): return -np.sum(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred)) @@ -40,45 +41,71 @@ def bce_loss(y_pred, y_true): def test_train_logreg(): # Test 1 - X = np.array([[ 0.76743473, -0.23413696, -0.23415337, 1.57921282], - [-1.4123037 , 0.31424733, -1.01283112, -0.90802408], - [-0.46572975, 0.54256004, -0.46947439, -0.46341769], - [-0.56228753, -1.91328024, 0.24196227, -1.72491783], - [-1.42474819, -0.2257763 , 1.46564877, 0.0675282 ], - [ 1.85227818, -0.29169375, -0.60063869, -0.60170661], - [ 0.37569802, 0.11092259, -0.54438272, -1.15099358], - [ 0.19686124, -1.95967012, 0.2088636 , -1.32818605], - [ 1.52302986, -0.1382643 , 0.49671415, 0.64768854], - [-1.22084365, -1.05771093, -0.01349722, 0.82254491]]) - y = np.array([1., 0., 0., 0., 1., 1., 0., 0., 1., 0.]) + X = np.array( + [ + [0.76743473, -0.23413696, -0.23415337, 1.57921282], + [-1.4123037, 0.31424733, -1.01283112, -0.90802408], + [-0.46572975, 0.54256004, -0.46947439, -0.46341769], + [-0.56228753, -1.91328024, 0.24196227, -1.72491783], + [-1.42474819, -0.2257763, 1.46564877, 0.0675282], + [1.85227818, -0.29169375, -0.60063869, -0.60170661], + [0.37569802, 0.11092259, -0.54438272, -1.15099358], + [0.19686124, -1.95967012, 0.2088636, -1.32818605], + [1.52302986, -0.1382643, 0.49671415, 0.64768854], + [-1.22084365, -1.05771093, -0.01349722, 0.82254491], + ] + ) + y = np.array([1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0]) learning_rate = 1e-3 iterations = 10 b, llf = train_logreg(X, y, learning_rate, iterations) - assert b == [-0.0097, 0.0286, 0.015, 0.0135, 0.0316] and \ - llf == [6.9315, 6.9075, 6.8837, 6.8601, 6.8367, 6.8134, 6.7904, 6.7675, 6.7448, 6.7223], \ - 'Test case 1 failed' + assert b == [-0.0097, 0.0286, 0.015, 0.0135, 0.0316] and llf == [ + 6.9315, + 6.9075, + 6.8837, + 6.8601, + 6.8367, + 6.8134, + 6.7904, + 6.7675, + 6.7448, + 6.7223, + ], "Test case 1 failed" # Test 2 - X = np.array([[ 0.76743473, 1.57921282, -0.46947439], - [-0.23415337, 1.52302986, -0.23413696], - [ 0.11092259, -0.54438272, -1.15099358], - [-0.60063869, 0.37569802, -0.29169375], - [-1.91328024, 0.24196227, -1.72491783], - [-1.01283112, -0.56228753, 0.31424733], - [-0.1382643 , 0.49671415, 0.64768854], - [-0.46341769, 0.54256004, -0.46572975], - [-1.4123037 , -0.90802408, 1.46564877], - [ 0.0675282 , -0.2257763 , -1.42474819]]) - y = np.array([1., 1., 0., 0., 0., 0., 1., 1., 0., 0.]) + X = np.array( + [ + [0.76743473, 1.57921282, -0.46947439], + [-0.23415337, 1.52302986, -0.23413696], + [0.11092259, -0.54438272, -1.15099358], + [-0.60063869, 0.37569802, -0.29169375], + [-1.91328024, 0.24196227, -1.72491783], + [-1.01283112, -0.56228753, 0.31424733], + [-0.1382643, 0.49671415, 0.64768854], + [-0.46341769, 0.54256004, -0.46572975], + [-1.4123037, -0.90802408, 1.46564877], + [0.0675282, -0.2257763, -1.42474819], + ] + ) + y = np.array([1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0]) learning_rate = 1e-1 iterations = 10 b, llf = train_logreg(X, y, learning_rate, iterations) - assert b == [-0.2509, 0.9325, 1.6218, 0.6336] and \ - llf == [6.9315, 5.5073, 4.6382, 4.0609, 3.6503, 3.3432, 3.1045, 2.9134, 2.7567, 2.6258], \ - 'Test case 2 failed' + assert b == [-0.2509, 0.9325, 1.6218, 0.6336] and llf == [ + 6.9315, + 5.5073, + 4.6382, + 4.0609, + 3.6503, + 3.3432, + 3.1045, + 2.9134, + 2.7567, + 2.6258, + ], "Test case 2 failed" - print('All tests passed') + print("All tests passed") -if __name__ == '__main__': - test_train_logreg() \ No newline at end of file +if __name__ == "__main__": + test_train_logreg() diff --git a/old_repo/Problems/107_masked_attention/solution.py b/old_repo/Problems/107_masked_attention/solution.py index 0386d639..d5bbab50 100644 --- a/old_repo/Problems/107_masked_attention/solution.py +++ b/old_repo/Problems/107_masked_attention/solution.py @@ -1,14 +1,17 @@ import numpy as np from typing import Tuple -def compute_qkv(X: np.ndarray, W_q: np.ndarray, W_k: np.ndarray, W_v: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + +def compute_qkv( + X: np.ndarray, W_q: np.ndarray, W_k: np.ndarray, W_v: np.ndarray +) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: """ Compute the Query (Q), Key (K), and Value (V) matrices. - + Args: X: numpy array of shape (seq_len, d_model), input sequence W_q, W_k, W_v: numpy arrays of shape (d_model, d_model), weight matrices for Q, K, and V - + Returns: Q, K, V: numpy arrays of shape (seq_len, d_model) """ @@ -17,28 +20,39 @@ def compute_qkv(X: np.ndarray, W_q: np.ndarray, W_k: np.ndarray, W_v: np.ndarray V = np.dot(X, W_v) # Compute the Value matrix V return Q, K, V -def masked_attention(Q: np.ndarray, K: np.ndarray, V: np.ndarray, mask: np.ndarray) -> np.ndarray: + +def masked_attention( + Q: np.ndarray, K: np.ndarray, V: np.ndarray, mask: np.ndarray +) -> np.ndarray: """ Compute self-attention for a single head with a mask applied. - + Args: Q: numpy array of shape (seq_len, d_k), Query matrix K: numpy array of shape (seq_len, d_k), Key matrix V: numpy array of shape (seq_len, d_k), Value matrix mask: numpy array of shape (seq_len, seq_len), Mask matrix - + Returns: attention_output: numpy array of shape (seq_len, d_k), output of the masked-attention mechanism """ d_k = Q.shape[1] # Get the dimension of the keys - scores = np.matmul(Q, K.T) / np.sqrt(d_k) # Compute scaled dot-product attention scores - + scores = np.matmul(Q, K.T) / np.sqrt( + d_k + ) # Compute scaled dot-product attention scores + # Apply the mask by adding a large negative value to the masked positions - scores = scores + mask # This will set the masked positions to a large negative value (-inf) - + scores = ( + scores + mask + ) # This will set the masked positions to a large negative value (-inf) + # For numerical stability, compute softmax - attention_weights = np.exp(scores - np.max(scores, axis=1, keepdims=True)) # Subtract max for numerical stability - attention_weights = attention_weights / np.sum(attention_weights, axis=1, keepdims=True) # Normalize + attention_weights = np.exp( + scores - np.max(scores, axis=1, keepdims=True) + ) # Subtract max for numerical stability + attention_weights = attention_weights / np.sum( + attention_weights, axis=1, keepdims=True + ) # Normalize # Compute the final attention output attention_output = np.matmul(attention_weights, V) @@ -49,41 +63,54 @@ def test_masked_attention(): # Test case 1: Basic functionality with computed Q, K, V m, n = 6, 8 np.random.seed(42) - X = np.arange(m*n).reshape(m,n) + X = np.arange(m * n).reshape(m, n) X = np.random.permutation(X.flatten()).reshape(m, n) - mask = np.triu(np.ones((m, m))*(-np.inf), k=1) - W_q = np.random.randint(0,4,size=(n,n)) - W_k = np.random.randint(0,5,size=(n,n)) - W_v = np.random.randint(0,6,size=(n,n)) + mask = np.triu(np.ones((m, m)) * (-np.inf), k=1) + W_q = np.random.randint(0, 4, size=(n, n)) + W_k = np.random.randint(0, 5, size=(n, n)) + W_v = np.random.randint(0, 6, size=(n, n)) Q, K, V = compute_qkv(X, W_q, W_k, W_v) # test masked attention actual_output = masked_attention(Q, K, V, mask) - expected_output = np.array([[547., 490., 399., 495., 485., 439., 645., 393.], - [547., 490., 399., 495., 485., 439., 645., 393.], - [471., 472., 429., 538., 377., 450., 531., 362.], - [471., 472., 429., 538., 377., 450., 531., 362.], - [471., 472., 429., 538., 377., 450., 531., 362.], - [471., 472., 429., 538., 377., 450., 531., 362.]]) - np.testing.assert_array_almost_equal(actual_output, expected_output, decimal=6, err_msg="Test case 1 failed") + expected_output = np.array( + [ + [547.0, 490.0, 399.0, 495.0, 485.0, 439.0, 645.0, 393.0], + [547.0, 490.0, 399.0, 495.0, 485.0, 439.0, 645.0, 393.0], + [471.0, 472.0, 429.0, 538.0, 377.0, 450.0, 531.0, 362.0], + [471.0, 472.0, 429.0, 538.0, 377.0, 450.0, 531.0, 362.0], + [471.0, 472.0, 429.0, 538.0, 377.0, 450.0, 531.0, 362.0], + [471.0, 472.0, 429.0, 538.0, 377.0, 450.0, 531.0, 362.0], + ] + ) + np.testing.assert_array_almost_equal( + actual_output, expected_output, decimal=6, err_msg="Test case 1 failed" + ) # test different shape m, n = 4, 4 np.random.seed(42) - X = np.arange(m*n).reshape(m,n) + X = np.arange(m * n).reshape(m, n) X = np.random.permutation(X.flatten()).reshape(m, n) - mask = np.triu(np.ones((m, m))*(-np.inf), k=1) - W_q = np.random.randint(0,4,size=(n,n)) - W_k = np.random.randint(0,5,size=(n,n)) - W_v = np.random.randint(0,6,size=(n,n)) + mask = np.triu(np.ones((m, m)) * (-np.inf), k=1) + W_q = np.random.randint(0, 4, size=(n, n)) + W_k = np.random.randint(0, 5, size=(n, n)) + W_v = np.random.randint(0, 6, size=(n, n)) Q, K, V = compute_qkv(X, W_q, W_k, W_v) actual_output = masked_attention(Q, K, V, mask) - expected_output = np.array([[ 52., 63., 48., 71.], - [103., 109., 46., 99.], - [103., 109., 46., 99.], - [103., 109., 46., 99.]]) - np.testing.assert_array_almost_equal(actual_output, expected_output, decimal=6, err_msg="Test case 2 failed") + expected_output = np.array( + [ + [52.0, 63.0, 48.0, 71.0], + [103.0, 109.0, 46.0, 99.0], + [103.0, 109.0, 46.0, 99.0], + [103.0, 109.0, 46.0, 99.0], + ] + ) + np.testing.assert_array_almost_equal( + actual_output, expected_output, decimal=6, err_msg="Test case 2 failed" + ) + if __name__ == "__main__": test_masked_attention() - print("All masked-attention tests passed.") \ No newline at end of file + print("All masked-attention tests passed.") diff --git a/old_repo/Problems/10_Calculate_cov_matrix/solution.py b/old_repo/Problems/10_Calculate_cov_matrix/solution.py index 07e2d602..5edcf58c 100644 --- a/old_repo/Problems/10_Calculate_cov_matrix/solution.py +++ b/old_repo/Problems/10_Calculate_cov_matrix/solution.py @@ -7,11 +7,15 @@ def calculate_covariance_matrix(vectors: list[list[float]]) -> list[list[float]] for i in range(n_features): for j in range(i, n_features): - covariance = sum((vectors[i][k] - means[i]) * (vectors[j][k] - means[j]) for k in range(n_observations)) / (n_observations - 1) + covariance = sum( + (vectors[i][k] - means[i]) * (vectors[j][k] - means[j]) + for k in range(n_observations) + ) / (n_observations - 1) covariance_matrix[i][j] = covariance_matrix[j][i] = covariance return covariance_matrix + def test_calculate_covariance_matrix() -> None: # Test cases for calculate_covariance_matrix function @@ -21,7 +25,12 @@ def test_calculate_covariance_matrix() -> None: # Test case 2 vectors = [[1, 5, 6], [2, 3, 4], [7, 8, 9]] - assert calculate_covariance_matrix(vectors) == [[7.0, 2.5, 2.5], [2.5, 1.0, 1.0], [2.5, 1.0, 1.0]] + assert calculate_covariance_matrix(vectors) == [ + [7.0, 2.5, 2.5], + [2.5, 1.0, 1.0], + [2.5, 1.0, 1.0], + ] + if __name__ == "__main__": test_calculate_covariance_matrix() diff --git a/old_repo/Problems/110_METEOR/solution.py b/old_repo/Problems/110_METEOR/solution.py index 7ef06506..fe43bf3e 100644 --- a/old_repo/Problems/110_METEOR/solution.py +++ b/old_repo/Problems/110_METEOR/solution.py @@ -1,33 +1,37 @@ -import numpy as np from collections import Counter + def meteor_score(reference, candidate, alpha=0.9, beta=3, gamma=0.5): if not reference or not candidate: raise ValueError("Reference and candidate cannot be empty") - + # Tokenize and count ref_tokens = reference.lower().split() cand_tokens = candidate.lower().split() - # Counter for unigram for reference and candidate - ref_counts = Counter(ref_tokens) + # Counter for unigram for reference and candidate + ref_counts = Counter(ref_tokens) cand_counts = Counter(cand_tokens) - + # Calculate matches - num_matches = sum((ref_counts & cand_counts).values()) # Number of matching words in candidate and reference + num_matches = sum( + (ref_counts & cand_counts).values() + ) # Number of matching words in candidate and reference ref_len = len(ref_tokens) - cand_len = len(cand_tokens) + cand_len = len(cand_tokens) + + # Unigram Precision and Recall + precision = ( + num_matches / cand_len if cand_len > 0 else 0 + ) # Avoiding Division by zero + recall = num_matches / ref_len if ref_len > 0 else 0 # Avoiding Division by zero - # Unigram Precision and Recall - precision = num_matches / cand_len if cand_len > 0 else 0 # Avoiding Division by zero - recall = num_matches / ref_len if ref_len > 0 else 0 # Avoiding Division by zero - if num_matches == 0: return 0.0 - + fmean = (precision * recall) / (alpha * precision + (1 - alpha) * recall) - # Chunk calculation + # Chunk calculation matched_positions = [] ref_positions = {} # Store positions of words in reference used_positions = set() # Track already used indices @@ -53,9 +57,10 @@ def meteor_score(reference, candidate, alpha=0.9, beta=3, gamma=0.5): # Fragmentation penalty penalty = gamma * ((num_chunks / num_matches) ** beta) if num_matches > 0 else 0 - + # Final score - return round(fmean * (1 - penalty), 3) # Rounding to 3 Decimal places + return round(fmean * (1 - penalty), 3) # Rounding to 3 Decimal places + def test_meteor_score(): # Test Case 1: Identical translations @@ -63,38 +68,39 @@ def test_meteor_score(): cand_test1 = "The cat sits on the mat" expected1 = 1.0 assert meteor_score(ref_test1, cand_test1) == expected1, "Test Case 1 Failed" - + # Test Case 2: Similar translations ref_test2 = "The quick brown fox jumps over the lazy dog" cand_test2 = "A quick brown fox jumps over a lazy dog" expected2 = 0.991 assert meteor_score(ref_test2, cand_test2) == expected2, "Test Case 2 Failed" - + # Test Case 3: Completely different translations ref_test3 = "The cat sits on the mat" cand_test3 = "Dogs run in the park" expected3 = 0.0 assert meteor_score(ref_test3, cand_test3) == expected3, "Test Case 3 Failed" - + # Test Case 4: Partially matching translations ref_test4 = "Machine learning is an exciting field" cand_test4 = "Machine learning algorithms are fascinating" expected4 = 0.667 assert meteor_score(ref_test4, cand_test4) == expected4, "Test Case 4 Failed" - + # Test Case 5: Empty input handling try: meteor_score("", "Some text") assert False, "Test Case 5 Failed" except ValueError: pass - + # Test Case 6: Partial match with penalty ref_test6 = "The cat sits on the mat" cand_test6 = "The cat on the mat sits" expected6 = 0.933 assert meteor_score(ref_test6, cand_test6) == expected6, "Test Case 6 Failed" - + + if __name__ == "__main__": test_meteor_score() print("All Test Cases Passed!") diff --git a/old_repo/Problems/111_PMI/solution.py b/old_repo/Problems/111_PMI/solution.py index 1a99ad14..2f2e4d7f 100644 --- a/old_repo/Problems/111_PMI/solution.py +++ b/old_repo/Problems/111_PMI/solution.py @@ -1,75 +1,98 @@ import numpy as np + def compute_pmi(joint_counts, total_counts_x, total_counts_y, total_samples): - - if not all(isinstance(x, (int, float)) for x in [joint_counts, total_counts_x, total_counts_y, total_samples]): + if not all( + isinstance(x, (int, float)) + for x in [joint_counts, total_counts_x, total_counts_y, total_samples] + ): raise ValueError("All inputs must be numeric") - - if any(x < 0 for x in [joint_counts, total_counts_x, total_counts_y, total_samples]): + + if any( + x < 0 for x in [joint_counts, total_counts_x, total_counts_y, total_samples] + ): raise ValueError("Counts cannot be negative") - + if total_samples == 0: raise ValueError("Total samples cannot be zero") - + if joint_counts > min(total_counts_x, total_counts_y): raise ValueError("Joint counts cannot exceed individual counts") - + if any(x > total_samples for x in [total_counts_x, total_counts_y]): raise ValueError("Individual counts cannot exceed total samples") - + p_x = total_counts_x / total_samples p_y = total_counts_y / total_samples p_xy = joint_counts / total_samples - + # Handle edge cases where probabilities are zero if p_xy == 0 or p_x == 0 or p_y == 0: - return float('-inf') - + return float("-inf") + pmi = np.log2(p_xy / (p_x * p_y)) - + return round(pmi, 3) + def test_pmi(): # Test Case 1: Perfect positive association joint_counts1 = 100 total_counts_x1 = 100 total_counts_y1 = 100 total_samples1 = 100 - expected1 = round(np.log2(1/(1*1)), 3) # Should be 0.0 - assert compute_pmi(joint_counts1, total_counts_x1, total_counts_y1, total_samples1) == expected1, "Test Case 1 Failed" - + expected1 = round(np.log2(1 / (1 * 1)), 3) # Should be 0.0 + assert ( + compute_pmi(joint_counts1, total_counts_x1, total_counts_y1, total_samples1) + == expected1 + ), "Test Case 1 Failed" + # Test Case 2: Independence joint_counts2 = 25 total_counts_x2 = 50 total_counts_y2 = 50 total_samples2 = 100 - expected2 = round(np.log2((25/100)/((50/100)*(50/100))), 3) # Should be 0.0 - assert compute_pmi(joint_counts2, total_counts_x2, total_counts_y2, total_samples2) == expected2, "Test Case 2 Failed" - + expected2 = round( + np.log2((25 / 100) / ((50 / 100) * (50 / 100))), 3 + ) # Should be 0.0 + assert ( + compute_pmi(joint_counts2, total_counts_x2, total_counts_y2, total_samples2) + == expected2 + ), "Test Case 2 Failed" + # Test Case 3: Negative association joint_counts3 = 10 total_counts_x3 = 50 total_counts_y3 = 50 total_samples3 = 100 - expected3 = round(np.log2((10/100)/((50/100)*(50/100))), 3) # Should be negative - assert compute_pmi(joint_counts3, total_counts_x3, total_counts_y3, total_samples3) == expected3, "Test Case 3 Failed" - + expected3 = round( + np.log2((10 / 100) / ((50 / 100) * (50 / 100))), 3 + ) # Should be negative + assert ( + compute_pmi(joint_counts3, total_counts_x3, total_counts_y3, total_samples3) + == expected3 + ), "Test Case 3 Failed" + # Test Case 4: Zero joint occurrence joint_counts4 = 0 total_counts_x4 = 50 total_counts_y4 = 50 total_samples4 = 100 - expected4 = float('-inf') - assert compute_pmi(joint_counts4, total_counts_x4, total_counts_y4, total_samples4) == expected4, "Test Case 4 Failed" - + expected4 = float("-inf") + assert ( + compute_pmi(joint_counts4, total_counts_x4, total_counts_y4, total_samples4) + == expected4 + ), "Test Case 4 Failed" + # Test Case 5: Invalid inputs try: compute_pmi(-1, 50, 50, 100) assert False, "Test Case 5 Failed: Should raise ValueError for negative counts" except ValueError: pass - + print("All Test Cases Passed!") + if __name__ == "__main__": test_pmi() diff --git a/old_repo/Problems/112_Min_Max_Normalization/solution.py b/old_repo/Problems/112_Min_Max_Normalization/solution.py index f2a9617e..44838364 100644 --- a/old_repo/Problems/112_Min_Max_Normalization/solution.py +++ b/old_repo/Problems/112_Min_Max_Normalization/solution.py @@ -1,29 +1,30 @@ -def min_max(x:list[int])->list[float]: +def min_max(x: list[int]) -> list[float]: + # trying to modify the input list in-place instead creating a new list - #trying to modify the input list in-place instead creating a new list + largest = max(x) # finding the largest value in the input array + smallest = min(x) # finding the minimum value in the input array - largest=max(x) #finding the largest value in the input array - smallest=min(x) #finding the minimum value in the input array - - if largest==smallest: # if input has identical elements - return[0.0]*len(x) + if largest == smallest: # if input has identical elements + return [0.0] * len(x) for i in range(len(x)): - #using the formula to normalize the input - x[i]=round((x[i]-smallest)/(largest-smallest),4) + # using the formula to normalize the input + x[i] = round((x[i] - smallest) / (largest - smallest), 4) + + return x - return(x) def test_min_max(): - #first_test_case: + # first_test_case: - assert min_max([1,2,3,4,5])==[0.0, 0.25, 0.5, 0.75, 1.0],"Test Case 1 failed" + assert min_max([1, 2, 3, 4, 5]) == [0.0, 0.25, 0.5, 0.75, 1.0], "Test Case 1 failed" - assert min_max([30,45,56,70,88])==[0.0, 0.2586, 0.4483, 0.6897, 1.0],"Test Case 2 failed" + assert min_max([30, 45, 56, 70, 88]) == [0.0, 0.2586, 0.4483, 0.6897, 1.0], ( + "Test Case 2 failed" + ) - assert min_max([5,5,5,5])==[0.0,0.0,0.0,0.0], "Test Case 3 failed" + assert min_max([5, 5, 5, 5]) == [0.0, 0.0, 0.0, 0.0], "Test Case 3 failed" -if __name__=="__main__": +if __name__ == "__main__": test_min_max() print("All Min Max Normalization test cases passed.") - diff --git a/old_repo/Problems/116-polynomial-derivative/solution.py b/old_repo/Problems/116-polynomial-derivative/solution.py index dde1e97a..b3925fd3 100644 --- a/old_repo/Problems/116-polynomial-derivative/solution.py +++ b/old_repo/Problems/116-polynomial-derivative/solution.py @@ -1,29 +1,31 @@ -def polynomial_derivative(x: float,n: float) -> float: +def polynomial_derivative(x: float, n: float) -> float: if n == 0.0: return 0.0 - return round(n*(x**(n-1)),4) + return round(n * (x ** (n - 1)), 4) + def test_polynomial_derivative(): # Test case 1 - x,n = 10.0,0.0 + x, n = 10.0, 0.0 expected_output = 0.0 - assert polynomial_derivative(x,n) == expected_output, "Test case 1 failed" + assert polynomial_derivative(x, n) == expected_output, "Test case 1 failed" # Test case 2 - x,n = 6.0,5.0 + x, n = 6.0, 5.0 expected_output = 6480.0 - assert polynomial_derivative(x,n) == expected_output, "Test case 2 failed" + assert polynomial_derivative(x, n) == expected_output, "Test case 2 failed" # Test case 3 - x,n = 12.0,4.3 + x, n = 12.0, 4.3 expected_output = 15659.0917 - assert polynomial_derivative(x,n) == expected_output, "Test case 3 failed" + assert polynomial_derivative(x, n) == expected_output, "Test case 3 failed" # Test case 4 - x,n = 14.35,1.0 + x, n = 14.35, 1.0 expected_output = 1.0 - assert polynomial_derivative(x,n) == expected_output, "Test case 4 failed" + assert polynomial_derivative(x, n) == expected_output, "Test case 4 failed" + if __name__ == "__main__": test_polynomial_derivative() - print("All Polynomial Derivative tests passed.") \ No newline at end of file + print("All Polynomial Derivative tests passed.") diff --git a/old_repo/Problems/11_Linear_equations_jacobi/solution.py b/old_repo/Problems/11_Linear_equations_jacobi/solution.py index f3ae3163..70fa52b7 100644 --- a/old_repo/Problems/11_Linear_equations_jacobi/solution.py +++ b/old_repo/Problems/11_Linear_equations_jacobi/solution.py @@ -1,5 +1,6 @@ import numpy as np + def solve_jacobi(A: np.ndarray, b: np.ndarray, n: int) -> list: d_a = np.diag(A) nda = A - np.diag(d_a) @@ -7,10 +8,11 @@ def solve_jacobi(A: np.ndarray, b: np.ndarray, n: int) -> list: x_hold = np.zeros(len(b)) for _ in range(n): for i in range(len(A)): - x_hold[i] = (1/d_a[i]) * (b[i] - sum(nda[i]*x)) + x_hold[i] = (1 / d_a[i]) * (b[i] - sum(nda[i] * x)) x = x_hold.copy() return np.round(x, 4).tolist() + def test_solve_jacobi() -> None: # Test cases for solve_jacobi function @@ -29,6 +31,7 @@ def test_solve_jacobi() -> None: b = np.array([0, 7, 5]) assert solve_jacobi(A, b, 3) == [1.7083, -1.9583, -0.7812] + if __name__ == "__main__": test_solve_jacobi() print("All solve_jacobi tests passed.") diff --git a/old_repo/Problems/11_Linear_equations_jacobi/solution_2.py b/old_repo/Problems/11_Linear_equations_jacobi/solution_2.py index cf49d2ef..b383abab 100644 --- a/old_repo/Problems/11_Linear_equations_jacobi/solution_2.py +++ b/old_repo/Problems/11_Linear_equations_jacobi/solution_2.py @@ -6,11 +6,13 @@ def solve_jacobi(A: np.ndarray, b: np.ndarray, n: int) -> list: x = np.zeros_like(b) A_diag_vec = np.diag(A) for epoch in range(n): - x = 1/A_diag_vec*(b-(A@x-A_diag_vec*x)) + x = 1 / A_diag_vec * (b - (A @ x - A_diag_vec * x)) return x + import numpy as np + def test_solve_jacobi() -> None: def lists_are_close(list1, list2, tol=1e-4): """Helper function to check if two lists are element-wise close.""" @@ -21,26 +23,31 @@ def lists_are_close(list1, list2, tol=1e-4): b = np.array([-1, 2, 3]) result = solve_jacobi(A, b, 2) expected = [0.146, 0.2032, -0.5175] - assert lists_are_close(result, expected), f"Test case 1 failed: {result} != {expected}" + assert lists_are_close(result, expected), ( + f"Test case 1 failed: {result} != {expected}" + ) # Test case 2 A = np.array([[4, 1, 2], [1, 5, 1], [2, 1, 3]]) b = np.array([4, 6, 7]) result = solve_jacobi(A, b, 5) expected = [-0.0806, 0.9324, 2.4422] - assert lists_are_close(result, expected), f"Test case 2 failed: {result} != {expected}" + assert lists_are_close(result, expected), ( + f"Test case 2 failed: {result} != {expected}" + ) # Test case 3 A = np.array([[4, 2, -2], [1, -3, -1], [3, -1, 4]]) b = np.array([0, 7, 5]) result = solve_jacobi(A, b, 3) expected = [1.7083, -1.9583, -0.7812] - assert lists_are_close(result, expected), f"Test case 3 failed: {result} != {expected}" + assert lists_are_close(result, expected), ( + f"Test case 3 failed: {result} != {expected}" + ) print("All test cases passed!") - if __name__ == "__main__": test_solve_jacobi() - print("All solve_jacobi tests passed.") \ No newline at end of file + print("All solve_jacobi tests passed.") diff --git a/old_repo/Problems/129_Unigram/solution.py b/old_repo/Problems/129_Unigram/solution.py index 38a33a00..c35354bf 100644 --- a/old_repo/Problems/129_Unigram/solution.py +++ b/old_repo/Problems/129_Unigram/solution.py @@ -1,26 +1,26 @@ -s=''' I am Jack +s = """ I am Jack Jack I am Jack I like Jack I do like - do I like Jack ''' + do I like Jack """ -def unigram_calculation(s,word): - tokens=s.split() - total_word_count=len(tokens) - word_count=tokens.count(word) - unigram_p=word_count/total_word_count - return round(unigram_p,4) -def test(): +def unigram_calculation(s, word): + tokens = s.split() + total_word_count = len(tokens) + word_count = tokens.count(word) + unigram_p = word_count / total_word_count + return round(unigram_p, 4) + - #test case 1 for the word Jack - assert unigram_calculation(s,"Jack")==0.1852,"Test Case 1 Failed !" +def test(): + # test case 1 for the word Jack + assert unigram_calculation(s, "Jack") == 0.1852, "Test Case 1 Failed !" - #test case 2 for the word like - assert unigram_calculation(s,"like")==0.1111,"Test Case 2 Failed !" + # test case 2 for the word like + assert unigram_calculation(s, "like") == 0.1111, "Test Case 2 Failed !" if __name__ == "__main__": test() print("All Unigram tests passed.") - diff --git a/old_repo/Problems/12_svd_2x2_singular_values/solution.py b/old_repo/Problems/12_svd_2x2_singular_values/solution.py index 6d5bc68c..9e48e7e1 100644 --- a/old_repo/Problems/12_svd_2x2_singular_values/solution.py +++ b/old_repo/Problems/12_svd_2x2_singular_values/solution.py @@ -1,43 +1,38 @@ -import numpy as np +import numpy as np def svd_2x2_singular_values(A: np.ndarray) -> tuple: - # stick to lowercase - a = A - - a_t = np.transpose(a) - a_2 = a_t @ a - - v = np.eye(2) - - for _ in range(1): - # Compute rotation angle for a 2x2 matrix - if a_2[0,0] == a_2[1,1]: - theta = np.pi/4 - else: - theta = 0.5 * np.arctan2(2 * a_2[0,1], a_2[0,0] - a_2[1,1]) - - # Create rotation matrix - r = np.array( - [ - [np.cos(theta), -np.sin(theta)], - [np.sin(theta), np.cos(theta)] - ] - ) - - # apply rotation - d = np.transpose(r) @ a_2 @ r - - # update a_2 - a_2 = d - - # accumulate v - v = v @ r - - # sigma is the diagonal elements squared - s = np.sqrt([d[0,0], d[1,1]]) - s_inv = np.array([[1/s[0], 0], [0, 1/s[1]]]) - - u = a @ v @ s_inv - - return (u, s, v.T) + # stick to lowercase + a = A + + a_t = np.transpose(a) + a_2 = a_t @ a + + v = np.eye(2) + + for _ in range(1): + # Compute rotation angle for a 2x2 matrix + if a_2[0, 0] == a_2[1, 1]: + theta = np.pi / 4 + else: + theta = 0.5 * np.arctan2(2 * a_2[0, 1], a_2[0, 0] - a_2[1, 1]) + + # Create rotation matrix + r = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) + + # apply rotation + d = np.transpose(r) @ a_2 @ r + + # update a_2 + a_2 = d + + # accumulate v + v = v @ r + + # sigma is the diagonal elements squared + s = np.sqrt([d[0, 0], d[1, 1]]) + s_inv = np.array([[1 / s[0], 0], [0, 1 / s[1]]]) + + u = a @ v @ s_inv + + return (u, s, v.T) diff --git a/old_repo/Problems/138_gini_impurity/solution.py b/old_repo/Problems/138_gini_impurity/solution.py index c12223e9..87768e07 100644 --- a/old_repo/Problems/138_gini_impurity/solution.py +++ b/old_repo/Problems/138_gini_impurity/solution.py @@ -1,6 +1,7 @@ import numpy as np from typing import Tuple + def find_best_split(X: np.ndarray, y: np.ndarray) -> Tuple[int, float]: """ Find the best feature and threshold to split the dataset based on Gini impurity. @@ -14,12 +15,12 @@ def gini_impurity(y_subset: np.ndarray) -> float: if len(y_subset) == 0: return 0.0 p = np.mean(y_subset == 1) - return 1.0 - (p ** 2 + (1 - p) ** 2) + return 1.0 - (p**2 + (1 - p) ** 2) n_samples, n_features = X.shape best_feature = -1 - best_threshold = float('inf') - best_gini = float('inf') + best_threshold = float("inf") + best_gini = float("inf") for feature_index in range(n_features): thresholds = np.unique(X[:, feature_index]) @@ -39,6 +40,7 @@ def gini_impurity(y_subset: np.ndarray) -> float: return best_feature, best_threshold + def test(): # Test 1: Balanced binary split X1 = np.array([[2.5], [3.5], [1.0], [4.0]]) @@ -84,5 +86,6 @@ def test(): print("All test cases passed.") + if __name__ == "__main__": test() diff --git a/old_repo/Problems/13_determinant_4x4/solution.py b/old_repo/Problems/13_determinant_4x4/solution.py index 6eb09d9b..ad4d3b0a 100644 --- a/old_repo/Problems/13_determinant_4x4/solution.py +++ b/old_repo/Problems/13_determinant_4x4/solution.py @@ -1,15 +1,16 @@ -def determinant_4x4(matrix: list[list[int|float]]) -> float: +def determinant_4x4(matrix: list[list[int | float]]) -> float: # Base case: If the matrix is 1x1, return its single element if len(matrix) == 1: return matrix[0][0] # Recursive case: Calculate determinant using Laplace's Expansion det = 0 for c in range(len(matrix)): - minor = [row[:c] + row[c+1:] for row in matrix[1:]] # Remove column c - cofactor = ((-1)**c) * determinant_4x4(minor) # Compute cofactor + minor = [row[:c] + row[c + 1 :] for row in matrix[1:]] # Remove column c + cofactor = ((-1) ** c) * determinant_4x4(minor) # Compute cofactor det += matrix[0][c] * cofactor # Add to running total return det + def test_determinant_4x4() -> None: # Test case 1 matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] @@ -23,6 +24,7 @@ def test_determinant_4x4() -> None: matrix = [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]] assert determinant_4x4(matrix) == 0, "Test case 3 failed" + if __name__ == "__main__": test_determinant_4x4() print("All determinant_4x4 tests passed.") diff --git a/old_repo/Problems/14_linear_regression_normal_equation/solution.py b/old_repo/Problems/14_linear_regression_normal_equation/solution.py index 34faa48b..a25da4df 100644 --- a/old_repo/Problems/14_linear_regression_normal_equation/solution.py +++ b/old_repo/Problems/14_linear_regression_normal_equation/solution.py @@ -1,19 +1,23 @@ import numpy as np -def linear_regression_normal_equation(X: list[list[float]], y: list[float]) -> list[float]: + +def linear_regression_normal_equation( + X: list[list[float]], y: list[float] +) -> list[float]: # Convert the inputs to numpy arrays X = np.array(X) y = np.array(y).reshape(-1, 1) - + # Compute the normal equation X_transpose = X.T theta = np.linalg.inv(X_transpose.dot(X)).dot(X_transpose).dot(y) - + # Round the result to four decimal places theta = np.round(theta, 4).flatten().tolist() - + return theta + def test_linear_regression_normal_equation() -> None: # Test case 1 X = [[1, 1], [1, 2], [1, 3]] @@ -23,7 +27,10 @@ def test_linear_regression_normal_equation() -> None: # Test case 2 X = [[1, 3, 4], [1, 2, 5], [1, 3, 2]] y = [1, 2, 1] - assert linear_regression_normal_equation(X, y) == [4.0, -1.0, -0.0], "Test case 2 failed" + assert linear_regression_normal_equation(X, y) == [4.0, -1.0, -0.0], ( + "Test case 2 failed" + ) + if __name__ == "__main__": test_linear_regression_normal_equation() diff --git a/old_repo/Problems/15_linear_regression_gradient_descent/solution.py b/old_repo/Problems/15_linear_regression_gradient_descent/solution.py index fd77afaf..9dc3c526 100644 --- a/old_repo/Problems/15_linear_regression_gradient_descent/solution.py +++ b/old_repo/Problems/15_linear_regression_gradient_descent/solution.py @@ -1,36 +1,45 @@ import numpy as np -def linear_regression_gradient_descent(X: np.ndarray, y: np.ndarray, alpha: float, iterations: int) -> np.ndarray: + +def linear_regression_gradient_descent( + X: np.ndarray, y: np.ndarray, alpha: float, iterations: int +) -> np.ndarray: # Number of training examples and features m, n = X.shape - + # Initialize the coefficients (weights) to zeros theta = np.zeros((n, 1)) - + # Perform gradient descent for a given number of iterations for _ in range(iterations): # Compute the predictions predictions = X @ theta - + # Calculate the error (difference between predictions and actual values) errors = predictions - y.reshape(-1, 1) - + # Calculate the updates for the coefficients updates = X.T @ errors / m - + # Update the coefficients theta -= alpha * updates - + # Round the coefficients to four decimal places and return as a 1D array return np.round(theta.flatten(), 4) + def test_linear_regression_gradient_descent() -> None: # Test case 1 X = np.array([[1, 1], [1, 2], [1, 3]]) y = np.array([1, 2, 3]) alpha = 0.01 iterations = 1000 - assert np.allclose(linear_regression_gradient_descent(X, y, alpha, iterations), np.array([0.1107, 0.9513]), atol=1e-4), "Test case 1 failed" + assert np.allclose( + linear_regression_gradient_descent(X, y, alpha, iterations), + np.array([0.1107, 0.9513]), + atol=1e-4, + ), "Test case 1 failed" + if __name__ == "__main__": test_linear_regression_gradient_descent() diff --git a/old_repo/Problems/16_feature_scaling/solution.py b/old_repo/Problems/16_feature_scaling/solution.py index c0f5b5e6..5e2630cc 100644 --- a/old_repo/Problems/16_feature_scaling/solution.py +++ b/old_repo/Problems/16_feature_scaling/solution.py @@ -1,26 +1,33 @@ import numpy as np + def feature_scaling(data: np.ndarray) -> (np.ndarray, np.ndarray): # Standardization mean = np.mean(data, axis=0) std = np.std(data, axis=0) standardized_data = (data - mean) / std - + # Min-Max Normalization min_val = np.min(data, axis=0) max_val = np.max(data, axis=0) normalized_data = (data - min_val) / (max_val - min_val) - + # Rounding to four decimal places and converting to lists - return np.round(standardized_data, 4).tolist(), np.round(normalized_data, 4).tolist() + return np.round(standardized_data, 4).tolist(), np.round( + normalized_data, 4 + ).tolist() + def test_feature_scaling() -> None: # Test case 1 data = np.array([[1, 2], [3, 4], [5, 6]]) standardized, normalized = feature_scaling(data) - assert standardized == [[-1.2247, -1.2247], [0.0, 0.0], [1.2247, 1.2247]], "Test case 1 failed" + assert standardized == [[-1.2247, -1.2247], [0.0, 0.0], [1.2247, 1.2247]], ( + "Test case 1 failed" + ) assert normalized == [[0.0, 0.0], [0.5, 0.5], [1.0, 1.0]], "Test case 1 failed" + if __name__ == "__main__": test_feature_scaling() print("All feature_scaling tests passed.") diff --git a/old_repo/Problems/17_k_means_clustering/solution.py b/old_repo/Problems/17_k_means_clustering/solution.py index 49357bd4..4fa79163 100644 --- a/old_repo/Problems/17_k_means_clustering/solution.py +++ b/old_repo/Problems/17_k_means_clustering/solution.py @@ -1,70 +1,116 @@ import numpy as np + def euclidean_distance(a, b): return np.sqrt(((a - b) ** 2).sum(axis=1)) + def k_means_clustering(points, k, initial_centroids, max_iterations): points = np.array(points) centroids = np.array(initial_centroids) - + for iteration in range(max_iterations): # Assign points to the nearest centroid - distances = np.array([euclidean_distance(points, centroid) for centroid in centroids]) + distances = np.array( + [euclidean_distance(points, centroid) for centroid in centroids] + ) assignments = np.argmin(distances, axis=0) - new_centroids = np.array([points[assignments == i].mean(axis=0) if len(points[assignments == i]) > 0 else centroids[i] for i in range(k)]) - + new_centroids = np.array( + [ + points[assignments == i].mean(axis=0) + if len(points[assignments == i]) > 0 + else centroids[i] + for i in range(k) + ] + ) + # Check for convergence if np.all(centroids == new_centroids): break centroids = new_centroids centroids = np.round(centroids, 4) - + return [tuple(centroid) for centroid in centroids] + def test_k_means_clustering() -> None: # Test case 1 points = [(1, 2), (1, 4), (1, 0), (10, 2), (10, 4), (10, 0)] k = 2 initial_centroids = [(1, 1), (10, 1)] max_iterations = 10 - assert k_means_clustering(points, k, initial_centroids, max_iterations) == [(1.0, 2.0), (10.0, 2.0)], "Test case 1 failed" + assert k_means_clustering(points, k, initial_centroids, max_iterations) == [ + (1.0, 2.0), + (10.0, 2.0), + ], "Test case 1 failed" # Test case 2 points = [(0, 0, 0), (2, 2, 2), (1, 1, 1), (9, 10, 9), (10, 11, 10), (12, 11, 12)] k = 2 initial_centroids = [(1, 1, 1), (10, 10, 10)] max_iterations = 10 - assert k_means_clustering(points, k, initial_centroids, max_iterations) == [(1.0, 1.0, 1.0), (10.3333, 10.6667, 10.3333)], "Test case 2 failed" + assert k_means_clustering(points, k, initial_centroids, max_iterations) == [ + (1.0, 1.0, 1.0), + (10.3333, 10.6667, 10.3333), + ], "Test case 2 failed" # Test case 3: Single cluster points = [(1, 1), (2, 2), (3, 3), (4, 4)] k = 1 initial_centroids = [(0, 0)] max_iterations = 10 - assert k_means_clustering(points, k, initial_centroids, max_iterations) == [(2.5, 2.5)], "Test case 3 failed" + assert k_means_clustering(points, k, initial_centroids, max_iterations) == [ + (2.5, 2.5) + ], "Test case 3 failed" # Test case 4: Four clusters in 2D space - points = [(0, 0), (1, 0), (0, 1), (1, 1), (5, 5), (6, 5), (5, 6), (6, 6), - (0, 5), (1, 5), (0, 6), (1, 6), (5, 0), (6, 0), (5, 1), (6, 1)] + points = [ + (0, 0), + (1, 0), + (0, 1), + (1, 1), + (5, 5), + (6, 5), + (5, 6), + (6, 6), + (0, 5), + (1, 5), + (0, 6), + (1, 6), + (5, 0), + (6, 0), + (5, 1), + (6, 1), + ] k = 4 initial_centroids = [(0, 0), (0, 5), (5, 0), (5, 5)] max_iterations = 10 result = k_means_clustering(points, k, initial_centroids, max_iterations) expected = [(0.5, 0.5), (0.5, 5.5), (5.5, 0.5), (5.5, 5.5)] - assert all(np.allclose(r, e) for r, e in zip(result, expected)), "Test case 4 failed" + assert all(np.allclose(r, e) for r, e in zip(result, expected)), ( + "Test case 4 failed" + ) # Test case 5: Clusters with different densities - points = [(0, 0), (0.5, 0), (0, 0.5), (0.5, 0.5), # Dense cluster - (4, 4), (6, 6)] # Sparse cluster + points = [ + (0, 0), + (0.5, 0), + (0, 0.5), + (0.5, 0.5), # Dense cluster + (4, 4), + (6, 6), + ] # Sparse cluster k = 2 initial_centroids = [(0, 0), (5, 5)] max_iterations = 10 result = k_means_clustering(points, k, initial_centroids, max_iterations) expected = [(0.25, 0.25), (5.0, 5.0)] - assert all(np.allclose(r, e) for r, e in zip(result, expected)), "Test case 5 failed" + assert all(np.allclose(r, e) for r, e in zip(result, expected)), ( + "Test case 5 failed" + ) + if __name__ == "__main__": test_k_means_clustering() print("All k_means_clustering tests passed.") - \ No newline at end of file diff --git a/old_repo/Problems/18_cross_validation_split/solution.py b/old_repo/Problems/18_cross_validation_split/solution.py index 637ce8c5..3ca5e8cb 100644 --- a/old_repo/Problems/18_cross_validation_split/solution.py +++ b/old_repo/Problems/18_cross_validation_split/solution.py @@ -1,7 +1,9 @@ - import numpy as np -def k_fold_cross_validation(X: np.ndarray, y: np.ndarray, k=5, shuffle=True, random_seed=None): + +def k_fold_cross_validation( + X: np.ndarray, y: np.ndarray, k=5, shuffle=True, random_seed=None +): """ Generate train and test indices for k-fold cross-validation. @@ -23,43 +25,74 @@ def k_fold_cross_validation(X: np.ndarray, y: np.ndarray, k=5, shuffle=True, ran np.random.shuffle(indices) fold_sizes = np.full(k, n_samples // k, dtype=int) - fold_sizes[:n_samples % k] += 1 # Distribute remainder among the first folds + fold_sizes[: n_samples % k] += 1 # Distribute remainder among the first folds folds = [] current = 0 for fold_size in fold_sizes: - folds.append(indices[current:current + fold_size]) + folds.append(indices[current : current + fold_size]) current += fold_size - return [(np.concatenate(folds[:i] + folds[i+1:]).tolist(), folds[i].tolist()) for i in range(k)] + return [ + (np.concatenate(folds[:i] + folds[i + 1 :]).tolist(), folds[i].tolist()) + for i in range(k) + ] + def test_k_fold_cross_validation(): # Test case 1: k=5, shuffle=False - result = k_fold_cross_validation(np.array([0,1,2,3,4,5,6,7,8,9]), np.array([0,1,2,3,4,5,6,7,8,9]), k=5, shuffle=False) - expected = [([2, 3, 4, 5, 6, 7, 8, 9], [0, 1]), ([0, 1, 4, 5, 6, 7, 8, 9], [2, 3]), - ([0, 1, 2, 3, 6, 7, 8, 9], [4, 5]), ([0, 1, 2, 3, 4, 5, 8, 9], [6, 7]), - ([0, 1, 2, 3, 4, 5, 6, 7], [8, 9])] + result = k_fold_cross_validation( + np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + k=5, + shuffle=False, + ) + expected = [ + ([2, 3, 4, 5, 6, 7, 8, 9], [0, 1]), + ([0, 1, 4, 5, 6, 7, 8, 9], [2, 3]), + ([0, 1, 2, 3, 6, 7, 8, 9], [4, 5]), + ([0, 1, 2, 3, 4, 5, 8, 9], [6, 7]), + ([0, 1, 2, 3, 4, 5, 6, 7], [8, 9]), + ] assert result == expected, "Test case 1 failed" - + # Test case 2: k=2, shuffle=True, fixed seed - result = k_fold_cross_validation(np.array([0,1,2,3,4,5,6,7,8,9]), np.array([0,1,2,3,4,5,6,7,8,9]), k=2, shuffle=True, random_seed=42) + result = k_fold_cross_validation( + np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + k=2, + shuffle=True, + random_seed=42, + ) expected = [([2, 9, 4, 3, 6], [8, 1, 5, 0, 7]), ([8, 1, 5, 0, 7], [2, 9, 4, 3, 6])] assert result == expected, "Test case 2 failed" - + # Test case 3: k=3, shuffle=False - result = k_fold_cross_validation(np.array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]), - np.array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]), k=3, shuffle=False) - expected = [([5, 6, 7, 8, 9, 10, 11, 12, 13, 14], [0, 1, 2, 3, 4]), - ([0, 1, 2, 3, 4, 10, 11, 12, 13, 14], [5, 6, 7, 8, 9]), - ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 14])] + result = k_fold_cross_validation( + np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]), + np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]), + k=3, + shuffle=False, + ) + expected = [ + ([5, 6, 7, 8, 9, 10, 11, 12, 13, 14], [0, 1, 2, 3, 4]), + ([0, 1, 2, 3, 4, 10, 11, 12, 13, 14], [5, 6, 7, 8, 9]), + ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]), + ] assert result == expected, "Test case 3 failed" - + # Test case 4: k=2, shuffle=False - result = k_fold_cross_validation(np.array([0,1,2,3,4,5,6,7,8,9]), np.array([0,1,2,3,4,5,6,7,8,9]), k=2, shuffle=False) + result = k_fold_cross_validation( + np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + k=2, + shuffle=False, + ) expected = [([5, 6, 7, 8, 9], [0, 1, 2, 3, 4]), ([0, 1, 2, 3, 4], [5, 6, 7, 8, 9])] assert result == expected, "Test case 4 failed" - + print("All k-fold cross-validation tests passed.") + if __name__ == "__main__": test_k_fold_cross_validation() diff --git a/old_repo/Problems/19_PCA/solution.py b/old_repo/Problems/19_PCA/solution.py index 935f2d93..62d2f085 100644 --- a/old_repo/Problems/19_PCA/solution.py +++ b/old_repo/Problems/19_PCA/solution.py @@ -1,25 +1,27 @@ import numpy as np + def pca(data, k): # Standardize the data data_standardized = (data - np.mean(data, axis=0)) / np.std(data, axis=0) - + # Compute the covariance matrix covariance_matrix = np.cov(data_standardized, rowvar=False) - + # Eigen decomposition eigenvalues, eigenvectors = np.linalg.eig(covariance_matrix) - + # Sort the eigenvectors by decreasing eigenvalues idx = np.argsort(eigenvalues)[::-1] - eigenvalues_sorted = eigenvalues[idx] + eigenvalues[idx] eigenvectors_sorted = eigenvectors[:, idx] - + # Select the top k eigenvectors (principal components) principal_components = eigenvectors_sorted[:, :k] - + return np.round(principal_components, 4).tolist() + def test_pca(): # Test case 1 data = np.array([[4, 2, 1], [5, 6, 7], [9, 12, 1], [4, 6, 7]]) @@ -33,6 +35,7 @@ def test_pca(): expected_output = [[0.7071], [0.7071]] assert pca(data, k) == expected_output, "Test case 2 failed" + if __name__ == "__main__": test_pca() print("All pca tests passed.") diff --git a/old_repo/Problems/1_matrix_times_vector/Easy_and_simple_solution.py b/old_repo/Problems/1_matrix_times_vector/Easy_and_simple_solution.py index 88501ca8..d9189f24 100644 --- a/old_repo/Problems/1_matrix_times_vector/Easy_and_simple_solution.py +++ b/old_repo/Problems/1_matrix_times_vector/Easy_and_simple_solution.py @@ -1,13 +1,15 @@ -def matrix_dot_vector(a: list[list[int|float]], b: list[int|float]) -> list[int|float]: - # if the no. of columns of a is not equal to the len of vector b then return -1 - if len(a[0]) != len(b): - return -1 - # create a vector to store the values - result = [] - # traverse through the matrix and add do the dot product and append to the result vector - for i in range(len(a)): - val = 0 - for j in range(len(b)): - val += a[i][j] * b[j] - result.append(val) - return result +def matrix_dot_vector( + a: list[list[int | float]], b: list[int | float] +) -> list[int | float]: + # if the no. of columns of a is not equal to the len of vector b then return -1 + if len(a[0]) != len(b): + return -1 + # create a vector to store the values + result = [] + # traverse through the matrix and add do the dot product and append to the result vector + for i in range(len(a)): + val = 0 + for j in range(len(b)): + val += a[i][j] * b[j] + result.append(val) + return result diff --git a/old_repo/Problems/1_matrix_times_vector/solution.py b/old_repo/Problems/1_matrix_times_vector/solution.py index 4a03ea8c..1d8147ff 100644 --- a/old_repo/Problems/1_matrix_times_vector/solution.py +++ b/old_repo/Problems/1_matrix_times_vector/solution.py @@ -28,12 +28,13 @@ def test_matrix_dot_vector() -> None: a: list[list[int | float]] = [[1, 2], [2, 4]] b: list[int | float] = [1, 2] assert matrix_dot_vector(a, b) == [5, 10] - - # valid product with rectangular matrix (non-square) -- > if we changed "for j in range(len(a[i]))" to "for j in range(len(a))" previous tests will pass + + # valid product with rectangular matrix (non-square) -- > if we changed "for j in range(len(a[i]))" to "for j in range(len(a))" previous tests will pass a: list[list[int | float]] = [[1, 2, 3], [2, 4, 6]] b: list[int | float] = [1, 2, 3] assert matrix_dot_vector(a, b) == [14, 28] + if __name__ == "__main__": test_matrix_dot_vector() print("All tests passed.") diff --git a/old_repo/Problems/1_matrix_times_vector/solution3.py b/old_repo/Problems/1_matrix_times_vector/solution3.py index 9e293e69..8e3dcb14 100644 --- a/old_repo/Problems/1_matrix_times_vector/solution3.py +++ b/old_repo/Problems/1_matrix_times_vector/solution3.py @@ -1,10 +1,14 @@ from numpy import dot as dot_product -def matrix_dot_vector(a: list[list[int|float]], b: list[int|float]) -> list[int|float]: + +def matrix_dot_vector( + a: list[list[int | float]], b: list[int | float] +) -> list[int | float]: if len(a) != len(b): return -1 - return dot_product(a,b) + return dot_product(a, b) + def test_matrix_dot_vector() -> None: # empty product @@ -19,12 +23,13 @@ def test_matrix_dot_vector() -> None: a: list[list[int | float]] = [[1, 2], [2, 4]] b: list[int | float] = [1, 2] assert matrix_dot_vector(a, b) == [5, 10] - - # valid product with rectangular matrix (non-square) -- > if we changed "for j in range(len(a[i]))" to "for j in range(len(a))" previous tests will pass + + # valid product with rectangular matrix (non-square) -- > if we changed "for j in range(len(a[i]))" to "for j in range(len(a))" previous tests will pass a: list[list[int | float]] = [[1, 2, 3], [2, 4, 6]] b: list[int | float] = [1, 2, 3] assert matrix_dot_vector(a, b) == [14, 28] + if __name__ == "__main__": test_matrix_dot_vector() print("All tests passed.") diff --git a/old_repo/Problems/1_matrix_times_vector/solution_2.py b/old_repo/Problems/1_matrix_times_vector/solution_2.py index 0c44153f..dc2d765c 100644 --- a/old_repo/Problems/1_matrix_times_vector/solution_2.py +++ b/old_repo/Problems/1_matrix_times_vector/solution_2.py @@ -4,14 +4,14 @@ def matrix_dot_vector( ) -> list[int | float] | int: #Check that dimensions match if len(a[0]) != len(b): - return -1 - - c = [] + return -1 + + c = [] #Iterate using a list comprehension - for s_a in a: - temp = sum([s_a[i]*b[i] for i in range(len(b))]) - c.append(temp) - return c + for s_a in a: + temp = sum([s_a[i]*b[i] for i in range(len(b))]) + c.append(temp) + return c def test_matrix_dot_vector() -> None: # empty product diff --git a/old_repo/Problems/20_decision_tree_learning/solution.py b/old_repo/Problems/20_decision_tree_learning/solution.py index f2e39156..766d1dad 100644 --- a/old_repo/Problems/20_decision_tree_learning/solution.py +++ b/old_repo/Problems/20_decision_tree_learning/solution.py @@ -1,67 +1,83 @@ import math from collections import Counter + def calculate_entropy(labels): label_counts = Counter(labels) total_count = len(labels) - entropy = -sum((count / total_count) * math.log2(count / total_count) for count in label_counts.values()) + entropy = -sum( + (count / total_count) * math.log2(count / total_count) + for count in label_counts.values() + ) return entropy + def calculate_information_gain(examples, attr, target_attr): total_entropy = calculate_entropy([example[target_attr] for example in examples]) values = set(example[attr] for example in examples) attr_entropy = 0 for value in values: - value_subset = [example[target_attr] for example in examples if example[attr] == value] + value_subset = [ + example[target_attr] for example in examples if example[attr] == value + ] value_entropy = calculate_entropy(value_subset) attr_entropy += (len(value_subset) / len(examples)) * value_entropy return total_entropy - attr_entropy + def majority_class(examples, target_attr): return Counter([example[target_attr] for example in examples]).most_common(1)[0][0] + def learn_decision_tree(examples, attributes, target_attr): if not examples: - return 'No examples' + return "No examples" if all(example[target_attr] == examples[0][target_attr] for example in examples): return examples[0][target_attr] if not attributes: return majority_class(examples, target_attr) - - gains = {attr: calculate_information_gain(examples, attr, target_attr) for attr in attributes} + + gains = { + attr: calculate_information_gain(examples, attr, target_attr) + for attr in attributes + } best_attr = max(gains, key=gains.get) tree = {best_attr: {}} - + for value in set(example[best_attr] for example in examples): subset = [example for example in examples if example[best_attr] == value] new_attributes = attributes.copy() new_attributes.remove(best_attr) subtree = learn_decision_tree(subset, new_attributes, target_attr) tree[best_attr][value] = subtree - + return tree + def test_learn_decision_tree(): # Test case examples = [ - {'Outlook': 'Sunny', 'Wind': 'Weak', 'PlayTennis': 'No'}, - {'Outlook': 'Overcast', 'Wind': 'Strong', 'PlayTennis': 'Yes'}, - {'Outlook': 'Rain', 'Wind': 'Weak', 'PlayTennis': 'Yes'}, - {'Outlook': 'Sunny', 'Wind': 'Strong', 'PlayTennis': 'No'}, - {'Outlook': 'Sunny', 'Wind': 'Weak', 'PlayTennis': 'Yes'}, - {'Outlook': 'Overcast', 'Wind': 'Weak', 'PlayTennis': 'Yes'}, - {'Outlook': 'Rain', 'Wind': 'Strong', 'PlayTennis': 'No'}, - {'Outlook': 'Rain', 'Wind': 'Weak', 'PlayTennis': 'Yes'} + {"Outlook": "Sunny", "Wind": "Weak", "PlayTennis": "No"}, + {"Outlook": "Overcast", "Wind": "Strong", "PlayTennis": "Yes"}, + {"Outlook": "Rain", "Wind": "Weak", "PlayTennis": "Yes"}, + {"Outlook": "Sunny", "Wind": "Strong", "PlayTennis": "No"}, + {"Outlook": "Sunny", "Wind": "Weak", "PlayTennis": "Yes"}, + {"Outlook": "Overcast", "Wind": "Weak", "PlayTennis": "Yes"}, + {"Outlook": "Rain", "Wind": "Strong", "PlayTennis": "No"}, + {"Outlook": "Rain", "Wind": "Weak", "PlayTennis": "Yes"}, ] - attributes = ['Outlook', 'Wind'] + attributes = ["Outlook", "Wind"] expected_output = { - 'Outlook': { - 'Sunny': {'Wind': {'Weak': 'No', 'Strong': 'No'}}, - 'Rain': {'Wind': {'Weak': 'Yes', 'Strong': 'No'}}, - 'Overcast': 'Yes' + "Outlook": { + "Sunny": {"Wind": {"Weak": "No", "Strong": "No"}}, + "Rain": {"Wind": {"Weak": "Yes", "Strong": "No"}}, + "Overcast": "Yes", } } - assert learn_decision_tree(examples, attributes, 'PlayTennis') == expected_output, "Test case failed" + assert learn_decision_tree(examples, attributes, "PlayTennis") == expected_output, ( + "Test case failed" + ) + if __name__ == "__main__": test_learn_decision_tree() diff --git a/old_repo/Problems/21_pegasos_kernel_svm/solution.py b/old_repo/Problems/21_pegasos_kernel_svm/solution.py index 2fd0e4f4..2eade777 100644 --- a/old_repo/Problems/21_pegasos_kernel_svm/solution.py +++ b/old_repo/Problems/21_pegasos_kernel_svm/solution.py @@ -1,12 +1,17 @@ import numpy as np + def linear_kernel(x, y): return np.dot(x, y) + def rbf_kernel(x, y, sigma=1.0): - return np.exp(-np.linalg.norm(x-y)**2 / (2 * (sigma ** 2))) + return np.exp(-(np.linalg.norm(x - y) ** 2) / (2 * (sigma**2))) + -def pegasos_kernel_svm(data, labels, kernel='linear', lambda_val=0.01, iterations=100, sigma=1.0): +def pegasos_kernel_svm( + data, labels, kernel="linear", lambda_val=0.01, iterations=100, sigma=1.0 +): n_samples = len(data) alphas = np.zeros(n_samples) b = 0 @@ -14,12 +19,19 @@ def pegasos_kernel_svm(data, labels, kernel='linear', lambda_val=0.01, iteration for t in range(1, iterations + 1): for i in range(n_samples): eta = 1.0 / (lambda_val * t) - if kernel == 'linear': + if kernel == "linear": kernel_func = linear_kernel - elif kernel == 'rbf': - kernel_func = lambda x, y: rbf_kernel(x, y, sigma) - - decision = sum(alphas[j] * labels[j] * kernel_func(data[j], data[i]) for j in range(n_samples)) + b + elif kernel == "rbf": + def kernel_func(x, y): + return rbf_kernel(x, y, sigma) + + decision = ( + sum( + alphas[j] * labels[j] * kernel_func(data[j], data[i]) + for j in range(n_samples) + ) + + b + ) if labels[i] * decision < 1: alphas[i] += eta * (labels[i] - lambda_val * alphas[i]) b += eta * labels[i] @@ -32,11 +44,22 @@ def test_pegasos_kernel_svm(): data = np.array([[1, 2], [2, 3], [3, 1], [4, 1]]) labels = np.array([1, 1, -1, -1]) expected_output = ([100.0, 0.0, -100.0, -100.0], -937.4755) - assert pegasos_kernel_svm(data, labels, kernel='linear', lambda_val=0.01, iterations=100) == expected_output, "Test case 1 failed" - + assert ( + pegasos_kernel_svm( + data, labels, kernel="linear", lambda_val=0.01, iterations=100 + ) + == expected_output + ), "Test case 1 failed" + # Test case 2: RBF kernel expected_output = ([100.0, 99.0, -100.0, -100.0], -115.0) - assert pegasos_kernel_svm(data, labels, kernel='rbf', lambda_val=0.01, iterations=100, sigma=0.5) == expected_output, "Test case 2 failed" + assert ( + pegasos_kernel_svm( + data, labels, kernel="rbf", lambda_val=0.01, iterations=100, sigma=0.5 + ) + == expected_output + ), "Test case 2 failed" + if __name__ == "__main__": test_pegasos_kernel_svm() diff --git a/old_repo/Problems/22_sigmoid/solution.py b/old_repo/Problems/22_sigmoid/solution.py index 31ad7e0f..269ca97b 100644 --- a/old_repo/Problems/22_sigmoid/solution.py +++ b/old_repo/Problems/22_sigmoid/solution.py @@ -1,19 +1,22 @@ import math + def sigmoid(z: float) -> float: result = 1 / (1 + math.exp(-z)) return round(result, 4) + def test_sigmoid(): # Test case 1: z = 0 assert sigmoid(0) == 0.5, "Test case 1 failed" - + # Test case 2: z = 1 assert sigmoid(1) == 0.7311, "Test case 2 failed" - + # Test case 3: z = -1 assert sigmoid(-1) == 0.2689, "Test case 3 failed" + if __name__ == "__main__": test_sigmoid() print("All sigmoid tests passed.") diff --git a/old_repo/Problems/23_softmax/solution.py b/old_repo/Problems/23_softmax/solution.py index 3b57b532..4b431a08 100644 --- a/old_repo/Problems/23_softmax/solution.py +++ b/old_repo/Problems/23_softmax/solution.py @@ -1,11 +1,13 @@ import numpy as np + def softmax(scores): exp_scores = np.exp(scores) sum_exp_scores = np.sum(exp_scores) probabilities = np.round(exp_scores / sum_exp_scores, 4) return probabilities.tolist() + def test_softmax(): # Test case 1 scores = [1, 2, 3] @@ -22,6 +24,7 @@ def test_softmax(): expected_output = [0.0025, 0.0067, 0.9909] assert softmax(scores) == expected_output, "Test case 3 failed" + if __name__ == "__main__": test_softmax() print("All softmax tests passed.") diff --git a/old_repo/Problems/24_single_neuron/solution.py b/old_repo/Problems/24_single_neuron/solution.py index 3f8ebee7..f075911b 100644 --- a/old_repo/Problems/24_single_neuron/solution.py +++ b/old_repo/Problems/24_single_neuron/solution.py @@ -1,17 +1,24 @@ import math + def single_neuron_model(features, labels, weights, bias): probabilities = [] for feature_vector in features: - z = sum(weight * feature for weight, feature in zip(weights, feature_vector)) + bias + z = ( + sum(weight * feature for weight, feature in zip(weights, feature_vector)) + + bias + ) prob = 1 / (1 + math.exp(-z)) probabilities.append(round(prob, 4)) - - mse = sum((prob - label) ** 2 for prob, label in zip(probabilities, labels)) / len(labels) + + mse = sum((prob - label) ** 2 for prob, label in zip(probabilities, labels)) / len( + labels + ) mse = round(mse, 4) - + return probabilities, mse + def test_single_neuron_model(): # Test case 1 features = [[0.5, 1.0], [-1.5, -2.0], [2.0, 1.5]] @@ -19,15 +26,20 @@ def test_single_neuron_model(): weights = [0.7, -0.4] bias = -0.1 expected_output = ([0.4626, 0.4134, 0.6682], 0.3349) - assert single_neuron_model(features, labels, weights, bias) == expected_output, "Test case 1 failed" - + assert single_neuron_model(features, labels, weights, bias) == expected_output, ( + "Test case 1 failed" + ) + # Test case 2 features = [[1, 2], [2, 3], [3, 1]] labels = [1, 0, 1] weights = [0.5, -0.2] bias = 0 expected_output = ([0.525, 0.5987, 0.7858], 0.21) - assert single_neuron_model(features, labels, weights, bias) == expected_output, "Test case 2 failed" + assert single_neuron_model(features, labels, weights, bias) == expected_output, ( + "Test case 2 failed" + ) + if __name__ == "__main__": test_single_neuron_model() diff --git a/old_repo/Problems/25_Single_Neuron_with_Backpropagation/solution.py b/old_repo/Problems/25_Single_Neuron_with_Backpropagation/solution.py index 1f9e2cf6..41cdba10 100644 --- a/old_repo/Problems/25_Single_Neuron_with_Backpropagation/solution.py +++ b/old_repo/Problems/25_Single_Neuron_with_Backpropagation/solution.py @@ -1,9 +1,13 @@ import numpy as np + def sigmoid(x): return 1 / (1 + np.exp(-x)) -def train_neuron(features, labels, initial_weights, initial_bias, learning_rate, epochs): + +def train_neuron( + features, labels, initial_weights, initial_bias, learning_rate, epochs +): weights = np.array(initial_weights) bias = initial_bias features = np.array(features) @@ -13,15 +17,19 @@ def train_neuron(features, labels, initial_weights, initial_bias, learning_rate, for _ in range(epochs): z = np.dot(features, weights) + bias predictions = sigmoid(z) - + mse = np.mean((predictions - labels) ** 2) mse_values.append(round(mse, 4)) # Gradient calculation for weights and bias errors = predictions - labels - weight_gradients = (2/len(labels)) * np.dot(features.T, errors * predictions * (1 - predictions)) - bias_gradient = (2/len(labels)) * np.mean(errors * predictions * (1 - predictions)) - + weight_gradients = (2 / len(labels)) * np.dot( + features.T, errors * predictions * (1 - predictions) + ) + bias_gradient = (2 / len(labels)) * np.mean( + errors * predictions * (1 - predictions) + ) + # Update weights and bias weights -= learning_rate * weight_gradients bias -= learning_rate * bias_gradient @@ -32,6 +40,7 @@ def train_neuron(features, labels, initial_weights, initial_bias, learning_rate, return updated_weights.tolist(), updated_bias, mse_values + def test_train_neuron(): # Test case 1 features = np.array([[1.0, 2.0], [2.0, 1.0], [-1.0, -2.0]]) @@ -41,8 +50,13 @@ def test_train_neuron(): learning_rate = 0.1 epochs = 2 expected_output = ([0.1035, -0.1426], -0.0056, [0.3033, 0.2947]) - assert train_neuron(features, labels, initial_weights, initial_bias, learning_rate, epochs) == expected_output, "Test case 1 failed" - + assert ( + train_neuron( + features, labels, initial_weights, initial_bias, learning_rate, epochs + ) + == expected_output + ), "Test case 1 failed" + # Test case 2 features = np.array([[1, 2], [2, 3], [3, 1]]) labels = np.array([1, 0, 1]) @@ -51,7 +65,13 @@ def test_train_neuron(): learning_rate = 0.1 epochs = 3 expected_output = ([0.4893, -0.2301], 0.001, [0.21, 0.2087, 0.2076]) - assert train_neuron(features, labels, initial_weights, initial_bias, learning_rate, epochs) == expected_output, "Test case 2 failed" + assert ( + train_neuron( + features, labels, initial_weights, initial_bias, learning_rate, epochs + ) + == expected_output + ), "Test case 2 failed" + if __name__ == "__main__": test_train_neuron() diff --git a/old_repo/Problems/26_Autograd/solution.py b/old_repo/Problems/26_Autograd/solution.py index 68820fda..f7cc198f 100644 --- a/old_repo/Problems/26_Autograd/solution.py +++ b/old_repo/Problems/26_Autograd/solution.py @@ -1,5 +1,5 @@ class Value: - def __init__(self, data, _children=(), _op=''): + def __init__(self, data, _children=(), _op=""): self.data = data self.grad = 0 self._backward = lambda: None @@ -8,29 +8,32 @@ def __init__(self, data, _children=(), _op=''): def __add__(self, other): other = other if isinstance(other, Value) else Value(other) - out = Value(self.data + other.data, (self, other), '+') + out = Value(self.data + other.data, (self, other), "+") def _backward(): self.grad += out.grad other.grad += out.grad + out._backward = _backward return out def __mul__(self, other): other = other if isinstance(other, Value) else Value(other) - out = Value(self.data * other.data, (self, other), '*') + out = Value(self.data * other.data, (self, other), "*") def _backward(): self.grad += other.data * out.grad other.grad += self.data * out.grad + out._backward = _backward return out def relu(self): - out = Value(0 if self.data < 0 else self.data, (self,), 'ReLU') + out = Value(0 if self.data < 0 else self.data, (self,), "ReLU") def _backward(): self.grad += (out.data > 0) * out.grad + out._backward = _backward return out @@ -78,9 +81,16 @@ def test_value_operations(): # Actual results results = [a, b, c, d, e, f, g] - for i, (result, (expected_data, expected_grad)) in enumerate(zip(results, expected)): - assert result.data == expected_data, f"Test failed at step {i}: data mismatch ({result.data} != {expected_data})" - assert result.grad == expected_grad, f"Test failed at step {i}: grad mismatch ({result.grad} != {expected_grad})" + for i, (result, (expected_data, expected_grad)) in enumerate( + zip(results, expected) + ): + assert result.data == expected_data, ( + f"Test failed at step {i}: data mismatch ({result.data} != {expected_data})" + ) + assert result.grad == expected_grad, ( + f"Test failed at step {i}: grad mismatch ({result.grad} != {expected_grad})" + ) + if __name__ == "__main__": test_value_operations() diff --git a/old_repo/Problems/28_svd_2x2_eign/solution.py b/old_repo/Problems/28_svd_2x2_eign/solution.py index 89f388b1..02e21dcf 100644 --- a/old_repo/Problems/28_svd_2x2_eign/solution.py +++ b/old_repo/Problems/28_svd_2x2_eign/solution.py @@ -5,8 +5,8 @@ def svd_2x2(A: np.ndarray) -> tuple: y1, x1 = (A[1, 0] + A[0, 1]), (A[0, 0] - A[1, 1]) y2, x2 = (A[1, 0] - A[0, 1]), (A[0, 0] + A[1, 1]) - h1 = np.sqrt(y1 ** 2 + x1 ** 2) - h2 = np.sqrt(y2 ** 2 + x2 ** 2) + h1 = np.sqrt(y1**2 + x1**2) + h2 = np.sqrt(y2**2 + x2**2) t1 = x1 / h1 t2 = x2 / h2 @@ -34,7 +34,11 @@ def is_equal(A: np.ndarray, B: np.ndarray, precision=1e-10) -> bool: # 1. U*S*V.T == A # 2. U and V are orthogonal matrix -> U*U.T == E, V*V.T == E result = U @ np.diag(s) @ V - return is_equal(result, A) and is_equal(U @ U.T, np.eye(U.shape[0])) and is_equal(V @ V.T, np.eye(V.shape[0])) + return ( + is_equal(result, A) + and is_equal(U @ U.T, np.eye(U.shape[0])) + and is_equal(V @ V.T, np.eye(V.shape[0])) + ) def test_svd_2x2(): diff --git a/old_repo/Problems/2_transpose_matrix/solution.py b/old_repo/Problems/2_transpose_matrix/solution.py index 606fbd46..234112b8 100644 --- a/old_repo/Problems/2_transpose_matrix/solution.py +++ b/old_repo/Problems/2_transpose_matrix/solution.py @@ -14,6 +14,7 @@ def test_transpose_matrix() -> None: a: list[list[int | float]] = [[1, 2, 3], [4, 5, 6]] assert transpose_matrix(a) == [[1, 4], [2, 5], [3, 6]] + if __name__ == "__main__": test_transpose_matrix() - print("All tests passed.") \ No newline at end of file + print("All tests passed.") diff --git a/old_repo/Problems/32_polynomial_features/solution.py b/old_repo/Problems/32_polynomial_features/solution.py index df0d21f1..1a4788a8 100644 --- a/old_repo/Problems/32_polynomial_features/solution.py +++ b/old_repo/Problems/32_polynomial_features/solution.py @@ -1,55 +1,136 @@ import numpy as np from itertools import combinations_with_replacement + def polynomial_features(X, degree): n_samples, n_features = np.shape(X) # Generate all combinations of feature indices for polynomial terms def index_combinations(): - combs = [combinations_with_replacement(range(n_features), i) for i in range(0, degree + 1)] + combs = [ + combinations_with_replacement(range(n_features), i) + for i in range(0, degree + 1) + ] flat_combs = [item for sublist in combs for item in sublist] return flat_combs - + combinations = index_combinations() n_output_features = len(combinations) X_new = np.empty((n_samples, n_output_features)) - + # Compute polynomial features - for i, index_combs in enumerate(combinations): + for i, index_combs in enumerate(combinations): X_new[:, i] = np.prod(X[:, index_combs], axis=1) return X_new + def test_polynomial_features(): # Test case 1 X = np.array([[2, 3], [3, 4], [5, 6]]) degree = 2 - expected_output = np.array([ - [ 1., 2., 3., 4., 6., 9.], - [ 1., 3., 4., 9., 12., 16.], - [ 1., 5., 6., 25., 30., 36.] - ]) - assert np.allclose(polynomial_features(X, degree), expected_output), "Test case 1 failed" - + expected_output = np.array( + [ + [1.0, 2.0, 3.0, 4.0, 6.0, 9.0], + [1.0, 3.0, 4.0, 9.0, 12.0, 16.0], + [1.0, 5.0, 6.0, 25.0, 30.0, 36.0], + ] + ) + assert np.allclose(polynomial_features(X, degree), expected_output), ( + "Test case 1 failed" + ) + # Test case 2 X = np.array([[1, 2], [3, 4], [5, 6]]) degree = 3 - expected_output = np.array([ - [ 1., 1., 2., 1., 2., 4., 1., 2., 4., 8.], - [ 1., 3., 4., 9., 12., 16., 27., 36., 48., 64.], - [ 1., 5., 6., 25., 30., 36., 125., 150., 180., 216.] - ]) - assert np.allclose(polynomial_features(X, degree), expected_output), "Test case 2 failed" - + expected_output = np.array( + [ + [1.0, 1.0, 2.0, 1.0, 2.0, 4.0, 1.0, 2.0, 4.0, 8.0], + [1.0, 3.0, 4.0, 9.0, 12.0, 16.0, 27.0, 36.0, 48.0, 64.0], + [1.0, 5.0, 6.0, 25.0, 30.0, 36.0, 125.0, 150.0, 180.0, 216.0], + ] + ) + assert np.allclose(polynomial_features(X, degree), expected_output), ( + "Test case 2 failed" + ) + # Test case 3 X = np.array([[1, 2, 3], [3, 4, 5], [5, 6, 9]]) degree = 3 - expected_output = np.array([ - [ 1., 1., 2., 3., 1., 2., 3., 4., 6., 9., 1., 2., 3., 4., 6., 9., 8., 12., 18., 27.], - [ 1., 3., 4., 5., 9., 12., 15., 16., 20., 25., 27., 36., 45., 48., 60., 75., 64., 80., 100., 125.], - [ 1., 5., 6., 9., 25., 30., 45., 36., 54., 81., 125., 150., 225., 180., 270., 405., 216., 324., 486., 729.] - ]) - assert np.allclose(polynomial_features(X, degree), expected_output), "Test case 3 failed" + expected_output = np.array( + [ + [ + 1.0, + 1.0, + 2.0, + 3.0, + 1.0, + 2.0, + 3.0, + 4.0, + 6.0, + 9.0, + 1.0, + 2.0, + 3.0, + 4.0, + 6.0, + 9.0, + 8.0, + 12.0, + 18.0, + 27.0, + ], + [ + 1.0, + 3.0, + 4.0, + 5.0, + 9.0, + 12.0, + 15.0, + 16.0, + 20.0, + 25.0, + 27.0, + 36.0, + 45.0, + 48.0, + 60.0, + 75.0, + 64.0, + 80.0, + 100.0, + 125.0, + ], + [ + 1.0, + 5.0, + 6.0, + 9.0, + 25.0, + 30.0, + 45.0, + 36.0, + 54.0, + 81.0, + 125.0, + 150.0, + 225.0, + 180.0, + 270.0, + 405.0, + 216.0, + 324.0, + 486.0, + 729.0, + ], + ] + ) + assert np.allclose(polynomial_features(X, degree), expected_output), ( + "Test case 3 failed" + ) + if __name__ == "__main__": test_polynomial_features() diff --git a/old_repo/Problems/33_random_subsets/solution.py b/old_repo/Problems/33_random_subsets/solution.py index 850fb041..18f293ed 100644 --- a/old_repo/Problems/33_random_subsets/solution.py +++ b/old_repo/Problems/33_random_subsets/solution.py @@ -1,12 +1,18 @@ import numpy as np + def get_random_subsets(X, y, n_subsets, replacements=True, seed=42): np.random.seed(seed) n, m = X.shape - + subset_size = n if replacements else n // 2 - idx = np.array([np.random.choice(n, subset_size, replace=replacements) for _ in range(n_subsets)]) + idx = np.array( + [ + np.random.choice(n, subset_size, replace=replacements) + for _ in range(n_subsets) + ] + ) # convert all ndarrays to lists return [(X[idx][i].tolist(), y[idx][i].tolist()) for i in range(n_subsets)] @@ -15,15 +21,23 @@ def test_get_random_subsets(): # Test case 1 X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]) y = np.array([1, 2, 3, 4, 5]) - expected_output = [([[3, 4], [9, 10]], [2, 5]), ([[7, 8], [3, 4]], [4, 2]), ([[3, 4], [1, 2]], [2, 1])] - assert get_random_subsets(X, y, 3, False, seed=42) == expected_output, "Test case 1 failed" + expected_output = [ + ([[3, 4], [9, 10]], [2, 5]), + ([[7, 8], [3, 4]], [4, 2]), + ([[3, 4], [1, 2]], [2, 1]), + ] + assert get_random_subsets(X, y, 3, False, seed=42) == expected_output, ( + "Test case 1 failed" + ) - # Test case 2 X = np.array([[1, 1], [2, 2], [3, 3], [4, 4]]) y = np.array([10, 20, 30, 40]) expected_output = [([[3, 3], [4, 4], [1, 1], [3, 3]], [30, 40, 10, 30])] - assert get_random_subsets(X, y, 1, True, seed=42) == expected_output, "Test case 2 failed" + assert get_random_subsets(X, y, 1, True, seed=42) == expected_output, ( + "Test case 2 failed" + ) + if __name__ == "__main__": test_get_random_subsets() diff --git a/old_repo/Problems/39_log_softmax/solution.py b/old_repo/Problems/39_log_softmax/solution.py index b1b5da54..d3b4defa 100644 --- a/old_repo/Problems/39_log_softmax/solution.py +++ b/old_repo/Problems/39_log_softmax/solution.py @@ -1,23 +1,26 @@ import numpy as np + def log_softmax(scores: np.ndarray) -> np.ndarray: # Subtract the maximum value for numerical stability scores = scores - np.max(scores) return np.round(scores - np.log(np.sum(np.exp(scores))), 4) + def test_log_softmax(): # Test case 1 - A = np.array([1,2,3]) + A = np.array([1, 2, 3]) assert np.allclose(log_softmax(A), [-2.4076, -1.4076, -0.4076]) # Test case 2 - A = np.array([1,1,1]) + A = np.array([1, 1, 1]) assert np.allclose(log_softmax(A), [-1.0986, -1.0986, -1.0986]) # Test case 3 - A = np.array([1,1,0]) + A = np.array([1, 1, 0]) assert np.allclose(log_softmax(A), [-0.862, -0.862, -1.862]) + if __name__ == "__main__": test_log_softmax() print("All log softmax tests passed.") diff --git a/old_repo/Problems/3_reshape_matrix/solution.py b/old_repo/Problems/3_reshape_matrix/solution.py index 9ced9795..3be1dfbd 100644 --- a/old_repo/Problems/3_reshape_matrix/solution.py +++ b/old_repo/Problems/3_reshape_matrix/solution.py @@ -1,13 +1,17 @@ import numpy as np -def reshape_matrix(a: list[list[int | float]],new_shape: tuple[int, int]) -> list[list[int | float]]: + +def reshape_matrix( + a: list[list[int | float]], new_shape: tuple[int, int] +) -> list[list[int | float]]: # Reshape the matrix using numpy and return it as a list of lists # Not compatible case - if len(a)*len(a[0]) != new_shape[0]*new_shape[1]: + if len(a) * len(a[0]) != new_shape[0] * new_shape[1]: return [] # Compatible matches return np.array(a).reshape(new_shape).tolist() + def test_reshape_matrix() -> None: # Test cases for reshape_matrix function @@ -32,37 +36,47 @@ def test_reshape_matrix() -> None: assert reshape_matrix(a, new_shape) == [] # Test case 5 - a = [[1, 2],[3, 4]] + a = [[1, 2], [3, 4]] new_shape = (4, 1) assert reshape_matrix(a, new_shape) == [[1], [2], [3], [4]] # Test case 6 - a = [[1, 2, 3],[4, 5, 6]] - new_shape = (2, 3) + a = [[1, 2, 3], [4, 5, 6]] + new_shape = (2, 3) assert reshape_matrix(a, new_shape) == [[1, 2, 3], [4, 5, 6]] # Test case 7 - a = [[1, 2, 3],[4, 5, 6]] + a = [[1, 2, 3], [4, 5, 6]] new_shape = (6, 1) assert reshape_matrix(a, new_shape) == [[1], [2], [3], [4], [5], [6]] # Test case 8 - a = [[1, 2],[3, 4],[5, 6]] + a = [[1, 2], [3, 4], [5, 6]] new_shape = (3, 2) # same as original assert reshape_matrix(a, new_shape) == [[1, 2], [3, 4], [5, 6]] # Test case 9 - a = [[1.5, 2.2, 3.1],[4.7, 5.9, 6.3]] + a = [[1.5, 2.2, 3.1], [4.7, 5.9, 6.3]] new_shape = (3, 2) - assert reshape_matrix(a, new_shape) == [[1.5, 2.2],[3.1, 4.7],[5.9, 6.3]] + assert reshape_matrix(a, new_shape) == [[1.5, 2.2], [3.1, 4.7], [5.9, 6.3]] # Test case 10 - a = [[1.5, 2.2, 3.1],[4.7, 5.9, 6.3],[7.7, 8.8, 9.9]] + a = [[1.5, 2.2, 3.1], [4.7, 5.9, 6.3], [7.7, 8.8, 9.9]] new_shape = (9, 1) - assert reshape_matrix(a, new_shape) == [[1.5], [2.2], [3.1], [4.7], [5.9], [6.3], [7.7], [8.8], [9.9]] + assert reshape_matrix(a, new_shape) == [ + [1.5], + [2.2], + [3.1], + [4.7], + [5.9], + [6.3], + [7.7], + [8.8], + [9.9], + ] # Test case 11 - a = [[0, 0],[0, 0]] + a = [[0, 0], [0, 0]] new_shape = (2, 2) assert reshape_matrix(a, new_shape) == [[0, 0], [0, 0]] @@ -92,14 +106,14 @@ def test_reshape_matrix() -> None: assert reshape_matrix(a, new_shape) == [[1, 2, 3, 4, 5]] # Test case 17 - a = [[-1, -2],[-3, -4]] + a = [[-1, -2], [-3, -4]] new_shape = (1, 4) assert reshape_matrix(a, new_shape) == [[-1, -2, -3, -4]] # Test case 18 - a = [[-1, 2],[3, -4],[5, 6],[7, -8]] + a = [[-1, 2], [3, -4], [5, 6], [7, -8]] new_shape = (2, 4) - assert reshape_matrix(a, new_shape) == [[-1, 2, 3, -4],[5, 6, 7, -8]] + assert reshape_matrix(a, new_shape) == [[-1, 2, 3, -4], [5, 6, 7, -8]] # Test case 19 a = [[1, 2, 3, 4, 5, 6]] @@ -111,6 +125,7 @@ def test_reshape_matrix() -> None: new_shape = (2, 3) assert reshape_matrix(a, new_shape) == [[1, 2, 3], [4, 5, 6]] + if __name__ == "__main__": test_reshape_matrix() - print("All reshape_matrix tests passed.") \ No newline at end of file + print("All reshape_matrix tests passed.") diff --git a/old_repo/Problems/3_reshape_matrix/solution_2.py b/old_repo/Problems/3_reshape_matrix/solution_2.py index fa453d05..fa2a8872 100644 --- a/old_repo/Problems/3_reshape_matrix/solution_2.py +++ b/old_repo/Problems/3_reshape_matrix/solution_2.py @@ -1,9 +1,11 @@ -def reshape_matrix(a: list[list[int | float]],new_shape: tuple[int, int]) -> list[list[int | float]]: +def reshape_matrix( + a: list[list[int | float]], new_shape: tuple[int, int] +) -> list[list[int | float]]: # Extract dimensions - rows,cols = len(a),len(a[0]) + rows, cols = len(a), len(a[0]) new_rows, new_cols = new_shape # Check if reshaping is feasible - if rows*cols != new_rows*new_cols: + if rows * cols != new_rows * new_cols: return [] # Flatten matrix flat_matrix = [] @@ -21,7 +23,7 @@ def reshape_matrix(a: list[list[int | float]],new_shape: tuple[int, int]) -> lis index += 1 reshaped_matrix.append(new_row) return reshaped_matrix - + def test_reshape_matrix() -> None: # Test cases for reshape_matrix function @@ -47,37 +49,47 @@ def test_reshape_matrix() -> None: assert reshape_matrix(a, new_shape) == [] # Test case 5 - a = [[1, 2],[3, 4]] + a = [[1, 2], [3, 4]] new_shape = (4, 1) assert reshape_matrix(a, new_shape) == [[1], [2], [3], [4]] # Test case 6 - a = [[1, 2, 3],[4, 5, 6]] - new_shape = (2, 3) + a = [[1, 2, 3], [4, 5, 6]] + new_shape = (2, 3) assert reshape_matrix(a, new_shape) == [[1, 2, 3], [4, 5, 6]] # Test case 7 - a = [[1, 2, 3],[4, 5, 6]] + a = [[1, 2, 3], [4, 5, 6]] new_shape = (6, 1) assert reshape_matrix(a, new_shape) == [[1], [2], [3], [4], [5], [6]] # Test case 8 - a = [[1, 2],[3, 4],[5, 6]] + a = [[1, 2], [3, 4], [5, 6]] new_shape = (3, 2) # same as original assert reshape_matrix(a, new_shape) == [[1, 2], [3, 4], [5, 6]] # Test case 9 - a = [[1.5, 2.2, 3.1],[4.7, 5.9, 6.3]] + a = [[1.5, 2.2, 3.1], [4.7, 5.9, 6.3]] new_shape = (3, 2) - assert reshape_matrix(a, new_shape) == [[1.5, 2.2],[3.1, 4.7],[5.9, 6.3]] + assert reshape_matrix(a, new_shape) == [[1.5, 2.2], [3.1, 4.7], [5.9, 6.3]] # Test case 10 - a = [[1.5, 2.2, 3.1],[4.7, 5.9, 6.3],[7.7, 8.8, 9.9]] + a = [[1.5, 2.2, 3.1], [4.7, 5.9, 6.3], [7.7, 8.8, 9.9]] new_shape = (9, 1) - assert reshape_matrix(a, new_shape) == [[1.5], [2.2], [3.1], [4.7], [5.9], [6.3], [7.7], [8.8], [9.9]] + assert reshape_matrix(a, new_shape) == [ + [1.5], + [2.2], + [3.1], + [4.7], + [5.9], + [6.3], + [7.7], + [8.8], + [9.9], + ] # Test case 11 - a = [[0, 0],[0, 0]] + a = [[0, 0], [0, 0]] new_shape = (2, 2) assert reshape_matrix(a, new_shape) == [[0, 0], [0, 0]] @@ -107,14 +119,14 @@ def test_reshape_matrix() -> None: assert reshape_matrix(a, new_shape) == [[1, 2, 3, 4, 5]] # Test case 17 - a = [[-1, -2],[-3, -4]] + a = [[-1, -2], [-3, -4]] new_shape = (1, 4) assert reshape_matrix(a, new_shape) == [[-1, -2, -3, -4]] # Test case 18 - a = [[-1, 2],[3, -4],[5, 6],[7, -8]] + a = [[-1, 2], [3, -4], [5, 6], [7, -8]] new_shape = (2, 4) - assert reshape_matrix(a, new_shape) == [[-1, 2, 3, -4],[5, 6, 7, -8]] + assert reshape_matrix(a, new_shape) == [[-1, 2, 3, -4], [5, 6, 7, -8]] # Test case 19 a = [[1, 2, 3, 4, 5, 6]] @@ -126,6 +138,7 @@ def test_reshape_matrix() -> None: new_shape = (2, 3) assert reshape_matrix(a, new_shape) == [[1, 2, 3], [4, 5, 6]] + if __name__ == "__main__": test_reshape_matrix() - print("All reshape_matrix tests passed.") \ No newline at end of file + print("All reshape_matrix tests passed.") diff --git a/old_repo/Problems/41_simple_conv2d_layer/solution.py b/old_repo/Problems/41_simple_conv2d_layer/solution.py index 72e2212f..19a28908 100644 --- a/old_repo/Problems/41_simple_conv2d_layer/solution.py +++ b/old_repo/Problems/41_simple_conv2d_layer/solution.py @@ -1,10 +1,15 @@ import numpy as np -def simple_conv2d(input_matrix: np.ndarray, kernel: np.ndarray, padding: int, stride: int): + +def simple_conv2d( + input_matrix: np.ndarray, kernel: np.ndarray, padding: int, stride: int +): input_height, input_width = input_matrix.shape kernel_height, kernel_width = kernel.shape - padded_input = np.pad(input_matrix, ((padding, padding), (padding, padding)), mode='constant') + padded_input = np.pad( + input_matrix, ((padding, padding), (padding, padding)), mode="constant" + ) input_height_padded, input_width_padded = padded_input.shape output_height = (input_height_padded - kernel_height) // stride + 1 @@ -14,7 +19,10 @@ def simple_conv2d(input_matrix: np.ndarray, kernel: np.ndarray, padding: int, st for i in range(output_height): for j in range(output_width): - region = padded_input[i*stride:i*stride + kernel_height, j*stride:j*stride + kernel_width] + region = padded_input[ + i * stride : i * stride + kernel_height, + j * stride : j * stride + kernel_width, + ] output_matrix[i, j] = np.sum(region * kernel) return output_matrix @@ -22,79 +30,115 @@ def simple_conv2d(input_matrix: np.ndarray, kernel: np.ndarray, padding: int, st def test_simple_conv2d(): # Test case 1 - input_matrix = np.array([ - [1., 2., 3., 4., 5.], - [6., 7., 8., 9., 10.], - [11., 12., 13., 14., 15.], - [16., 17., 18., 19., 20.], - [21., 22., 23., 24., 25.], - ]) - kernel = np.array([ - [1., 2.], - [3., -1.], - ]) + input_matrix = np.array( + [ + [1.0, 2.0, 3.0, 4.0, 5.0], + [6.0, 7.0, 8.0, 9.0, 10.0], + [11.0, 12.0, 13.0, 14.0, 15.0], + [16.0, 17.0, 18.0, 19.0, 20.0], + [21.0, 22.0, 23.0, 24.0, 25.0], + ] + ) + kernel = np.array( + [ + [1.0, 2.0], + [3.0, -1.0], + ] + ) padding, stride = 0, 1 - expected = np.array([ - [ 16., 21., 26., 31.], - [ 41., 46., 51., 56.], - [ 66., 71., 76., 81.], - [ 91., 96., 101., 106.], - ]) - assert np.array_equal(expected, simple_conv2d(input_matrix, kernel, padding, stride)) + expected = np.array( + [ + [16.0, 21.0, 26.0, 31.0], + [41.0, 46.0, 51.0, 56.0], + [66.0, 71.0, 76.0, 81.0], + [91.0, 96.0, 101.0, 106.0], + ] + ) + assert np.array_equal( + expected, simple_conv2d(input_matrix, kernel, padding, stride) + ) # Test case 2 padding, stride = 1, 1 - expected = np.array([ - [ -1., 1., 3., 5., 7., 15.], - [ -4., 16., 21., 26., 31., 35.], - [ 1., 41., 46., 51., 56., 55.], - [ 6., 66., 71., 76., 81., 75.], - [ 11., 91., 96., 101., 106., 95.], - [ 42., 65., 68., 71., 74., 25.], - ]) - assert np.array_equal(expected, simple_conv2d(input_matrix, kernel, padding, stride)) + expected = np.array( + [ + [-1.0, 1.0, 3.0, 5.0, 7.0, 15.0], + [-4.0, 16.0, 21.0, 26.0, 31.0, 35.0], + [1.0, 41.0, 46.0, 51.0, 56.0, 55.0], + [6.0, 66.0, 71.0, 76.0, 81.0, 75.0], + [11.0, 91.0, 96.0, 101.0, 106.0, 95.0], + [42.0, 65.0, 68.0, 71.0, 74.0, 25.0], + ] + ) + assert np.array_equal( + expected, simple_conv2d(input_matrix, kernel, padding, stride) + ) # Test case 3 - kernel = np.array([ - [1., 2., 3.,], - [-6., 2., 8.,], - [5., 2., 3.,], - ]) + kernel = np.array( + [ + [ + 1.0, + 2.0, + 3.0, + ], + [ + -6.0, + 2.0, + 8.0, + ], + [ + 5.0, + 2.0, + 3.0, + ], + ] + ) padding, stride = 0, 1 - expected = np.array([ - [174., 194., 214.], - [274., 294., 314.], - [374., 394., 414.], - ]) - assert np.array_equal(expected, simple_conv2d(input_matrix, kernel, padding, stride)) + expected = np.array( + [ + [174.0, 194.0, 214.0], + [274.0, 294.0, 314.0], + [374.0, 394.0, 414.0], + ] + ) + assert np.array_equal( + expected, simple_conv2d(input_matrix, kernel, padding, stride) + ) # Test case 4 padding, stride = 1, 2 - expected = np.array([ - [51., 104., 51.], - [234., 294., 110.], - [301., 216., -35.], - ]) - assert np.array_equal(expected, simple_conv2d(input_matrix, kernel, padding, stride)) + expected = np.array( + [ + [51.0, 104.0, 51.0], + [234.0, 294.0, 110.0], + [301.0, 216.0, -35.0], + ] + ) + assert np.array_equal( + expected, simple_conv2d(input_matrix, kernel, padding, stride) + ) # Test case 5 - input_matrix = np.array([ - [1, 2, 3], - [1, 2, 3], - [1, 2, 3], - ]) - kernel = np.array([ - [1, 2, 3], - [1, 2, 3], - [1, 2, 3], - ]) + input_matrix = np.array( + [ + [1, 2, 3], + [1, 2, 3], + [1, 2, 3], + ] + ) + kernel = np.array( + [ + [1, 2, 3], + [1, 2, 3], + [1, 2, 3], + ] + ) padding, stride = 1, 1 - expected = np.array([ - [16., 28., 16.], - [24., 42., 24.], - [16., 28., 16.] -]) - assert np.array_equal(expected, simple_conv2d(input_matrix, kernel, padding, stride)) + expected = np.array([[16.0, 28.0, 16.0], [24.0, 42.0, 24.0], [16.0, 28.0, 16.0]]) + assert np.array_equal( + expected, simple_conv2d(input_matrix, kernel, padding, stride) + ) if __name__ == "__main__": diff --git a/old_repo/Problems/42_relu_activation_function/solution.py b/old_repo/Problems/42_relu_activation_function/solution.py index 8de4562e..9114fcac 100644 --- a/old_repo/Problems/42_relu_activation_function/solution.py +++ b/old_repo/Problems/42_relu_activation_function/solution.py @@ -1,16 +1,18 @@ def relu(z: float) -> float: return max(0, z) + def test_relu(): # Test case 1: z = 0 assert relu(0) == 0, "Test case 1 failed" - + # Test case 2: z = 1 assert relu(1) == 1, "Test case 2 failed" - + # Test case 3: z = -1 assert relu(-1) == 0, "Test case 3 failed" + if __name__ == "__main__": test_relu() - print("All ReLU tests passed.") \ No newline at end of file + print("All ReLU tests passed.") diff --git a/old_repo/Problems/43_ridge_loss/solution.py b/old_repo/Problems/43_ridge_loss/solution.py index 71c8e5eb..4a342b6c 100644 --- a/old_repo/Problems/43_ridge_loss/solution.py +++ b/old_repo/Problems/43_ridge_loss/solution.py @@ -1,30 +1,28 @@ import numpy as np + def ridge_loss(X: np.ndarray, w: np.ndarray, y_true: np.ndarray, alpha): - loss = np.mean((y_true - X@w)**2) + alpha * np.sum(w**2) + loss = np.mean((y_true - X @ w) ** 2) + alpha * np.sum(w**2) return np.array(loss) def test_ridge_loss(): # Test case 1 - X = np.array([[1,1],[2,1],[3,1],[4,1]]) - W = np.array([.2,2]) - y = np.array([2,3,4,5]) - - expected = 2.204 - assert np.array_equal(expected, ridge_loss(X,W,y,.1)) + X = np.array([[1, 1], [2, 1], [3, 1], [4, 1]]) + W = np.array([0.2, 2]) + y = np.array([2, 3, 4, 5]) + expected = 2.204 + assert np.array_equal(expected, ridge_loss(X, W, y, 0.1)) # Test case 2 - X = np.array([[1,1,4],[2,1,2],[3,1,.1],[4,1,1.2],[1,2,3]]) - W = np.array([.2,2,5]) - y = np.array([2,3,4,5,2]) - - expected = 161.7884 - assert np.array_equal(expected, ridge_loss(X,W,y,.1)) + X = np.array([[1, 1, 4], [2, 1, 2], [3, 1, 0.1], [4, 1, 1.2], [1, 2, 3]]) + W = np.array([0.2, 2, 5]) + y = np.array([2, 3, 4, 5, 2]) - + expected = 161.7884 + assert np.array_equal(expected, ridge_loss(X, W, y, 0.1)) if __name__ == "__main__": diff --git a/old_repo/Problems/45_linear_kernel/solution.py b/old_repo/Problems/45_linear_kernel/solution.py index d532da00..e8d5a827 100644 --- a/old_repo/Problems/45_linear_kernel/solution.py +++ b/old_repo/Problems/45_linear_kernel/solution.py @@ -1,21 +1,24 @@ import numpy as np + def kernel_function(x1, x2): return np.inner(x1, x2) + def test_kernel_function(): # Test case 1 x1 = np.array([1, 2, 3]) x2 = np.array([4, 5, 6]) expected_output = 32 assert kernel_function(x1, x2) == expected_output, "Test case 1 failed" - + # Test case 2 x1 = np.array([0, 1, 2]) x2 = np.array([3, 4, 5]) expected_output = 14 assert kernel_function(x1, x2) == expected_output, "Test case 2 failed" + if __name__ == "__main__": test_kernel_function() print("All kernel_function tests passed.") diff --git a/old_repo/Problems/46_precision/solution.py b/old_repo/Problems/46_precision/solution.py index df2136ac..73e4c05b 100644 --- a/old_repo/Problems/46_precision/solution.py +++ b/old_repo/Problems/46_precision/solution.py @@ -1,9 +1,15 @@ import numpy as np + def precision(y_true, y_pred): true_positives = np.sum((y_true == 1) & (y_pred == 1)) false_positives = np.sum((y_true == 0) & (y_pred == 1)) - return true_positives / (true_positives + false_positives) if (true_positives + false_positives) > 0 else 0.0 + return ( + true_positives / (true_positives + false_positives) + if (true_positives + false_positives) > 0 + else 0.0 + ) + def test_precision(): # Test case 1 @@ -11,13 +17,14 @@ def test_precision(): y_pred = np.array([1, 0, 1, 0, 0, 1]) expected_output = 1.0 assert precision(y_true, y_pred) == expected_output, "Test case 1 failed" - + # Test case 2 y_true = np.array([1, 0, 1, 1, 0, 0]) y_pred = np.array([1, 0, 0, 0, 0, 1]) expected_output = 0.5 assert precision(y_true, y_pred) == expected_output, "Test case 2 failed" + if __name__ == "__main__": test_precision() print("All precision tests passed.") diff --git a/old_repo/Problems/47_gradient_descent/solution.py b/old_repo/Problems/47_gradient_descent/solution.py index 1331cdf2..596ff2fb 100644 --- a/old_repo/Problems/47_gradient_descent/solution.py +++ b/old_repo/Problems/47_gradient_descent/solution.py @@ -1,36 +1,40 @@ import numpy as np -def gradient_descent(X, y, weights, learning_rate, n_iterations, batch_size=1, method='batch'): + +def gradient_descent( + X, y, weights, learning_rate, n_iterations, batch_size=1, method="batch" +): m = len(y) - + for _ in range(n_iterations): - if method == 'batch': + if method == "batch": # Calculate the gradient using all data points predictions = X.dot(weights) errors = predictions - y gradient = 2 * X.T.dot(errors) / m weights = weights - learning_rate * gradient - - elif method == 'stochastic': + + elif method == "stochastic": # Update weights for each data point individually for i in range(m): prediction = X[i].dot(weights) error = prediction - y[i] gradient = 2 * X[i].T.dot(error) weights = weights - learning_rate * gradient - - elif method == 'mini_batch': + + elif method == "mini_batch": # Update weights using sequential batches of data points without shuffling for i in range(0, m, batch_size): - X_batch = X[i:i+batch_size] - y_batch = y[i:i+batch_size] + X_batch = X[i : i + batch_size] + y_batch = y[i : i + batch_size] predictions = X_batch.dot(weights) errors = predictions - y_batch gradient = 2 * X_batch.T.dot(errors) / batch_size weights = weights - learning_rate * gradient - + return weights + def test_gradient_descent(): # Test case 1: Batch Gradient Descent X = np.array([[1, 1], [2, 1], [3, 1], [4, 1]]) @@ -39,18 +43,32 @@ def test_gradient_descent(): learning_rate = 0.01 n_iterations = 100 expected_output = np.array([1.14905239, 0.56176776]) - assert np.allclose(gradient_descent(X, y, weights, learning_rate, n_iterations, method='batch'), expected_output), "Test case 1 failed" - + assert np.allclose( + gradient_descent(X, y, weights, learning_rate, n_iterations, method="batch"), + expected_output, + ), "Test case 1 failed" + # Test case 2: Stochastic Gradient Descent weights = np.zeros(X.shape[1]) expected_output = np.array([1.0507814, 0.83659454]) - assert np.allclose(gradient_descent(X, y, weights, learning_rate, n_iterations, method='stochastic'), expected_output), "Test case 2 failed" - + assert np.allclose( + gradient_descent( + X, y, weights, learning_rate, n_iterations, method="stochastic" + ), + expected_output, + ), "Test case 2 failed" + # Test case 3: Mini-Batch Gradient Descent weights = np.zeros(X.shape[1]) batch_size = 2 expected_output = np.array([1.10334065, 0.68329431]) - assert np.allclose(gradient_descent(X, y, weights, learning_rate, n_iterations, batch_size, method='mini_batch'), expected_output), "Test case 3 failed" + assert np.allclose( + gradient_descent( + X, y, weights, learning_rate, n_iterations, batch_size, method="mini_batch" + ), + expected_output, + ), "Test case 3 failed" + if __name__ == "__main__": test_gradient_descent() diff --git a/old_repo/Problems/48_rref/solution.py b/old_repo/Problems/48_rref/solution.py index 06ab6807..bd45a181 100644 --- a/old_repo/Problems/48_rref/solution.py +++ b/old_repo/Problems/48_rref/solution.py @@ -1,15 +1,17 @@ import numpy as np + def rref(matrix): # Convert to float for division operations A = matrix.astype(np.float32) n, m = A.shape - + for i in range(n): if A[i, i] == 0: nonzero_rel_id = np.nonzero(A[i:, i])[0] - if len(nonzero_rel_id) == 0: continue - + if len(nonzero_rel_id) == 0: + continue + A[i] = A[i] + A[nonzero_rel_id[0] + i] A[i] = A[i] / A[i, i] @@ -19,58 +21,33 @@ def rref(matrix): return A + def test_rref(): # Test case 1 - matrix = np.array([ - [1, 2, -1, -4], - [2, 3, -1, -11], - [-2, 0, -3, 22] - ]) - expected_output = np.array([ - [ 1., 0., 0., -8.], - [ 0., 1., 0., 1.], - [-0., -0., 1., -2.] - ]) + matrix = np.array([[1, 2, -1, -4], [2, 3, -1, -11], [-2, 0, -3, 22]]) + expected_output = np.array( + [[1.0, 0.0, 0.0, -8.0], [0.0, 1.0, 0.0, 1.0], [-0.0, -0.0, 1.0, -2.0]] + ) assert np.allclose(rref(matrix), expected_output), "Test case 1 failed" - + # Test case 2 - matrix = np.array([ - [2, 4, -2], - [4, 9, -3], - [-2, -3, 7] - ]) - expected_output = np.array([ - [ 1., 0., 0.], - [ 0., 1., 0.], - [ 0., 0., 1.] - ]) + matrix = np.array([[2, 4, -2], [4, 9, -3], [-2, -3, 7]]) + expected_output = np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]) assert np.allclose(rref(matrix), expected_output), "Test case 2 failed" - + # Test case 3 - matrix = np.array([ - [0, 2, -1, -4], - [2, 0, -1, -11], - [-2, 0, 0, 22] - ]) - expected_output = np.array([ - [ 1., 0., 0., -11.], - [-0., 1., 0., -7.5], - [-0., -0., 1., -11.] - ]) + matrix = np.array([[0, 2, -1, -4], [2, 0, -1, -11], [-2, 0, 0, 22]]) + expected_output = np.array( + [[1.0, 0.0, 0.0, -11.0], [-0.0, 1.0, 0.0, -7.5], [-0.0, -0.0, 1.0, -11.0]] + ) assert np.allclose(rref(matrix), expected_output), "Test case 3 failed" - - # Test case 4 - matrix = np.array([ - [1, 2, -1], - [2, 4, -1], - [-2, -4, -3]]) - expected_output = np.array([ - [ 1., 2., 0.], - [ 0., 0., 0.], - [-0., -0., 1.] - ]) + + # Test case 4 + matrix = np.array([[1, 2, -1], [2, 4, -1], [-2, -4, -3]]) + expected_output = np.array([[1.0, 2.0, 0.0], [0.0, 0.0, 0.0], [-0.0, -0.0, 1.0]]) assert np.allclose(rref(matrix), expected_output), "Test case 4 failed" + if __name__ == "__main__": test_rref() print("All rref tests passed.") diff --git a/old_repo/Problems/4_calculate_mean_by_row_or_column/solution.py b/old_repo/Problems/4_calculate_mean_by_row_or_column/solution.py index 3bd4eda9..5e9bcfcb 100644 --- a/old_repo/Problems/4_calculate_mean_by_row_or_column/solution.py +++ b/old_repo/Problems/4_calculate_mean_by_row_or_column/solution.py @@ -3,34 +3,36 @@ def calculate_matrix_mean( mode: str, ) -> list[float]: # Calculate mean by row or column - if mode == 'column': + if mode == "column": return [sum(col) / len(matrix) for col in zip(*matrix)] - elif mode == 'row': + elif mode == "row": return [sum(row) / len(row) for row in matrix] else: raise ValueError("Mode must be 'row' or 'column'") + def test_calculate_matrix_mean() -> None: # Test cases for calculate_matrix_mean function # Test case 1 matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] - mode = 'column' + mode = "column" assert calculate_matrix_mean(matrix, mode) == [4.0, 5.0, 6.0] # Test case 2 - mode = 'row' + mode = "row" assert calculate_matrix_mean(matrix, mode) == [2.0, 5.0, 8.0] # Test case 3 matrix = [[1, 2], [3, 4], [5, 6]] - mode = 'column' + mode = "column" assert calculate_matrix_mean(matrix, mode) == [3.0, 4.0] # Test case 4 - mode = 'row' + mode = "row" assert calculate_matrix_mean(matrix, mode) == [1.5, 3.5, 5.5] + if __name__ == "__main__": test_calculate_matrix_mean() - print("All calculate_matrix_mean tests passed.") \ No newline at end of file + print("All calculate_matrix_mean tests passed.") diff --git a/old_repo/Problems/4_calculate_mean_by_row_or_column/solution_2.py b/old_repo/Problems/4_calculate_mean_by_row_or_column/solution_2.py index 343b3a52..587cd2b4 100644 --- a/old_repo/Problems/4_calculate_mean_by_row_or_column/solution_2.py +++ b/old_repo/Problems/4_calculate_mean_by_row_or_column/solution_2.py @@ -3,42 +3,44 @@ def calculate_matrix_mean( mode: str, ) -> list[float]: # Calculate mean by row or column - if mode not in ['row','column']: + if mode not in ["row", "column"]: raise ValueError("Mode has to be row or column") - #Get dimensions and initialize return array + # Get dimensions and initialize return array rows, columns = len(matrix), len(matrix[0]) means = [] - #Row mode - if mode == 'row': + # Row mode + if mode == "row": for r in range(rows): mean = 0 for c in range(columns): mean += matrix[r][c] mean /= columns means.append(mean) - #Column mode + # Column mode else: - for c in range(columns): + for c in range(columns): mean = 0 for r in range(rows): mean += matrix[r][c] mean /= rows - means.append(mean) - #Return + means.append(mean) + # Return return means + def test_calculate_matrix_mean() -> None: # Test cases for calculate_matrix_mean function # Test case 1 matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] - mode = 'column' + mode = "column" assert calculate_matrix_mean(matrix, mode) == [4.0, 5.0, 6.0] # Test case 2 - mode = 'row' + mode = "row" assert calculate_matrix_mean(matrix, mode) == [2.0, 5.0, 8.0] + if __name__ == "__main__": test_calculate_matrix_mean() - print("All calculate_matrix_mean tests passed.") \ No newline at end of file + print("All calculate_matrix_mean tests passed.") diff --git a/old_repo/Problems/50_lasso_regression_gradient_descent/solution.py b/old_repo/Problems/50_lasso_regression_gradient_descent/solution.py index ecf66fc4..8cf2c512 100644 --- a/old_repo/Problems/50_lasso_regression_gradient_descent/solution.py +++ b/old_repo/Problems/50_lasso_regression_gradient_descent/solution.py @@ -1,6 +1,14 @@ import numpy as np -def l1_regularization_gradient_descent(X:np.array, y:np.array, alpha: float=0.1, learning_rate: float=0.01, max_iter: int=1000, tol: float=1e-4) -> tuple: + +def l1_regularization_gradient_descent( + X: np.array, + y: np.array, + alpha: float = 0.1, + learning_rate: float = 0.01, + max_iter: int = 1000, + tol: float = 1e-4, +) -> tuple: n_samples, n_features = X.shape # zero out weights and biases weights = np.zeros(n_features) @@ -19,27 +27,32 @@ def l1_regularization_gradient_descent(X:np.array, y:np.array, alpha: float=0.1, return weights, bias -def test_l1_regularization_gradient_descent(): - X = np.array([[0,0], [1, 1], [2, 2]]) +def test_l1_regularization_gradient_descent(): + X = np.array([[0, 0], [1, 1], [2, 2]]) y = np.array([0, 1, 2]) alpha = 0.1 - l1_regularization_gradient_descent(X,y , alpha = 0.1, max_iter = 5000) + l1_regularization_gradient_descent(X, y, alpha=0.1, max_iter=5000) expected_weights = np.array([0.425, 0.425]) expected_bias = 0.15 - weights, bias = l1_regularization_gradient_descent(X, y, alpha=alpha, learning_rate=0.01, max_iter=1000) + weights, bias = l1_regularization_gradient_descent( + X, y, alpha=alpha, learning_rate=0.01, max_iter=1000 + ) assert np.allclose(weights, expected_weights, atol=0.01), "Test case 1 failed" assert np.isclose(bias, expected_bias, atol=0.01), "Test case 1 failed" - - X = np.array([[0,1], [1,2], [2,3], [3,4], [4,5]]) + X = np.array([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]) y = np.array([1, 2, 3, 4, 5]) alpha = 0.1 expected_weights = np.array([0.27, 0.68]) - expected_bias = 0.4 - weights, bias = l1_regularization_gradient_descent(X, y, alpha=alpha, learning_rate=0.01, max_iter=1000) + expected_bias = 0.4 + weights, bias = l1_regularization_gradient_descent( + X, y, alpha=alpha, learning_rate=0.01, max_iter=1000 + ) assert np.allclose(weights, expected_weights, atol=0.01), "Test case 2 failed" assert np.isclose(bias, expected_bias, atol=0.01), "Test case 2 failed" + + if __name__ == "__main__": test_l1_regularization_gradient_descent() print("All l1_regularization tests passed.") diff --git a/old_repo/Problems/51_OSA_distance/solution.py b/old_repo/Problems/51_OSA_distance/solution.py index dd3f5ea3..7f00f3f0 100644 --- a/old_repo/Problems/51_OSA_distance/solution.py +++ b/old_repo/Problems/51_OSA_distance/solution.py @@ -1,42 +1,47 @@ def OSA(source: str, target: str) -> int: source_len, target_len = len(source), len(target) - - osa_matrix = [[0]*(target_len + 1) for _ in range(source_len + 1)] - + + osa_matrix = [[0] * (target_len + 1) for _ in range(source_len + 1)] + for j in range(1, target_len + 1): osa_matrix[0][j] = j - + for i in range(1, source_len + 1): osa_matrix[i][0] = i - + for i in range(1, source_len + 1): for j in range(1, target_len + 1): osa_matrix[i][j] = min( osa_matrix[i - 1][j] + 1, osa_matrix[i][j - 1] + 1, - osa_matrix[i - 1][j - 1] + (1 if source[i - 1] != target[j - 1] else 0) + osa_matrix[i - 1][j - 1] + (1 if source[i - 1] != target[j - 1] else 0), ) - if i > 1 and j > 1 and source[i - 1] == target[j-2] and source[i-2] == target[j - 1]: + if ( + i > 1 + and j > 1 + and source[i - 1] == target[j - 2] + and source[i - 2] == target[j - 1] + ): osa_matrix[i][j] = min(osa_matrix[i][j], osa_matrix[i - 2][j - 2] + 1) return osa_matrix[-1][-1] -def test_OSA(): +def test_OSA(): input_string_pairs = [ - ("butterfly", "dragonfly"), - ("london", "paris"), - ("shower", "grower"), - ("telescope", "microscope"), - ("labyrinth", "puzzle"), - ("silhouette", "shadow"), - ("whisper", "screaming"), - ("enigma", "mystery"), - ("symphony", "cacophony"), - ("mirage", "oasis"), - ("asteroid", "meteorite"), - ("palindrome", "palladium"), - ("caper", "acer") + ("butterfly", "dragonfly"), + ("london", "paris"), + ("shower", "grower"), + ("telescope", "microscope"), + ("labyrinth", "puzzle"), + ("silhouette", "shadow"), + ("whisper", "screaming"), + ("enigma", "mystery"), + ("symphony", "cacophony"), + ("mirage", "oasis"), + ("asteroid", "meteorite"), + ("palindrome", "palladium"), + ("caper", "acer"), ] expected_output = [6, 6, 2, 5, 9, 8, 9, 7, 4, 6, 5, 5, 2] @@ -44,6 +49,7 @@ def test_OSA(): for (s1, s2), expected_distance in zip(input_string_pairs, expected_output): assert OSA(s1, s2) == expected_distance + if __name__ == "__main__": test_OSA() print("All OSA distance tests passed") diff --git a/old_repo/Problems/52_recall/solution.py b/old_repo/Problems/52_recall/solution.py index 0a305ec7..1a079959 100644 --- a/old_repo/Problems/52_recall/solution.py +++ b/old_repo/Problems/52_recall/solution.py @@ -1,5 +1,6 @@ import numpy as np + def recall(y_true, y_pred): tp = np.sum((y_true == 1) & (y_pred == 1)) fn = np.sum((y_true == 1) & (y_pred == 0)) @@ -9,6 +10,7 @@ def recall(y_true, y_pred): except ZeroDivisionError: return 0.0 + def test_recall(): # Test case 1 y_true = np.array([1, 0, 1, 1, 0, 1]) @@ -46,6 +48,7 @@ def test_recall(): expected_output = 0.667 assert recall(y_true, y_pred) == expected_output, "Test case 6 failed" + if __name__ == "__main__": test_recall() print("All recall tests passed.") diff --git a/old_repo/Problems/53_self_attention/solution.py b/old_repo/Problems/53_self_attention/solution.py index 48addfa3..420822f7 100644 --- a/old_repo/Problems/53_self_attention/solution.py +++ b/old_repo/Problems/53_self_attention/solution.py @@ -1,13 +1,14 @@ import numpy as np + def compute_qkv(X, W_q, W_k, W_v): """ Compute Q, K, V matrices from input X and weights. - + Args: X: numpy array of shape (seq_len, d_model), input sequence W_q, W_k, W_v: numpy arrays of shape (d_model, d_model), weight matrices for Q, K, V - + Returns: Q, K, V: numpy arrays of shape (seq_len, d_model) """ @@ -16,67 +17,76 @@ def compute_qkv(X, W_q, W_k, W_v): V = np.dot(X, W_v) return Q, K, V + def self_attention(Q, K, V): """ Compute self-attention using the Q, K, V matrices. - + Args: Q, K, V: numpy arrays of shape (seq_len, d_model) - + Returns: attention_output: numpy array of shape (seq_len, d_model) """ d_k = Q.shape[1] - + # Compute attention scores scores = np.matmul(Q, K.T) / np.sqrt(d_k) - + # Apply softmax to get attention weights attention_weights = np.exp(scores) / np.sum(np.exp(scores), axis=1, keepdims=True) - + # Compute attention output attention_output = np.matmul(attention_weights, V) return attention_output + def test_self_attention(): # Test case 1: Basic functionality with computed Q, K, V X = np.array([[1, 0], [0, 1]]) W_q = np.array([[1, 0], [0, 1]]) W_k = np.array([[1, 0], [0, 1]]) W_v = np.array([[1, 2], [3, 4]]) - + Q, K, V = compute_qkv(X, W_q, W_k, W_v) expected_output = np.array([[1.660477, 2.660477], [2.339523, 3.339523]]) actual_output = self_attention(Q, K, V) - np.testing.assert_array_almost_equal(actual_output, expected_output, decimal=6, - err_msg="Test case 1 failed") + np.testing.assert_array_almost_equal( + actual_output, expected_output, decimal=6, err_msg="Test case 1 failed" + ) # Test case 2: Different input X and weight matrices X = np.array([[1, 1], [1, 0]]) W_q = np.array([[1, 0], [0, 1]]) W_k = np.array([[1, 0], [0, 1]]) W_v = np.array([[1, 2], [3, 4]]) - + Q, K, V = compute_qkv(X, W_q, W_k, W_v) - expected_output = np.array([[3.00928465, 4.6790462 ], - [2.5 , 4.]]) + expected_output = np.array([[3.00928465, 4.6790462], [2.5, 4.0]]) actual_output = self_attention(Q, K, V) - np.testing.assert_array_almost_equal(actual_output, expected_output, decimal=6, - err_msg="Test case 2 failed") + np.testing.assert_array_almost_equal( + actual_output, expected_output, decimal=6, err_msg="Test case 2 failed" + ) # Test case 3: Larger input X = np.array([[1, 0, 1], [0, 1, 1], [1, 1, 0]]) W_q = np.array([[1, 1, 0], [0, 1, 1], [1, 0, 1]]) W_k = np.array([[1, 1, 0], [0, 1, 1], [1, 0, 1]]) W_v = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - + Q, K, V = compute_qkv(X, W_q, W_k, W_v) - expected_output = np.array([[ 8.,10.,12. ], - [ 8.61987385, 10.61987385, 12.61987385], - [ 7.38012615 , 9.38012615, 11.38012615]]) + expected_output = np.array( + [ + [8.0, 10.0, 12.0], + [8.61987385, 10.61987385, 12.61987385], + [7.38012615, 9.38012615, 11.38012615], + ] + ) actual_output = self_attention(Q, K, V) - np.testing.assert_array_almost_equal(actual_output, expected_output, decimal=6, - err_msg="Test case 3 failed") + np.testing.assert_array_almost_equal( + actual_output, expected_output, decimal=6, err_msg="Test case 3 failed" + ) + if __name__ == "__main__": test_self_attention() diff --git a/old_repo/Problems/54_RNN_layer/solution.py b/old_repo/Problems/54_RNN_layer/solution.py index 6156f78d..faed0779 100644 --- a/old_repo/Problems/54_RNN_layer/solution.py +++ b/old_repo/Problems/54_RNN_layer/solution.py @@ -1,6 +1,13 @@ import numpy as np -def rnn_forward(input_sequence: list[list[float]], initial_hidden_state: list[float], Wx: list[list[float]], Wh: list[list[float]], b: list[float]) -> list[float]: + +def rnn_forward( + input_sequence: list[list[float]], + initial_hidden_state: list[float], + Wx: list[list[float]], + Wh: list[list[float]], + b: list[float], +) -> list[float]: h = np.array(initial_hidden_state) Wx = np.array(Wx) Wh = np.array(Wh) @@ -11,45 +18,44 @@ def rnn_forward(input_sequence: list[list[float]], initial_hidden_state: list[fl final_hidden_state = h return final_hidden_state + def test_rnn_forward(): # Test case 1: Single feature inputs input_sequence_1 = [[1.0], [2.0], [3.0]] initial_hidden_state_1 = [0.0] Wx_1 = [[0.5]] # Input to hidden weights Wh_1 = [[0.8]] # Hidden to hidden weights - b_1 = [0.0] # Bias + b_1 = [0.0] # Bias expected_output_1 = [0.97588162] output_1 = rnn_forward(input_sequence_1, initial_hidden_state_1, Wx_1, Wh_1, b_1) - assert np.allclose(output_1, expected_output_1, atol=0.01), f"Test case 1 failed: expected {expected_output_1}, got {output_1}" + assert np.allclose(output_1, expected_output_1, atol=0.01), ( + f"Test case 1 failed: expected {expected_output_1}, got {output_1}" + ) # Test case 2: Single feature inputs with different weights and bias input_sequence_2 = [[0.5], [0.1], [-0.2]] initial_hidden_state_2 = [0.0] Wx_2 = [[1.0]] # Input to hidden weights - Wh_2 = [[0.5]] # Hidden to hidden weights - b_2 = [0.1] # Bias + Wh_2 = [[0.5]] # Hidden to hidden weights + b_2 = [0.1] # Bias expected_output_2 = [0.118] output_2 = rnn_forward(input_sequence_2, initial_hidden_state_2, Wx_2, Wh_2, b_2) - assert np.allclose(output_2, expected_output_2, atol=0.01), f"Test case 2 failed: expected {expected_output_2}, got {output_2}" + assert np.allclose(output_2, expected_output_2, atol=0.01), ( + f"Test case 2 failed: expected {expected_output_2}, got {output_2}" + ) # Test case 3: Multiple feature inputs - input_sequence_3 = [ - [0.1, 0.2, 0.3], - [0.4, 0.5, 0.6] - ] + input_sequence_3 = [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]] initial_hidden_state_3 = [0.0, 0.0] - Wx_3 = [ - [0.1, 0.2, 0.3], - [0.4, 0.5, 0.6] - ] # Input to hidden weights - Wh_3 = [ - [0.7, 0.8], - [0.9, 1.0] - ] # Hidden to hidden weights + Wx_3 = [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]] # Input to hidden weights + Wh_3 = [[0.7, 0.8], [0.9, 1.0]] # Hidden to hidden weights b_3 = [0.1, 0.2] # Bias expected_output_3 = [0.7474, 0.9302] output_3 = rnn_forward(input_sequence_3, initial_hidden_state_3, Wx_3, Wh_3, b_3) - assert np.allclose(output_3, expected_output_3, atol=0.01), f"Test case 3 failed: expected {expected_output_3}, got {output_3}" + assert np.allclose(output_3, expected_output_3, atol=0.01), ( + f"Test case 3 failed: expected {expected_output_3}, got {output_3}" + ) + if __name__ == "__main__": test_rnn_forward() diff --git a/old_repo/Problems/55_2D_translation_matrix/solution.py b/old_repo/Problems/55_2D_translation_matrix/solution.py index 20103f1a..3678ec9f 100644 --- a/old_repo/Problems/55_2D_translation_matrix/solution.py +++ b/old_repo/Problems/55_2D_translation_matrix/solution.py @@ -1,48 +1,53 @@ import numpy as np -def translate_object(points: list[list[float]], tx: float, ty: float) -> list[list[float]]: + +def translate_object( + points: list[list[float]], tx: float, ty: float +) -> list[list[float]]: """ Translate a set of 2D points by tx and ty. - + :param points: List of [x, y] coordinates representing the object :param tx: Translation in x-direction :param ty: Translation in y-direction :return: List of translated [x, y] coordinates """ - + # Translation matrix - translation_matrix = np.array([ - [1, 0, tx], - [0, 1, ty], - [0, 0, 1] - ]) - + translation_matrix = np.array([[1, 0, tx], [0, 1, ty], [0, 0, 1]]) + # Convert points to homogeneous coordinates homogeneous_points = np.hstack([np.array(points), np.ones((len(points), 1))]) - + # Translation translated_points = np.dot(homogeneous_points, translation_matrix.T) - + # Convert back to 2D coordinates and to list return translated_points[:, :2].tolist() + def test_translate_object() -> None: # Test cases for translate_object function - + # Test case 1 (triangle) triangle = [[0, 0], [1, 0], [0.5, 1]] tx, ty = 2, 3 translated_triangle = translate_object(triangle, tx, ty) expected_result = [[2.0, 3.0], [3.0, 3.0], [2.5, 4.0]] - assert translated_triangle == expected_result, f"Expected {expected_result}, but got {translated_triangle}" - + assert translated_triangle == expected_result, ( + f"Expected {expected_result}, but got {translated_triangle}" + ) + # Test case 2 (square) square = [[0, 0], [1, 0], [1, 1], [0, 1]] tx, ty = -1, 2 translated_square = translate_object(square, tx, ty) expected_result = [[-1.0, 2.0], [0.0, 2.0], [0.0, 3.0], [-1.0, 3.0]] - assert translated_square == expected_result, f"Expected {expected_result}, but got {translated_square}" + assert translated_square == expected_result, ( + f"Expected {expected_result}, but got {translated_square}" + ) + if __name__ == "__main__": test_translate_object() - print("All tests passed.") \ No newline at end of file + print("All tests passed.") diff --git a/old_repo/Problems/57_gauss_seidel/solution.py b/old_repo/Problems/57_gauss_seidel/solution.py index 7299211e..b11f8a14 100644 --- a/old_repo/Problems/57_gauss_seidel/solution.py +++ b/old_repo/Problems/57_gauss_seidel/solution.py @@ -1,57 +1,61 @@ import numpy as np -def gauss_seidel_it(A:np.array, b:np.array, x: np.array) -> np.array: - + +def gauss_seidel_it(A: np.array, b: np.array, x: np.array) -> np.array: rows, cols = A.shape - + for i in range(rows): x_new = b[i] for j in range(cols): if i != j: - x_new -= A[i,j] * x[j] - x[i] = x_new/A[i,i] - + x_new -= A[i, j] * x[j] + x[i] = x_new / A[i, i] + return x -def gauss_seidel(A:np.array, b:np.array, n: int, x_ini: np.array=None) -> np.array: - + +def gauss_seidel(A: np.array, b: np.array, n: int, x_ini: np.array = None) -> np.array: x = x_ini or np.zeros_like(b) - + for _ in range(n): - x = gauss_seidel_it(A,b,x) - + x = gauss_seidel_it(A, b, x) + return x + def test_gauss_seidel(): - # Test case 1: basic test - A_1 = np.array([[4, 1, 2],[3, 5, 1],[1, 1, 3]], dtype=float) - b_1 = np.array([4,7,3], dtype=float) + A_1 = np.array([[4, 1, 2], [3, 5, 1], [1, 1, 3]], dtype=float) + b_1 = np.array([4, 7, 3], dtype=float) n = 5 expected_1 = np.array([0.5008, 0.99968, 0.49984]) output_1 = gauss_seidel(A_1, b_1, n) - assert np.allclose(output_1, expected_1, atol=0.01), f"Test case 1 failed: expected {expected_1}, got {output_1}" + assert np.allclose(output_1, expected_1, atol=0.01), ( + f"Test case 1 failed: expected {expected_1}, got {output_1}" + ) # Test case 2: testing a zero pivot - A_2 = np.array([[4, -1, 0, 1], - [-1, 4, -1, 0], - [0, -1, 4, -1], - [1, 0, -1, 4]], dtype=float) + A_2 = np.array( + [[4, -1, 0, 1], [-1, 4, -1, 0], [0, -1, 4, -1], [1, 0, -1, 4]], dtype=float + ) b_2 = np.array([15, 10, 10, 15], dtype=float) n = 1 expected_2 = np.array([3.75, 3.4375, 3.359375, 3.65234375]) output_2 = gauss_seidel(A_2, b_2, n) - assert np.allclose(output_2, expected_2, atol=0.01), f"Test case 2 failed: expected {expected_2}, got {output_2}" + assert np.allclose(output_2, expected_2, atol=0.01), ( + f"Test case 2 failed: expected {expected_2}, got {output_2}" + ) # Test case 3: Multiple feature inputs - A_3 = np.array([[10, -1, 2], - [-1, 11, -1], - [2, -1, 10]], dtype=float) + A_3 = np.array([[10, -1, 2], [-1, 11, -1], [2, -1, 10]], dtype=float) b_3 = np.array([6, 25, -11], dtype=float) n = 100 expected_3 = np.array([1.04326923, 2.26923077, -1.08173077]) output_3 = gauss_seidel(A_3, b_3, n) - assert np.allclose(output_3, expected_3, atol=0.01), f"Test case 3 failed: expected {expected_3}, got {output_3}" + assert np.allclose(output_3, expected_3, atol=0.01), ( + f"Test case 3 failed: expected {expected_3}, got {output_3}" + ) + if __name__ == "__main__": test_gauss_seidel() diff --git a/old_repo/Problems/58_gaussian_elimination_partial_pivoting/solution.py b/old_repo/Problems/58_gaussian_elimination_partial_pivoting/solution.py index a233e944..3e055bf5 100644 --- a/old_repo/Problems/58_gaussian_elimination_partial_pivoting/solution.py +++ b/old_repo/Problems/58_gaussian_elimination_partial_pivoting/solution.py @@ -1,76 +1,97 @@ import numpy as np + def partial_pivoting(A_aug: np.array, row_num: int, col_num: int) -> np.array: - rows, cols = A_aug.shape - + max_row = row_num - max_val = abs(A_aug[row_num,col_num]) - + max_val = abs(A_aug[row_num, col_num]) + for i in range(row_num, rows): current_val = abs(A_aug[i, col_num]) if current_val > max_val: max_val = current_val max_row = i - + if max_row != row_num: A_aug[[row_num, max_row]] = A_aug[[max_row, row_num]] - + return A_aug + def gaussian_elimination(A: np.array, b: np.array) -> np.array: - # get original matrix dimensions to avoid overwriting source later in augmented matrix rows, cols = A.shape - + # create augmented matrix - A_aug = np.hstack((A,b.reshape(-1,1))) - + A_aug = np.hstack((A, b.reshape(-1, 1))) + # Elimination # loop over rows - for i in range(rows-1): + for i in range(rows - 1): A_aug = partial_pivoting(A_aug, i, i) # apply elimination to all rows below the current row - for j in range(i+1, rows): - A_aug[j, i:] -= (A_aug[j,i] / A_aug[i,i]) * A_aug[i, i:] + for j in range(i + 1, rows): + A_aug[j, i:] -= (A_aug[j, i] / A_aug[i, i]) * A_aug[i, i:] x = np.zeros_like(b, dtype=float) - + # Backsubtitution - for i in range(rows-1,-1,-1): - x[i] = (A_aug[i,-1] - np.dot(A_aug[i,i+1:cols],x[i+1:]))/A_aug[i,i] - + for i in range(rows - 1, -1, -1): + x[i] = (A_aug[i, -1] - np.dot(A_aug[i, i + 1 : cols], x[i + 1 :])) / A_aug[i, i] + return x + def test_gaussian_elimination(): # Test case 1: basic test - A_1 = np.array([[2,8,4],[2,5,1],[4,10,-1]], dtype=float) - b_1 = np.array([2,5,1], dtype=float) - expected_1 = np.array([11., -4., 3.]) + A_1 = np.array([[2, 8, 4], [2, 5, 1], [4, 10, -1]], dtype=float) + b_1 = np.array([2, 5, 1], dtype=float) + expected_1 = np.array([11.0, -4.0, 3.0]) output_1 = gaussian_elimination(A_1, b_1) - assert np.allclose(output_1, expected_1, atol=0.01), f"Test case 1 failed: expected {expected_1}, got {output_1}" + assert np.allclose(output_1, expected_1, atol=0.01), ( + f"Test case 1 failed: expected {expected_1}, got {output_1}" + ) # Test case 2: testing a zero pivot - A_2 = np.array([ - [0, 2, 1, 0, 0, 0, 0], - [2, 6, 2, 1, 0, 0, 0], - [1, 2, 7, 2, 1, 0, 0], - [0, 1, 2, 8, 2, 1, 0], - [0, 0, 1, 2, 9, 2, 1], - [0, 0, 0, 1, 2, 10, 2], - [0, 0, 0, 0, 1, 2, 11] - ], dtype=float) + A_2 = np.array( + [ + [0, 2, 1, 0, 0, 0, 0], + [2, 6, 2, 1, 0, 0, 0], + [1, 2, 7, 2, 1, 0, 0], + [0, 1, 2, 8, 2, 1, 0], + [0, 0, 1, 2, 9, 2, 1], + [0, 0, 0, 1, 2, 10, 2], + [0, 0, 0, 0, 1, 2, 11], + ], + dtype=float, + ) b_2 = np.array([1, 2, 3, 4, 5, 6, 7], dtype=float) - expected_2 = np.array([-0.4894027, 0.36169985, 0.2766003, 0.25540569, 0.31898951, 0.40387497, 0.53393278]) + expected_2 = np.array( + [ + -0.4894027, + 0.36169985, + 0.2766003, + 0.25540569, + 0.31898951, + 0.40387497, + 0.53393278, + ] + ) output_2 = gaussian_elimination(A_2, b_2) - assert np.allclose(output_2, expected_2, atol=0.01), f"Test case 2 failed: expected {expected_2}, got {output_2}" + assert np.allclose(output_2, expected_2, atol=0.01), ( + f"Test case 2 failed: expected {expected_2}, got {output_2}" + ) # Test case 3: Multiple feature inputs A_3 = np.array([[2, 1, -1], [-3, -1, 2], [-2, 1, 2]], dtype=float) b_3 = np.array([8, -11, -3], dtype=float) - expected_3 = np.array([2., 3., -1.]) + expected_3 = np.array([2.0, 3.0, -1.0]) output_3 = gaussian_elimination(A_3, b_3) - assert np.allclose(output_3, expected_3, atol=0.01), f"Test case 3 failed: expected {expected_3}, got {output_3}" + assert np.allclose(output_3, expected_3, atol=0.01), ( + f"Test case 3 failed: expected {expected_3}, got {output_3}" + ) + if __name__ == "__main__": test_gaussian_elimination() diff --git a/old_repo/Problems/5_scalar_multiplication_of_a_matrix/solution.py b/old_repo/Problems/5_scalar_multiplication_of_a_matrix/solution.py index efb4b4ba..64bdba66 100644 --- a/old_repo/Problems/5_scalar_multiplication_of_a_matrix/solution.py +++ b/old_repo/Problems/5_scalar_multiplication_of_a_matrix/solution.py @@ -5,6 +5,7 @@ def scalar_multiply( # Multiply each element by the scalar return [[element * scalar for element in row] for row in matrix] + def test_scalar_multiply() -> None: # Test cases for scalar_multiply function @@ -18,6 +19,7 @@ def test_scalar_multiply() -> None: scalar = -1 assert scalar_multiply(matrix, scalar) == [[0, 1], [-1, 0]] + if __name__ == "__main__": test_scalar_multiply() - print("All scalar_multiply tests passed.") \ No newline at end of file + print("All scalar_multiply tests passed.") diff --git a/old_repo/Problems/60_TF-IDF/solution.py b/old_repo/Problems/60_TF-IDF/solution.py index 497f78ce..789c5a1f 100644 --- a/old_repo/Problems/60_TF-IDF/solution.py +++ b/old_repo/Problems/60_TF-IDF/solution.py @@ -1,10 +1,11 @@ import numpy as np + def compute_tf_idf(corpus, query): """ Compute TF-IDF scores for a query against a corpus of documents using only NumPy. The output TF-IDF scores retain five decimal places. - + :param corpus: List of documents, where each document is a list of words :param query: List of words in the query :return: List of lists containing TF-IDF scores for the query words in each document, @@ -13,10 +14,10 @@ def compute_tf_idf(corpus, query): # Build the vocabulary from the corpus and include query terms vocab = sorted(set(word for document in corpus for word in document).union(query)) word_to_index = {word: idx for idx, word in enumerate(vocab)} - + # Initialize term-frequency (TF) matrix tf = np.zeros((len(corpus), len(vocab))) - + # Compute term frequencies for doc_idx, document in enumerate(corpus): for word in document: @@ -24,69 +25,76 @@ def compute_tf_idf(corpus, query): tf[doc_idx, word_idx] += 1 # Normalize TF values by the document length tf[doc_idx, :] /= len(document) - + # Compute document frequency (DF) for each term df = np.count_nonzero(tf > 0, axis=0) - + # Compute inverse document frequency (IDF) with smoothing num_docs = len(corpus) - idf = np.log((num_docs + 1) / (df + 1)) + 1 # Add 1 to numerator and denominator to prevent division by zero - + idf = ( + np.log((num_docs + 1) / (df + 1)) + 1 + ) # Add 1 to numerator and denominator to prevent division by zero + # Compute TF-IDF matrix tf_idf = tf * idf - + # Extract TF-IDF scores for the query words query_indices = [word_to_index[word] for word in query] tf_idf_scores = tf_idf[:, query_indices] - + # Round the TF-IDF scores to five decimal places tf_idf_scores = np.round(tf_idf_scores, 5) - + # Convert the TF-IDF scores to a list of lists tf_idf_scores_list = tf_idf_scores.tolist() - + return tf_idf_scores_list + def test_tf_idf(): # Test case 1: Simple corpus with single-word query corpus_1 = [ ["the", "cat", "sat", "on", "the", "mat"], ["the", "dog", "chased", "the", "cat"], - ["the", "bird", "flew", "over", "the", "mat"] + ["the", "bird", "flew", "over", "the", "mat"], ] query_1 = ["cat"] expected_output_1 = [[0.21461], [0.25754], [0.0]] output_1 = compute_tf_idf(corpus_1, query_1) - assert np.allclose(output_1, expected_output_1, atol=1e-5), \ + assert np.allclose(output_1, expected_output_1, atol=1e-5), ( f"Test case 1 failed: expected {expected_output_1}, got {output_1}" - + ) + # Test case 2: Simple corpus with multi-word query corpus_2 = corpus_1 # Reuse the corpus from test case 1 query_2 = ["cat", "mat"] expected_output_2 = [[0.21461, 0.21461], [0.25754, 0.0], [0.0, 0.21461]] output_2 = compute_tf_idf(corpus_2, query_2) - assert np.allclose(output_2, expected_output_2, atol=1e-5), \ + assert np.allclose(output_2, expected_output_2, atol=1e-5), ( f"Test case 2 failed: expected {expected_output_2}, got {output_2}" - + ) + # Test case 3: Larger corpus with multi-word query corpus_3 = [ ["this", "is", "a", "sample"], ["this", "is", "another", "example"], ["yet", "another", "sample", "document"], - ["one", "more", "document", "for", "testing"] + ["one", "more", "document", "for", "testing"], ] query_3 = ["sample", "document", "test"] expected_output_3 = [ [0.37771, 0.0, 0.0], [0.0, 0.0, 0.0], [0.37771, 0.37771, 0.0], - [0.0, 0.30217, 0.0] + [0.0, 0.30217, 0.0], ] output_3 = compute_tf_idf(corpus_3, query_3) - assert np.allclose(output_3, expected_output_3, atol=1e-5), \ + assert np.allclose(output_3, expected_output_3, atol=1e-5), ( f"Test case 3 failed: expected {expected_output_3}, got {output_3}" - + ) + print("All TF-IDF tests passed.") + if __name__ == "__main__": test_tf_idf() diff --git a/old_repo/Problems/61_f_score/solution.py b/old_repo/Problems/61_f_score/solution.py index 030b0b08..931afec7 100644 --- a/old_repo/Problems/61_f_score/solution.py +++ b/old_repo/Problems/61_f_score/solution.py @@ -1,5 +1,6 @@ import numpy as np + def f_score(y_true, y_pred, beta): tp = np.sum((y_true == 1) & (y_pred == 1)) fn = np.sum((y_true == 1) & (y_pred == 0)) @@ -14,9 +15,10 @@ def f_score(y_true, y_pred, beta): if div == 0 or op == 0: return 0 - score = op/div * (1 + (beta ** 2)) + score = op / div * (1 + (beta**2)) return round(score, 3) + def test_f_score(): # Test case 1 y_true = np.array([1, 0, 1, 1, 0, 1]) @@ -74,6 +76,7 @@ def test_f_score(): expected_output = 0.667 assert f_score(y_true, y_pred, beta) == expected_output, "Test case 8 failed" + if __name__ == "__main__": test_f_score() print("All F-score tests passed.") diff --git a/old_repo/Problems/63_conjugate_gradient/solution.py b/old_repo/Problems/63_conjugate_gradient/solution.py index ee60ffad..656d68c6 100644 --- a/old_repo/Problems/63_conjugate_gradient/solution.py +++ b/old_repo/Problems/63_conjugate_gradient/solution.py @@ -1,22 +1,23 @@ import numpy as np -def conjugate_gradient(A: np.array, b: np.array, n: int, x0: np.array=None, tol=1e-8) -> np.array: - + +def conjugate_gradient( + A: np.array, b: np.array, n: int, x0: np.array = None, tol=1e-8 +) -> np.array: # calculate initial residual vector x = np.zeros_like(b) - r = residual(A, b, x) # residual vector + r = residual(A, b, x) # residual vector rPlus1 = r - p = r # search direction vector + p = r # search direction vector for i in range(n): - # line search step value - this minimizes the error along the current search direction alp = alpha(A, r, p) # new x and r based on current p (the search direction vector) x = x + alp * p - rPlus1 = r - alp * (A@p) - + rPlus1 = r - alp * (A @ p) + # calculate beta - this ensures that all vectors are A-orthogonal to each other bet = beta(r, rPlus1) @@ -28,64 +29,72 @@ def conjugate_gradient(A: np.array, b: np.array, n: int, x0: np.array=None, tol= r = rPlus1 # break if less than tolerance - if np.linalg.norm(residual(A,b,x)) < tol: + if np.linalg.norm(residual(A, b, x)) < tol: break return x + def residual(A: np.array, b: np.array, x: np.array) -> np.array: # calculate linear system residuals return b - A @ x -def alpha(A: np.array, r: np.array, p: np.array) -> float: +def alpha(A: np.array, r: np.array, p: np.array) -> float: # calculate step size alpha_num = np.dot(r, r) alpha_den = np.dot(p @ A, p) - return alpha_num/alpha_den + return alpha_num / alpha_den + def beta(r: np.array, r_plus1: np.array) -> float: - # calculate direction scaling beta_num = np.dot(r_plus1, r_plus1) beta_den = np.dot(r, r) - return beta_num/beta_den + return beta_num / beta_den -def test_conjugate_gradient() -> None: - A_1 = A_1 = np.array([[4, 1], - [1, 3]]) +def test_conjugate_gradient() -> None: + A_1 = A_1 = np.array([[4, 1], [1, 3]]) b_1 = np.array([1, 2]) n = 5 expected_1 = np.array([0.09090909, 0.63636364]) output_1 = conjugate_gradient(A_1, b_1, n) - assert np.allclose(output_1, expected_1, atol=0.01), f"Test case 1 failed: expected {expected_1}, got {output_1}" + assert np.allclose(output_1, expected_1, atol=0.01), ( + f"Test case 1 failed: expected {expected_1}, got {output_1}" + ) - A_2 = np.array([[4, 1, 2], - [1, 3, 0], - [2, 0, 5]]) + A_2 = np.array([[4, 1, 2], [1, 3, 0], [2, 0, 5]]) b_2 = np.array([7, 8, 5]) n = 1 expected_2 = np.array([1.2627451, 1.44313725, 0.90196078]) output_2 = conjugate_gradient(A_2, b_2, n) - assert np.allclose(output_2, expected_2, atol=0.01), f"Test case 2 failed: expected {expected_2}, got {output_2}" + assert np.allclose(output_2, expected_2, atol=0.01), ( + f"Test case 2 failed: expected {expected_2}, got {output_2}" + ) # 5x5 positive definite - A_3 = np.array([[6, 2, 1, 1, 0], - [2, 5, 2, 1, 1], - [1, 2, 6, 1, 2], - [1, 1, 1, 7, 1], - [0, 1, 2, 1, 8]]) + A_3 = np.array( + [ + [6, 2, 1, 1, 0], + [2, 5, 2, 1, 1], + [1, 2, 6, 1, 2], + [1, 1, 1, 7, 1], + [0, 1, 2, 1, 8], + ] + ) b_3 = np.array([1, 2, 3, 4, 5]) n = 100 expected_3 = np.array([0.01666667, 0.11666667, 0.21666667, 0.45, 0.5]) output_3 = conjugate_gradient(A_3, b_3, n) - assert np.allclose(output_3, expected_3, atol=0.01), f"Test case 3 failed: expected {expected_3}, got {output_3}" + assert np.allclose(output_3, expected_3, atol=0.01), ( + f"Test case 3 failed: expected {expected_3}, got {output_3}" + ) if __name__ == "__main__": test_conjugate_gradient() - print("All Conjugate Gradient tests passed.") \ No newline at end of file + print("All Conjugate Gradient tests passed.") diff --git a/old_repo/Problems/64_gini_impurity/solution.py b/old_repo/Problems/64_gini_impurity/solution.py index 1bac5ade..1bc76bfe 100644 --- a/old_repo/Problems/64_gini_impurity/solution.py +++ b/old_repo/Problems/64_gini_impurity/solution.py @@ -1,29 +1,29 @@ import numpy as np -def gini_impurity(y: list[int]) -> float: +def gini_impurity(y: list[int]) -> float: classes = set(y) n = len(y) gini_impurity = 0 for cls in classes: - gini_impurity += (y.count(cls)/n)**2 + gini_impurity += (y.count(cls) / n) ** 2 - return np.round(1-gini_impurity,3) + return np.round(1 - gini_impurity, 3) def test_gini_impurity() -> None: - - classes_1 = [0,0,0,0,1,1,1,1] + classes_1 = [0, 0, 0, 0, 1, 1, 1, 1] assert gini_impurity(classes_1) == 0.5 - classes_2 = [0,0,0,0,0,1] + classes_2 = [0, 0, 0, 0, 0, 1] assert gini_impurity(classes_2) == 0.278 - classes_3 = [0,1,2,2,2,1,2] + classes_3 = [0, 1, 2, 2, 2, 1, 2] assert gini_impurity(classes_3) == 0.571 + if __name__ == "__main__": test_gini_impurity() print("All Gini Impurity tests passed.") diff --git a/old_repo/Problems/65_compressed_row_sparse_matrix/solution.py b/old_repo/Problems/65_compressed_row_sparse_matrix/solution.py index 45624436..f2cefbfe 100644 --- a/old_repo/Problems/65_compressed_row_sparse_matrix/solution.py +++ b/old_repo/Problems/65_compressed_row_sparse_matrix/solution.py @@ -1,8 +1,6 @@ -import numpy as np -from scipy.sparse import csr_matrix - -def compressed_row_sparse_matrix(dense_matrix: list[list[float]]) -> tuple[list[float], list[int], list[int]]: - +def compressed_row_sparse_matrix( + dense_matrix: list[list[float]], +) -> tuple[list[float], list[int], list[int]]: vals = [] col_idx = [] row_ptr = [0] @@ -13,35 +11,26 @@ def compressed_row_sparse_matrix(dense_matrix: list[list[float]]) -> tuple[list[ continue vals.append(val) col_idx.append(j) - row_ptr.append(len(vals)) + row_ptr.append(len(vals)) return vals, col_idx, row_ptr - -def test_compressed_row(): +def test_compressed_row(): # Test case 1 - dense_matrix = [ - [0, 0, 0], - [0, 0, 0], - [0, 0, 0] - ] + dense_matrix = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] vals, col_idx, row_ptr = compressed_row_sparse_matrix(dense_matrix) - + assert vals == [], "Test case 1 failed: vals should be an empty list" assert col_idx == [], "Test case 1 failed: col_idx should be an empty list" assert row_ptr == [0, 0, 0, 0], "Test case 1 failed: row_ptr should be [0, 0, 0, 0]" # Test case 2 - dense_matrix = [ - [0, 0, 0], - [1, 2, 0], - [0, 3, 4] - ] + dense_matrix = [[0, 0, 0], [1, 2, 0], [0, 3, 4]] vals, col_idx, row_ptr = compressed_row_sparse_matrix(dense_matrix) - + assert vals == [1, 2, 3, 4], "Test case 2 failed: vals should be [1, 2, 3, 4]" assert col_idx == [0, 1, 1, 2], "Test case 2 failed: col_idx should be [0, 1, 1, 2]" assert row_ptr == [0, 0, 2, 4], "Test case 2 failed: row_ptr should be [0, 0, 2, 4]" @@ -52,14 +41,21 @@ def test_compressed_row(): [0, 4, 0, 0, 0], # One non-zero element [5, 0, 0, 6, 0], # Two non-zero elements [0, 0, 0, 0, 0], # All zeros - [0, 7, 0, 0, 8] # Two non-zero elements + [0, 7, 0, 0, 8], # Two non-zero elements ] vals, col_idx, row_ptr = compressed_row_sparse_matrix(dense_matrix) - assert vals == [3, 4, 5, 6, 7, 8], "Test case failed: vals should be [3, 4, 5, 6, 7, 8]" - assert col_idx == [2, 1, 0, 3, 1, 4], "Test case failed: col_idx should be [2, 1, 0, 3, 1, 4]" - assert row_ptr == [0, 1, 2, 4, 4, 6], "Test case failed: row_ptr should be [0, 1, 2, 4, 4, 6]" + assert vals == [3, 4, 5, 6, 7, 8], ( + "Test case failed: vals should be [3, 4, 5, 6, 7, 8]" + ) + assert col_idx == [2, 1, 0, 3, 1, 4], ( + "Test case failed: col_idx should be [2, 1, 0, 3, 1, 4]" + ) + assert row_ptr == [0, 1, 2, 4, 4, 6], ( + "Test case failed: row_ptr should be [0, 1, 2, 4, 4, 6]" + ) + if __name__ == "__main__": test_compressed_row() diff --git a/old_repo/Problems/66_orthogonal_projection/solution.py b/old_repo/Problems/66_orthogonal_projection/solution.py index 76913bf5..e15bc03a 100644 --- a/old_repo/Problems/66_orthogonal_projection/solution.py +++ b/old_repo/Problems/66_orthogonal_projection/solution.py @@ -1,45 +1,51 @@ -def dot(v1:list[float], v2:list[float]) -> float: - +def dot(v1: list[float], v2: list[float]) -> float: if len(v1) != len(v2): raise Exception("Vectors are not of the same dimensions.") - - return sum([ax1*ax2 for ax1,ax2 in zip(v1,v2)]) -def scalar_mult(scalar:float, v:list[float]) -> list[float]: + return sum([ax1 * ax2 for ax1, ax2 in zip(v1, v2)]) + +def scalar_mult(scalar: float, v: list[float]) -> list[float]: + return [scalar * ax for ax in v] - return [scalar*ax for ax in v] -def orthogonal_projection(v:list[float], L: list[float]) -> list[list[float]]: - +def orthogonal_projection(v: list[float], L: list[float]) -> list[list[float]]: # calculate the orthogonal projection of v onto L # calculate the unit vector of L - L_mag = sum([ax**2 for ax in L])**0.5 - u = [ax/L_mag for ax in L] + L_mag = sum([ax**2 for ax in L]) ** 0.5 + u = [ax / L_mag for ax in L] # calculate orthogonal projection proj_v = scalar_mult(dot(v, u), u) return proj_v + def test_orthogonal_projection() -> None: # Test case 1: 2D vectors v1 = [3, 4] L1 = [1, 0] expected_proj1 = [3, 0] # Projection of v1 onto L1 should lie along the x-axis - assert orthogonal_projection(v1, L1) == expected_proj1, f"Test case 1 failed: {orthogonal_projection(v1, L1)} != {expected_proj1}" + assert orthogonal_projection(v1, L1) == expected_proj1, ( + f"Test case 1 failed: {orthogonal_projection(v1, L1)} != {expected_proj1}" + ) # Test case 2: 3D vectors v2 = [1, 2, 3] L2 = [0, 0, 1] expected_proj2 = [0, 0, 3] # Projection of v2 onto L2 should be along the z-axis - assert orthogonal_projection(v2, L2) == expected_proj2, f"Test case 2 failed: {orthogonal_projection(v2, L2)} != {expected_proj2}" + assert orthogonal_projection(v2, L2) == expected_proj2, ( + f"Test case 2 failed: {orthogonal_projection(v2, L2)} != {expected_proj2}" + ) # Test case 3: Arbitrary 3D vectors v3 = [5, 6, 7] L3 = [2, 0, 0] # Projection should align with the x-axis expected_proj3 = [5, 0, 0] - assert orthogonal_projection(v3, L3) == expected_proj3, f"Test case 3 failed: {orthogonal_projection(v3, L3)} != {expected_proj3}" + assert orthogonal_projection(v3, L3) == expected_proj3, ( + f"Test case 3 failed: {orthogonal_projection(v3, L3)} != {expected_proj3}" + ) + if __name__ == "__main__": test_orthogonal_projection() diff --git a/old_repo/Problems/67_compressed_column_sparse_matrix/solution.py b/old_repo/Problems/67_compressed_column_sparse_matrix/solution.py index e6fa6eab..805ffacb 100644 --- a/old_repo/Problems/67_compressed_column_sparse_matrix/solution.py +++ b/old_repo/Problems/67_compressed_column_sparse_matrix/solution.py @@ -1,8 +1,6 @@ -import numpy as np -from scipy.sparse import csc_matrix - -def compressed_col_sparse_matrix(dense_matrix: list[list[float]]) -> tuple[list[float], list[int], list[int]]: - +def compressed_col_sparse_matrix( + dense_matrix: list[list[float]], +) -> tuple[list[float], list[int], list[int]]: vals = [] row_idx = [] col_ptr = [0] @@ -16,35 +14,26 @@ def compressed_col_sparse_matrix(dense_matrix: list[list[float]]) -> tuple[list[ continue vals.append(val) row_idx.append(j) - col_ptr.append(len(vals)) + col_ptr.append(len(vals)) return vals, row_idx, col_ptr - -def test_compressed_col(): +def test_compressed_col(): # Test case 1 - dense_matrix = [ - [0, 0, 0], - [0, 0, 0], - [0, 0, 0] - ] + dense_matrix = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] vals, row_idx, col_ptr = compressed_col_sparse_matrix(dense_matrix) - + assert vals == [], "Test case 1 failed: vals should be an empty list" assert row_idx == [], "Test case 1 failed: row_idx should be an empty list" assert col_ptr == [0, 0, 0, 0], "Test case 1 failed: col_ptr should be [0, 0, 0, 0]" # Test case 2 - dense_matrix = [ - [0, 0, 0], - [1, 2, 0], - [0, 3, 4] - ] + dense_matrix = [[0, 0, 0], [1, 2, 0], [0, 3, 4]] vals, row_idx, col_ptr = compressed_col_sparse_matrix(dense_matrix) - + assert vals == [1, 2, 3, 4], "Test case 2 failed: vals should be [1, 2, 3, 4]" assert row_idx == [1, 1, 2, 2], "Test case 2 failed: row_idx should be [1, 1, 2, 2]" assert col_ptr == [0, 1, 3, 4], "Test case 2 failed: col_ptr should be [0, 1, 3, 4]" @@ -52,17 +41,24 @@ def test_compressed_col(): # Test case 3 dense_matrix = [ [0, 0, 3, 0, 0], - [0, 4, 0, 0, 0], + [0, 4, 0, 0, 0], [5, 0, 0, 6, 0], - [0, 0, 0, 0, 0], - [0, 7, 0, 0, 8] + [0, 0, 0, 0, 0], + [0, 7, 0, 0, 8], ] vals, row_idx, col_ptr = compressed_col_sparse_matrix(dense_matrix) - assert vals == [5, 4, 7, 3, 6, 8], "Test case failed: vals should be [5, 4, 7, 3, 6, 8]" - assert row_idx == [2, 1, 4, 0, 2, 4], "Test case failed: row_idx should be [2, 1, 4, 0, 2, 4]" - assert col_ptr == [0, 1, 3, 4, 5, 6], "Test case failed: col_ptr should be [0, 1, 3, 4, 5, 6]" + assert vals == [5, 4, 7, 3, 6, 8], ( + "Test case failed: vals should be [5, 4, 7, 3, 6, 8]" + ) + assert row_idx == [2, 1, 4, 0, 2, 4], ( + "Test case failed: row_idx should be [2, 1, 4, 0, 2, 4]" + ) + assert col_ptr == [0, 1, 3, 4, 5, 6], ( + "Test case failed: col_ptr should be [0, 1, 3, 4, 5, 6]" + ) + if __name__ == "__main__": test_compressed_row() diff --git a/old_repo/Problems/69_r-squared/solution.py b/old_repo/Problems/69_r-squared/solution.py index 199c73a1..563f2c3f 100644 --- a/old_repo/Problems/69_r-squared/solution.py +++ b/old_repo/Problems/69_r-squared/solution.py @@ -1,25 +1,26 @@ import numpy as np + def r_squared(y_true, y_pred): """ Calculate the R-squared (R²) coefficient of determination. - + Args: y_true (numpy.ndarray): Array of true values y_pred (numpy.ndarray): Array of predicted values - + Returns: float: R-squared value rounded to 3 decimal places """ if np.array_equal(y_true, y_pred): return 1.0 - + # Calculate mean of true values y_mean = np.mean(y_true) - + # Calculate Sum of Squared Residuals (SSR) ssr = np.sum((y_true - y_pred) ** 2) - + # Calculate Total Sum of Squares (SST) sst = np.sum((y_true - y_mean) ** 2) @@ -32,6 +33,7 @@ def r_squared(y_true, y_pred): except ZeroDivisionError: return 0.0 + def test_r_squared(): # Test case 1: Perfect prediction y_true = np.array([1, 2, 3, 4, 5]) @@ -49,7 +51,7 @@ def test_r_squared(): y_true = np.array([1, 2, 3, 4, 5]) y_pred = np.array([2, 1, 4, 3, 5]) expected_output = 0.600 - output = r_squared(y_true, y_pred) + r_squared(y_true, y_pred) assert r_squared(y_true, y_pred) == expected_output, "Test case 3 failed" # Test case 4: Worst possible prediction (predicting mean) @@ -57,7 +59,7 @@ def test_r_squared(): y_pred = np.array([3, 3, 3, 3, 3]) expected_output = 0.000 assert r_squared(y_true, y_pred) == expected_output, "Test case 4 failed" - + # Test case 5 y_true = np.array([3, 3, 3, 3, 3]) y_pred = np.array([1, 2, 3, 4, 5]) @@ -70,18 +72,19 @@ def test_r_squared(): expected_output = -3.000 assert r_squared(y_true, y_pred) == expected_output, "Test case 6 failed" - # Test case 7: All zeros + # Test case 7: All zeros y_true = np.array([0, 0, 0, 0, 0]) y_pred = np.array([0, 0, 0, 0, 0]) expected_output = 1.000 assert r_squared(y_true, y_pred) == expected_output, "Test case 7 failed" - + # Test case 8 : output = -inf y_true = np.array([-2, -2, -2]) y_pred = np.array([-2, -2, -2 + 1e-8]) expected_output = 0.000 assert r_squared(y_true, y_pred) == expected_output, "Test case 8 failed" + if __name__ == "__main__": test_r_squared() - print("All R-squared tests passed.") \ No newline at end of file + print("All R-squared tests passed.") diff --git a/old_repo/Problems/6_calculate_eigenvalues/solution.py b/old_repo/Problems/6_calculate_eigenvalues/solution.py index b661fb1f..951cfb7d 100644 --- a/old_repo/Problems/6_calculate_eigenvalues/solution.py +++ b/old_repo/Problems/6_calculate_eigenvalues/solution.py @@ -12,6 +12,7 @@ def calculate_eigenvalues( lambda_2 = (trace - discriminant**0.5) / 2 return [lambda_1, lambda_2] + def test_calculate_eigenvalues() -> None: # Test cases for calculate_eigenvalues function @@ -23,6 +24,7 @@ def test_calculate_eigenvalues() -> None: matrix = [[4, -2], [1, 1]] assert calculate_eigenvalues(matrix) == [3.0, 2.0] + if __name__ == "__main__": test_calculate_eigenvalues() - print("All calculate_eigenvalues tests passed.") \ No newline at end of file + print("All calculate_eigenvalues tests passed.") diff --git a/old_repo/Problems/70_image_brightness_calculator/solution.py b/old_repo/Problems/70_image_brightness_calculator/solution.py index ef1c4ce8..3f624d95 100644 --- a/old_repo/Problems/70_image_brightness_calculator/solution.py +++ b/old_repo/Problems/70_image_brightness_calculator/solution.py @@ -4,9 +4,9 @@ def calculate_brightness( # Check if image is empty or has no columns if not img or not img[0]: return -1 - + rows, cols = len(img), len(img[0]) - + # Check if all rows have same length and values are valid for row in img: if len(row) != cols: @@ -14,7 +14,7 @@ def calculate_brightness( for pixel in row: if not 0 <= pixel <= 255: return -1 - + # Calculate average brightness total = sum(sum(row) for row in img) return round(total / (rows * cols), 2) @@ -23,18 +23,19 @@ def calculate_brightness( def test_calculate_brightness() -> None: # Test empty image assert calculate_brightness([]) == -1 - + # Test invalid dimensions assert calculate_brightness([[100, 200], [150]]) == -1 - + # Test invalid pixel values assert calculate_brightness([[100, 300]]) == -1 assert calculate_brightness([[100, -1]]) == -1 - + # Test valid cases assert calculate_brightness([[128]]) == 128.0 assert calculate_brightness([[100, 200], [50, 150]]) == 125.0 - + + if __name__ == "__main__": test_calculate_brightness() - print("All tests passed.") \ No newline at end of file + print("All tests passed.") diff --git a/old_repo/Problems/71_Room_Mean_Square_Error/solution.py b/old_repo/Problems/71_Room_Mean_Square_Error/solution.py index 2e7d2ab2..b8e6482f 100644 --- a/old_repo/Problems/71_Room_Mean_Square_Error/solution.py +++ b/old_repo/Problems/71_Room_Mean_Square_Error/solution.py @@ -1,31 +1,34 @@ import numpy as np -def rmse(y_true,y_pred): + +def rmse(y_true, y_pred): if y_true.shape != y_pred.shape: raise ValueError("Arrays must have the same shape") if y_true.size == 0: raise ValueError("Arrays cannot be empty") - - return round(np.sqrt(np.mean((y_true - y_pred) ** 2)),3) + + return round(np.sqrt(np.mean((y_true - y_pred) ** 2)), 3) + + def test_rmse(): -# Test Case 1: Normal Case + # Test Case 1: Normal Case y_true1 = np.array([3, -0.5, 2, 7]) y_pred1 = np.array([2.5, 0.0, 2, 8]) expected1 = 0.612 assert abs(rmse(y_true1, y_pred1)) == expected1, "Test Case Failed" -# Test Case 2: 2D Array + # Test Case 2: 2D Array y_true2 = np.array([[0.5, 1], [-1, 1], [7, -6]]) y_pred2 = np.array([[0, 2], [-1, 2], [8, -5]]) expected2 = 0.842 - assert rmse(y_true2, y_pred2)==expected2, "Test Case Failed" + assert rmse(y_true2, y_pred2) == expected2, "Test Case Failed" -# Test Case 3: Perfect predictions + # Test Case 3: Perfect predictions y_true3 = np.array([[1, 2], [3, 4]]) y_pred3 = np.array([[1, 2], [3, 4]]) assert rmse(y_true3, y_pred3) == 0.0, "Test Case Failed" -# Test Case 4: Different shapes + # Test Case 4: Different shapes y_true4 = np.array([[1, 2], [3, 4]]) y_pred4 = np.array([1, 2, 3, 4]) try: @@ -34,7 +37,7 @@ def test_rmse(): except ValueError: pass -# Test Case 5: Empty arrays + # Test Case 5: Empty arrays y_true5 = np.array([]) y_pred5 = np.array([]) try: @@ -43,6 +46,7 @@ def test_rmse(): except ValueError: pass + if __name__ == "__main__": test_rmse() print("All Test Cases Passed !") diff --git a/old_repo/Problems/73_Dice_Score/solution.py b/old_repo/Problems/73_Dice_Score/solution.py index 939e231a..a1f0c622 100644 --- a/old_repo/Problems/73_Dice_Score/solution.py +++ b/old_repo/Problems/73_Dice_Score/solution.py @@ -1,13 +1,14 @@ import numpy as np + def dice_score(y_true, y_pred): """ Calculate the Dice coefficient (also known as F1-score or Sørensen–Dice coefficient). - + Args: y_true (numpy.ndarray): Array of true values (ground truth) y_pred (numpy.ndarray): Array of predicted values - + Returns: float: Dice score value rounded to 3 decimal places """ @@ -15,65 +16,66 @@ def dice_score(y_true, y_pred): intersection = np.logical_and(y_true, y_pred).sum() true_sum = y_true.sum() pred_sum = y_pred.sum() - - # Handle edge cases + + # Handle edge cases if true_sum == 0 or pred_sum == 0: return 0.0 - + # Calculate Dice coefficient dice = (2.0 * intersection) / (true_sum + pred_sum) return round(float(dice), 3) + def test_dice_score(): # Test case 1: Perfect overlap y_true = np.array([1, 1, 0, 0]) y_pred = np.array([1, 1, 0, 0]) expected_output = 1.000 assert dice_score(y_true, y_pred) == expected_output, "Test case 1 failed" - + # Test case 2: No overlap y_true = np.array([1, 1, 0, 0]) y_pred = np.array([0, 0, 1, 1]) expected_output = 0.000 assert dice_score(y_true, y_pred) == expected_output, "Test case 2 failed" - + # Test case 3: Partial overlap y_true = np.array([1, 1, 0, 0]) y_pred = np.array([1, 0, 0, 0]) expected_output = 0.667 assert dice_score(y_true, y_pred) == expected_output, "Test case 3 failed" - + # Test case 4: All zeros y_true = np.array([0, 0, 0, 0]) y_pred = np.array([0, 0, 0, 0]) expected_output = 0.000 assert dice_score(y_true, y_pred) == expected_output, "Test case 4 failed" - + # Test case 5: All ones y_true = np.array([1, 1, 1, 1]) y_pred = np.array([1, 1, 1, 1]) expected_output = 1.000 assert dice_score(y_true, y_pred) == expected_output, "Test case 5 failed" - + # Test case 6: One empty, one full y_true = np.array([0, 0, 0, 0]) y_pred = np.array([1, 1, 1, 1]) expected_output = 0.000 assert dice_score(y_true, y_pred) == expected_output, "Test case 6 failed" - + # Test case 7: Single element arrays y_true = np.array([1]) y_pred = np.array([1]) expected_output = 1.000 assert dice_score(y_true, y_pred) == expected_output, "Test case 7 failed" - + # Test case 8: Different data types y_true = np.array([True, True, False, False]) y_pred = np.array([1, 1, 0, 0]) expected_output = 1.000 assert dice_score(y_true, y_pred) == expected_output, "Test case 8 failed" - + if __name__ == "__main__": test_dice_score() - print("All Dice score test cases passed.") \ No newline at end of file + print("All Dice score test cases passed.") diff --git a/old_repo/Problems/74_hdc_bundling_binding/solution.py b/old_repo/Problems/74_hdc_bundling_binding/solution.py index cb762b6f..06864589 100644 --- a/old_repo/Problems/74_hdc_bundling_binding/solution.py +++ b/old_repo/Problems/74_hdc_bundling_binding/solution.py @@ -1,24 +1,30 @@ import numpy as np + def create_hv(dim): return np.random.choice([-1, 1], dim) + def create_col_hvs(dim, seed): np.random.seed(seed) return create_hv(dim), create_hv(dim) + def bind(hv1, hv2): - return hv1*hv2 + return hv1 * hv2 + def bundle(hvs, dim): bundled = np.sum(list(hvs.values()), axis=0) return sign(bundled) + def sign(vector, threshold=0.01): return np.array([1 if v >= 0 else -1 for v in vector]) -def create_row_hv(row:dict[str,str], dim:int, random_seeds:dict[str,int]): - row_hvs = {col:bind(*create_col_hvs(dim, random_seeds[col])) for col in row.keys()} + +def create_row_hv(row: dict[str, str], dim: int, random_seeds: dict[str, int]): + row_hvs = {col: bind(*create_col_hvs(dim, random_seeds[col])) for col in row.keys()} return bundle(row_hvs, dim) @@ -30,26 +36,33 @@ def test_create_row_hv(): # Test case 1 dim = 5 hv = create_row_hv(row, dim, seed_dict) - result_hv = np.array([1,-1,1,1,1]) + result_hv = np.array([1, -1, 1, 1, 1]) assert len(hv) == dim, "Test case 1 failed: Incorrect dimension" - assert np.all(np.isin(hv, [-1, 1])), "Test case 1 failed: Non-bipolar values present" - assert np.array_equal(hv,result_hv) + assert np.all(np.isin(hv, [-1, 1])), ( + "Test case 1 failed: Non-bipolar values present" + ) + assert np.array_equal(hv, result_hv) # Test case 2 dim = 10 hv = create_row_hv(row, dim, seed_dict) - result_hv = np.array([1,-1,1,1,-1,-1,-1,-1,-1,-1]) + result_hv = np.array([1, -1, 1, 1, -1, -1, -1, -1, -1, -1]) assert len(hv) == dim, "Test case 2 failed: Incorrect dimension" - assert np.all(np.isin(hv, [-1, 1])), "Test case 2 failed: Non-bipolar values present" - assert np.array_equal(hv,result_hv) + assert np.all(np.isin(hv, [-1, 1])), ( + "Test case 2 failed: Non-bipolar values present" + ) + assert np.array_equal(hv, result_hv) # Test case 3 dim = 15 hv = create_row_hv(row, dim, seed_dict) - result_hv = np.array([1,1,-1,-1,1,1,1,1,-1,1,1,1,-1,-1,1]) + result_hv = np.array([1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1]) assert len(hv) == dim, "Test case 3 failed: Incorrect dimension" - assert np.all(np.isin(hv, [-1, 1])), "Test case 3 failed: Non-bipolar values present" - assert np.array_equal(hv,result_hv) + assert np.all(np.isin(hv, [-1, 1])), ( + "Test case 3 failed: Non-bipolar values present" + ) + assert np.array_equal(hv, result_hv) + if __name__ == "__main__": test_create_row_hv() diff --git a/old_repo/Problems/75_classification_performance_metrics/solution.py b/old_repo/Problems/75_classification_performance_metrics/solution.py index b8d1f47e..bf5d4b4d 100644 --- a/old_repo/Problems/75_classification_performance_metrics/solution.py +++ b/old_repo/Problems/75_classification_performance_metrics/solution.py @@ -1,42 +1,78 @@ from collections import Counter -def performance_metrics(actual: list[int],predicted: list[int]) -> tuple: - #Merge lists into one - data = list(zip(actual,predicted)) - #Count all occurrences + +def performance_metrics(actual: list[int], predicted: list[int]) -> tuple: + # Merge lists into one + data = list(zip(actual, predicted)) + # Count all occurrences counts = Counter(tuple(pair) for pair in data) - #Get metrics - TP, FN, FP, TN = counts[(1,1)],counts[(1,0)],counts[(0,1)],counts[(0,0)] - #Define confusin matrix - confusion_matrix = [[TP,FN],[FP,TN]] - #Get accuracy - accuracy = (TP+TN)/(TP+TN+FP+FN) - #Get precision - precision = TP/(TP+FP) - #Get recall - recall = TP/(TP + FN) - #Get F1 score - f1 = 2*precision*recall/(precision+recall) - #Get negative predictive value - negativePredictive = TN/(TN+FN) - #Get specificiy - specificity = TN/(TN+FP) - #Return - return confusion_matrix, round(accuracy,3),round(f1,3), round(specificity,3), round(negativePredictive,3), + # Get metrics + TP, FN, FP, TN = counts[(1, 1)], counts[(1, 0)], counts[(0, 1)], counts[(0, 0)] + # Define confusin matrix + confusion_matrix = [[TP, FN], [FP, TN]] + # Get accuracy + accuracy = (TP + TN) / (TP + TN + FP + FN) + # Get precision + precision = TP / (TP + FP) + # Get recall + recall = TP / (TP + FN) + # Get F1 score + f1 = 2 * precision * recall / (precision + recall) + # Get negative predictive value + negativePredictive = TN / (TN + FN) + # Get specificiy + specificity = TN / (TN + FP) + # Return + return ( + confusion_matrix, + round(accuracy, 3), + round(f1, 3), + round(specificity, 3), + round(negativePredictive, 3), + ) + def test_confusion_matrix() -> None: # Test case 1 - y_actual, y_pred = [1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1], [0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0] - assert performance_metrics(y_actual,y_pred) == ([[6, 4], [2, 7]],0.684, 0.667, 0.778, 0.636), "Test case 1 failed" + y_actual, y_pred = ( + [1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1], + [0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0], + ) + assert performance_metrics(y_actual, y_pred) == ( + [[6, 4], [2, 7]], + 0.684, + 0.667, + 0.778, + 0.636, + ), "Test case 1 failed" # Test case 2 - y_actual, y_pred = [0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0],[1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1] - assert performance_metrics(y_actual,y_pred) == ([[4, 4], [5, 2]], 0.4, 0.471, 0.286, 0.333), "Test case 1 failed" + y_actual, y_pred = ( + [0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0], + [1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1], + ) + assert performance_metrics(y_actual, y_pred) == ( + [[4, 4], [5, 2]], + 0.4, + 0.471, + 0.286, + 0.333, + ), "Test case 1 failed" # Test case 3 - y_actual, y_pred = [1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1],[0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0] - assert performance_metrics(y_actual,y_pred) == ([[4, 5], [4, 2]], 0.4, 0.471, 0.333, 0.286), "Test case 1 failed" + y_actual, y_pred = ( + [1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1], + [0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0], + ) + assert performance_metrics(y_actual, y_pred) == ( + [[4, 5], [4, 2]], + 0.4, + 0.471, + 0.333, + 0.286, + ), "Test case 1 failed" + if __name__ == "__main__": test_confusion_matrix() - print("All performance metrics tests passed.") \ No newline at end of file + print("All performance metrics tests passed.") diff --git a/old_repo/Problems/76_Cosine_Similarity/solution.py b/old_repo/Problems/76_Cosine_Similarity/solution.py index 16ff3ba4..0f68a543 100644 --- a/old_repo/Problems/76_Cosine_Similarity/solution.py +++ b/old_repo/Problems/76_Cosine_Similarity/solution.py @@ -1,47 +1,49 @@ import numpy as np + def cosine_similarity(v1, v2): if v1.shape != v2.shape: raise ValueError("Arrays must have the same shape") - + if v1.size == 0: raise ValueError("Arrays cannot be empty") - + # Flatten arrays in case of 2D v1_flat = v1.flatten() v2_flat = v2.flatten() - + dot_product = np.dot(v1_flat, v2_flat) magnitude1 = np.sqrt(np.sum(v1_flat**2)) magnitude2 = np.sqrt(np.sum(v2_flat**2)) - + if magnitude1 == 0 or magnitude2 == 0: raise ValueError("Vectors cannot have zero magnitude") - + return round(dot_product / (magnitude1 * magnitude2), 3) + def test_cosine_similarity(): v1_test1 = np.array([1, 2, 3]) v2_test1 = np.array([2, 4, 6]) - expected1 = 1.0 + expected1 = 1.0 assert cosine_similarity(v1_test1, v2_test1) == expected1, "Test Case Failed" - + v1_test2 = np.array([[1, 2], [3, 4]]) v2_test2 = np.array([[2, 4], [6, 8]]) expected2 = 1.0 assert cosine_similarity(v1_test2, v2_test2) == expected2, "Test Case Failed" - + v1_test3 = np.array([1, 2, 3]) v2_test3 = np.array([-1, -2, -3]) expected3 = -1.0 assert cosine_similarity(v1_test3, v2_test3) == expected3, "Test Case Failed" - + # Test Case : Orthogonal vectors v1_test4 = np.array([1, 0]) v2_test4 = np.array([0, 1]) expected4 = 0.0 assert cosine_similarity(v1_test4, v2_test4) == expected4, "Test Case Failed" - + # Test Case : Different shapes v1_test5 = np.array([1, 2, 3]) v2_test5 = np.array([1, 2]) @@ -50,7 +52,7 @@ def test_cosine_similarity(): assert False, "Test Case Failed" except ValueError: pass - + # Test Case : Zero magnitude vector v1_test7 = np.array([0, 0, 0]) v2_test7 = np.array([1, 2, 3]) @@ -60,6 +62,7 @@ def test_cosine_similarity(): except ValueError: pass + if __name__ == "__main__": test_cosine_similarity() print("All Test Cases Passed!") diff --git a/old_repo/Problems/77_classification_performance_metrics/solution.py b/old_repo/Problems/77_classification_performance_metrics/solution.py index 239a057d..10352662 100644 --- a/old_repo/Problems/77_classification_performance_metrics/solution.py +++ b/old_repo/Problems/77_classification_performance_metrics/solution.py @@ -1,45 +1,81 @@ from collections import Counter -def performance_metrics(actual: list[int],predicted: list[int]) -> tuple: - #Ensure lists are of the same length + +def performance_metrics(actual: list[int], predicted: list[int]) -> tuple: + # Ensure lists are of the same length if len(actual) != len(predicted): raise ValueError("Lists must be of the same length") - #Merge lists into one - data = list(zip(actual,predicted)) - #Count all occurrences + # Merge lists into one + data = list(zip(actual, predicted)) + # Count all occurrences counts = Counter(tuple(pair) for pair in data) - #Get metrics - TP, FN, FP, TN = counts[(1,1)],counts[(1,0)],counts[(0,1)],counts[(0,0)] - #Define confusin matrix - confusion_matrix = [[TP,FN],[FP,TN]] - #Get accuracy - accuracy = (TP+TN)/(TP+TN+FP+FN) - #Get precision - precision = TP/(TP+FP) - #Get recall - recall = TP/(TP + FN) - #Get F1 score - f1 = 2*precision*recall/(precision+recall) - #Get negative predictive value - negativePredictive = TN/(TN+FN) - #Get specificiy - specificity = TN/(TN+FP) - #Return - return confusion_matrix, round(accuracy,3),round(f1,3), round(specificity,3), round(negativePredictive,3), + # Get metrics + TP, FN, FP, TN = counts[(1, 1)], counts[(1, 0)], counts[(0, 1)], counts[(0, 0)] + # Define confusin matrix + confusion_matrix = [[TP, FN], [FP, TN]] + # Get accuracy + accuracy = (TP + TN) / (TP + TN + FP + FN) + # Get precision + precision = TP / (TP + FP) + # Get recall + recall = TP / (TP + FN) + # Get F1 score + f1 = 2 * precision * recall / (precision + recall) + # Get negative predictive value + negativePredictive = TN / (TN + FN) + # Get specificiy + specificity = TN / (TN + FP) + # Return + return ( + confusion_matrix, + round(accuracy, 3), + round(f1, 3), + round(specificity, 3), + round(negativePredictive, 3), + ) + def test_confusion_matrix() -> None: # Test case 1 - y_actual, y_pred = [1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1], [0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0] - assert performance_metrics(y_actual,y_pred) == ([[6, 4], [2, 7]],0.684, 0.667, 0.778, 0.636), "Test case 1 failed" + y_actual, y_pred = ( + [1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1], + [0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0], + ) + assert performance_metrics(y_actual, y_pred) == ( + [[6, 4], [2, 7]], + 0.684, + 0.667, + 0.778, + 0.636, + ), "Test case 1 failed" # Test case 2 - y_actual, y_pred = [0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0],[1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1] - assert performance_metrics(y_actual,y_pred) == ([[4, 4], [5, 2]], 0.4, 0.471, 0.286, 0.333), "Test case 1 failed" + y_actual, y_pred = ( + [0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0], + [1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1], + ) + assert performance_metrics(y_actual, y_pred) == ( + [[4, 4], [5, 2]], + 0.4, + 0.471, + 0.286, + 0.333, + ), "Test case 1 failed" # Test case 3 - y_actual, y_pred = [1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1],[0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0] - assert performance_metrics(y_actual,y_pred) == ([[4, 5], [4, 2]], 0.4, 0.471, 0.333, 0.286), "Test case 1 failed" + y_actual, y_pred = ( + [1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1], + [0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0], + ) + assert performance_metrics(y_actual, y_pred) == ( + [[4, 5], [4, 2]], + 0.4, + 0.471, + 0.333, + 0.286, + ), "Test case 1 failed" + if __name__ == "__main__": test_confusion_matrix() - print("All performance metrics tests passed.") \ No newline at end of file + print("All performance metrics tests passed.") diff --git a/old_repo/Problems/78_binomial_distribution/solution.py b/old_repo/Problems/78_binomial_distribution/solution.py index ad7ace5f..91dcaaa2 100644 --- a/old_repo/Problems/78_binomial_distribution/solution.py +++ b/old_repo/Problems/78_binomial_distribution/solution.py @@ -1,5 +1,6 @@ import math + def binomial_probability(n, k, p): """ Calculate the probability of achieving exactly k successes in n independent Bernoulli trials, @@ -13,47 +14,54 @@ def binomial_probability(n, k, p): # Calculate binomial coefficient (n choose k) binomial_coeff = math.comb(n, k) # Calculate the probability using the binomial formula - probability = binomial_coeff * (p ** k) * ((1 - p) ** (n - k)) + probability = binomial_coeff * (p**k) * ((1 - p) ** (n - k)) # Return the probability, rounded to five decimal places return round(probability, 5) + def test_binomial_probability(): # Test case 1: Basic binomial calculation n1, k1, p1 = 6, 2, 0.5 expected_output_1 = 0.23438 output_1 = binomial_probability(n1, k1, p1) - assert output_1 == expected_output_1, \ + assert output_1 == expected_output_1, ( f"Test case 1 failed: expected {expected_output_1}, got {output_1}" + ) # Test case 2: Higher success probability n2, k2, p2 = 6, 4, 0.7 expected_output_2 = 0.32413 output_2 = binomial_probability(n2, k2, p2) - assert output_2 == expected_output_2, \ + assert output_2 == expected_output_2, ( f"Test case 2 failed: expected {expected_output_2}, got {output_2}" + ) # Test case 3: All trials succeed n3, k3, p3 = 3, 3, 0.9 expected_output_3 = 0.729 output_3 = binomial_probability(n3, k3, p3) - assert output_3 == expected_output_3, \ + assert output_3 == expected_output_3, ( f"Test case 3 failed: expected {expected_output_3}, got {output_3}" + ) # Test case 4: All trials fail n4, k4, p4 = 5, 0, 0.3 expected_output_4 = 0.16807 output_4 = binomial_probability(n4, k4, p4) - assert output_4 == expected_output_4, \ + assert output_4 == expected_output_4, ( f"Test case 4 failed: expected {expected_output_4}, got {output_4}" + ) # Test case 5: Low probability of success n5, k5, p5 = 7, 2, 0.1 expected_output_5 = 0.12106 output_5 = binomial_probability(n5, k5, p5) - assert output_5 == expected_output_5, \ + assert output_5 == expected_output_5, ( f"Test case 5 failed: expected {expected_output_5}, got {output_5}" + ) print("All Binomial distribution tests passed.") + if __name__ == "__main__": test_binomial_probability() diff --git a/old_repo/Problems/78_descriptive_stats/solution.py b/old_repo/Problems/78_descriptive_stats/solution.py index 84dcdd0e..5dbdde43 100644 --- a/old_repo/Problems/78_descriptive_stats/solution.py +++ b/old_repo/Problems/78_descriptive_stats/solution.py @@ -44,7 +44,7 @@ def descriptive_statistics(data): "25th_percentile": percentiles[0], "50th_percentile": percentiles[1], "75th_percentile": percentiles[2], - "interquartile_range": iqr + "interquartile_range": iqr, } return stats_dict @@ -62,11 +62,13 @@ def test_descriptive_statistics(): "25th_percentile": 20.0, "50th_percentile": 30.0, "75th_percentile": 40.0, - "interquartile_range": 20.0 + "interquartile_range": 20.0, } output_1 = descriptive_statistics(data_1) - assert all(np.isclose(output_1[key], value, atol=1e-5) for key, value in expected_output_1.items()), \ - f"Test case 1 failed: expected {expected_output_1}, got {output_1}" + assert all( + np.isclose(output_1[key], value, atol=1e-5) + for key, value in expected_output_1.items() + ), f"Test case 1 failed: expected {expected_output_1}, got {output_1}" # Test case 2: Dataset with repeated elements data_2 = [1, 2, 2, 3, 4, 4, 4, 5] @@ -79,11 +81,13 @@ def test_descriptive_statistics(): "25th_percentile": 2.0, "50th_percentile": 3.5, "75th_percentile": 4.0, - "interquartile_range": 2.0 + "interquartile_range": 2.0, } output_2 = descriptive_statistics(data_2) - assert all(np.isclose(output_2[key], value, atol=1e-5) for key, value in expected_output_2.items()), \ - f"Test case 2 failed: expected {expected_output_2}, got {output_2}" + assert all( + np.isclose(output_2[key], value, atol=1e-5) + for key, value in expected_output_2.items() + ), f"Test case 2 failed: expected {expected_output_2}, got {output_2}" # Test case 3: Single-element dataset data_3 = [100] @@ -96,11 +100,13 @@ def test_descriptive_statistics(): "25th_percentile": 100.0, "50th_percentile": 100.0, "75th_percentile": 100.0, - "interquartile_range": 0.0 + "interquartile_range": 0.0, } output_3 = descriptive_statistics(data_3) - assert all(np.isclose(output_3[key], value, atol=1e-5) for key, value in expected_output_3.items()), \ - f"Test case 3 failed: expected {expected_output_3}, got {output_3}" + assert all( + np.isclose(output_3[key], value, atol=1e-5) + for key, value in expected_output_3.items() + ), f"Test case 3 failed: expected {expected_output_3}, got {output_3}" print("All descriptive statistics tests passed.") diff --git a/old_repo/Problems/7_transform_matrix/solution.py b/old_repo/Problems/7_transform_matrix/solution.py index e7312a4f..7b0e73a9 100644 --- a/old_repo/Problems/7_transform_matrix/solution.py +++ b/old_repo/Problems/7_transform_matrix/solution.py @@ -1,29 +1,30 @@ import numpy as np + def transform_matrix( A: list[list[int | float]], T: list[list[int | float]], S: list[list[int | float]], ) -> list[list[int | float]]: - # Convert to numpy arrays for easier manipulation A = np.array(A, dtype=float) T = np.array(T, dtype=float) S = np.array(S, dtype=float) - + # Check if the matrices T and S are invertible if np.linalg.det(T) == 0 or np.linalg.det(S) == 0: # raise ValueError("The matrices T and/or S are not invertible.") return -1 - + # Compute the inverse of T T_inv = np.linalg.inv(T) - + # Perform the matrix transformation; use @ for better readability transformed_matrix = np.round(T_inv @ A @ S, 3) - + return transformed_matrix.tolist() + def test_transform_matrix() -> None: # Test cases for transform_matrix function # Test case 1 @@ -31,19 +32,19 @@ def test_transform_matrix() -> None: T = [[2, 0], [0, 2]] S = [[1, 1], [0, 1]] assert transform_matrix(A, T, S) == [[0.5, 1.5], [1.5, 3.5]] - + # Test case 2 A = [[1, 0], [0, 1]] T = [[1, 2], [3, 4]] S = [[2, 0], [0, 2]] assert transform_matrix(A, T, S) == [[-4.0, 2.0], [3.0, -1.0]] - + # Test case 3 A = [[2, 3], [1, 4]] T = [[3, 0], [0, 3]] S = [[1, 1], [0, 1]] assert transform_matrix(A, T, S) == [[0.667, 1.667], [0.333, 1.667]] - + # Test case 4 A = [[2, 3], [1, 4]] T = [[3, 0], [0, 3]] @@ -51,16 +52,21 @@ def test_transform_matrix() -> None: assert transform_matrix(A, T, S) == -1 # Test case 5 - A = [[1, 2, 3],[0, 1, 4],[5, 6, 0]] - T = [[2, 0, 0],[0, 2, 0],[0, 0, 2]] - S = [[0, 1, 0],[0, 0, 1],[1, 0, 0]] - assert transform_matrix(A, T, S) == [[1.5, 0.5, 1.0], [2.0, 0.0, 0.5], [0.0, 2.5, 3.0]] + A = [[1, 2, 3], [0, 1, 4], [5, 6, 0]] + T = [[2, 0, 0], [0, 2, 0], [0, 0, 2]] + S = [[0, 1, 0], [0, 0, 1], [1, 0, 0]] + assert transform_matrix(A, T, S) == [ + [1.5, 0.5, 1.0], + [2.0, 0.0, 0.5], + [0.0, 2.5, 3.0], + ] # try: # transform_matrix(A, T, S) # assert False, "ValueError not raised" # except ValueError as e: # assert str(e) == "The matrices T and/or S are not invertible." + if __name__ == "__main__": test_transform_matrix() - print("All transform_matrix tests passed.") \ No newline at end of file + print("All transform_matrix tests passed.") diff --git a/old_repo/Problems/80_normal_distribution/solution.py b/old_repo/Problems/80_normal_distribution/solution.py index f5c5b34a..47a933d5 100644 --- a/old_repo/Problems/80_normal_distribution/solution.py +++ b/old_repo/Problems/80_normal_distribution/solution.py @@ -1,5 +1,6 @@ import math + def normal_pdf(x, mean, std_dev): """ Calculate the probability density function (PDF) of the normal distribution. @@ -10,9 +11,10 @@ def normal_pdf(x, mean, std_dev): :return: The PDF value for the given x. """ coefficient = 1 / (math.sqrt(2 * math.pi) * std_dev) - exponent = math.exp(-((x - mean) ** 2) / (2 * std_dev ** 2)) + exponent = math.exp(-((x - mean) ** 2) / (2 * std_dev**2)) return round(coefficient * exponent, 5) + def test_normal_pdf(): """ Test cases for the normal_pdf function. @@ -21,25 +23,29 @@ def test_normal_pdf(): x1, mean1, std_dev1 = 0, 0, 1 expected_output_1 = 0.39894 output_1 = normal_pdf(x1, mean1, std_dev1) - assert output_1 == expected_output_1, \ + assert output_1 == expected_output_1, ( f"Test case 1 failed: expected {expected_output_1}, got {output_1}" + ) # Test case 2: Normal distribution with non-zero mean x2, mean2, std_dev2 = 16, 15, 2.04 expected_output_2 = 0.17603 output_2 = normal_pdf(x2, mean2, std_dev2) - assert output_2 == expected_output_2, \ + assert output_2 == expected_output_2, ( f"Test case 2 failed: expected {expected_output_2}, got {output_2}" + ) # Test case 3: Low standard deviation x3, mean3, std_dev3 = 1, 0, 0.5 expected_output_3 = 0.10798 output_3 = normal_pdf(x3, mean3, std_dev3) - assert output_3 == expected_output_3, \ + assert output_3 == expected_output_3, ( f"Test case 3 failed: expected {expected_output_3}, got {output_3}" + ) print("All Normal Distribution tests passed.") + if __name__ == "__main__": # Run the test cases - test_normal_pdf() \ No newline at end of file + test_normal_pdf() diff --git a/old_repo/Problems/81_poisson_distribution/solution.py b/old_repo/Problems/81_poisson_distribution/solution.py index d939282e..c08a2c73 100644 --- a/old_repo/Problems/81_poisson_distribution/solution.py +++ b/old_repo/Problems/81_poisson_distribution/solution.py @@ -1,5 +1,6 @@ import math + def poisson_probability(k, lam): """ Calculate the probability of observing exactly k events in a fixed interval, @@ -10,47 +11,54 @@ def poisson_probability(k, lam): :return: Probability of k events occurring """ # Calculate the Poisson probability using the formula - probability = (lam ** k) * math.exp(-lam) / math.factorial(k) + probability = (lam**k) * math.exp(-lam) / math.factorial(k) # Return the probability, rounded to five decimal places return round(probability, 5) + def test_poisson_probability(): # Test case 1: Basic Poisson distribution calculation k1, lam1 = 3, 5 expected_output_1 = 0.14037 output_1 = poisson_probability(k1, lam1) - assert output_1 == expected_output_1, \ + assert output_1 == expected_output_1, ( f"Test case 1 failed: expected {expected_output_1}, got {output_1}" + ) # Test case 2: Calculate probability for k = 0 k2, lam2 = 0, 5 expected_output_2 = 0.00674 output_2 = poisson_probability(k2, lam2) - assert output_2 == expected_output_2, \ + assert output_2 == expected_output_2, ( f"Test case 2 failed: expected {expected_output_2}, got {output_2}" + ) # Test case 3: Larger lambda (mean rate) k3, lam3 = 2, 10 expected_output_3 = 0.00045 output_3 = poisson_probability(k3, lam3) - assert output_3 == expected_output_3, \ + assert output_3 == expected_output_3, ( f"Test case 3 failed: expected {expected_output_3}, got {output_3}" + ) # Test case 4: Small k with small lambda k4, lam4 = 1, 1 expected_output_4 = 0.36788 output_4 = poisson_probability(k4, lam4) - assert output_4 == expected_output_4, \ + assert output_4 == expected_output_4, ( f"Test case 4 failed: expected {expected_output_4}, got {output_4}" + ) # Test case 5: Larger k with large lambda k5, lam5 = 20, 20 expected_output_5 = 0.08505 output_5 = poisson_probability(k5, lam5) - assert output_5 == expected_output_5, \ + assert output_5 == expected_output_5, ( f"Test case 5 failed: expected {expected_output_5}, got {output_5}" + ) print("All Poisson distribution tests passed.") + if __name__ == "__main__": test_poisson_probability() diff --git a/old_repo/Problems/82_image_basic_contrast_calculator/solution.py b/old_repo/Problems/82_image_basic_contrast_calculator/solution.py index 1f09250b..11272d2f 100644 --- a/old_repo/Problems/82_image_basic_contrast_calculator/solution.py +++ b/old_repo/Problems/82_image_basic_contrast_calculator/solution.py @@ -1,5 +1,6 @@ import numpy as np + def calculate_contrast(img): """ Calculate the contrast of a grayscale image. @@ -10,42 +11,44 @@ def calculate_contrast(img): Returns: float: Contrast value rounded to 3 decimal places. """ - + # Find the maximum and minimum pixel values max_pixel = np.max(img) min_pixel = np.min(img) - + # Calculate contrast contrast = max_pixel - min_pixel - + return round(float(contrast), 3) + def test_calculate_contrast(): # Test case 1: Simple gradient img1 = np.array([[0, 50], [200, 255]]) expected_output1 = 255 assert calculate_contrast(img1) == expected_output1, "Test case 1 failed" - + # Test case 2: Uniform image (all pixels same) img2 = np.array([[128, 128], [128, 128]]) expected_output2 = 0 assert calculate_contrast(img2) == expected_output2, "Test case 2 failed" - + # Test case 3: All black img3 = np.zeros((10, 10), dtype=np.uint8) expected_output3 = 0 assert calculate_contrast(img3) == expected_output3, "Test case 3 failed" - + # Test case 4: All white img4 = np.ones((10, 10), dtype=np.uint8) * 255 expected_output4 = 0 assert calculate_contrast(img4) == expected_output4, "Test case 4 failed" - + # Test case 5: Random values img5 = np.array([[10, 20, 30], [40, 50, 60]]) expected_output5 = 50 assert calculate_contrast(img5) == expected_output5, "Test case 5 failed" + if __name__ == "__main__": test_calculate_contrast() - print("All contrast test cases passed.") \ No newline at end of file + print("All contrast test cases passed.") diff --git a/old_repo/Problems/83_vector_dot_product/solution.py b/old_repo/Problems/83_vector_dot_product/solution.py index 8203f86f..68b7fad0 100644 --- a/old_repo/Problems/83_vector_dot_product/solution.py +++ b/old_repo/Problems/83_vector_dot_product/solution.py @@ -1,5 +1,6 @@ import numpy as np + def calculate_dot_product(vec1, vec2): """ Calculate the dot product of two vectors. @@ -13,37 +14,39 @@ def calculate_dot_product(vec1, vec2): """ return np.dot(vec1, vec2) + def test_calculate_dot_product(): # Test case 1: Positive numbers vec1 = np.array([1, 2, 3]) vec2 = np.array([4, 5, 6]) expected_output1 = 32 assert calculate_dot_product(vec1, vec2) == expected_output1, "Test case 1 failed" - + # Test case 2: Include negative numbers vec1 = np.array([-1, 2, 3]) vec2 = np.array([4, -5, 6]) expected_output2 = 4 assert calculate_dot_product(vec1, vec2) == expected_output2, "Test case 2 failed" - + # Test case 3: Orthogonal vectors vec1 = np.array([1, 0]) vec2 = np.array([0, 1]) expected_output3 = 0 assert calculate_dot_product(vec1, vec2) == expected_output3, "Test case 3 failed" - + # Test case 4: All zeros vec1 = np.array([0, 0, 0]) vec2 = np.array([0, 0, 0]) expected_output4 = 0 assert calculate_dot_product(vec1, vec2) == expected_output4, "Test case 4 failed" - + # Test case 5: Scalars (single-element vectors) vec1 = np.array([7]) vec2 = np.array([3]) expected_output5 = 21 assert calculate_dot_product(vec1, vec2) == expected_output5, "Test case 5 failed" + if __name__ == "__main__": test_calculate_dot_product() print("All dot product test cases passed.") diff --git a/old_repo/Problems/84_phi_transformation/solution.py b/old_repo/Problems/84_phi_transformation/solution.py index 5df869da..d6bfe4b2 100644 --- a/old_repo/Problems/84_phi_transformation/solution.py +++ b/old_repo/Problems/84_phi_transformation/solution.py @@ -1,36 +1,40 @@ import numpy as np -def phi_transform(data: list[float], degree: int,) -> list[list[float]]: + +def phi_transform( + data: list[float], + degree: int, +) -> list[list[float]]: if degree < 0 or not data: return [] - return np.array([[x ** i for i in range(degree + 1)] for x in data]).tolist() + return np.array([[x**i for i in range(degree + 1)] for x in data]).tolist() + def test_phi_transform() -> None: - assert phi_transform([], 2) == [], 'Test Case 1 Failed.' + assert phi_transform([], 2) == [], "Test Case 1 Failed." - assert phi_transform([1.0, 2.0], -1) == [], 'Test Case 2 Failed.' + assert phi_transform([1.0, 2.0], -1) == [], "Test Case 2 Failed." data: list[float] = [1.0, 2.0] degree: int = 2 assert phi_transform(data, degree) == [ [1.0, 1.0, 1.0], [1.0, 2.0, 4.0], - ], 'Test Case 3 Failed.' + ], "Test Case 3 Failed." data: list[float] = [1.0, 3.0] degree: int = 3 assert phi_transform(data, degree) == [ [1.0, 1.0, 1.0, 1.0], [1.0, 3.0, 9.0, 27.0], - ], 'Test Case 4 Failed.' + ], "Test Case 4 Failed." data: list[float] = [2.0] degree: int = 4 - assert phi_transform(data, degree) == [ - [1.0, 2.0, 4.0, 8.0, 16.0] - ], 'Test Case 5 Failed.' + assert phi_transform(data, degree) == [[1.0, 2.0, 4.0, 8.0, 16.0]], ( + "Test Case 5 Failed." + ) - if __name__ == "__main__": test_phi_transform() diff --git a/old_repo/Problems/85_Positional_encoding/solution.py b/old_repo/Problems/85_Positional_encoding/solution.py index e2aabfc5..258ad841 100644 --- a/old_repo/Problems/85_Positional_encoding/solution.py +++ b/old_repo/Problems/85_Positional_encoding/solution.py @@ -1,14 +1,14 @@ import numpy as np -def pos_encoding(position:int, dmodel:int): - - if position == 0 or dmodel == 0: return -1 + +def pos_encoding(position: int, dmodel: int): + if position == 0 or dmodel == 0: + return -1 pos = np.array(np.arange(position), np.float16) ind = np.array(np.arange(dmodel), np.float16) - pos = pos.reshape(position,1) - ind = ind.reshape(1,dmodel) - + pos = pos.reshape(position, 1) + ind = ind.reshape(1, dmodel) def get_angles(pos, i): angles = 1 / np.power(10000, (2 * (i // 2)) / np.float16(dmodel)) @@ -19,53 +19,145 @@ def get_angles(pos, i): sine = np.sin(angle1[:, 0::2]) cosine = np.cos(angle1[:, 1::2]) - pos_encoding = np.concatenate([sine, cosine], axis = -1) + pos_encoding = np.concatenate([sine, cosine], axis=-1) pos_encoding = pos_encoding[np.newaxis, :] pos_encoding = np.float16(pos_encoding) return pos_encoding + def test_pos_encoding() -> None: # Test case 1: - ans1 = np.array([[[0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0], - [0.8413, 0.0998, 0.01, 0.001, 0.5405, 0.995, 1.0, 1.0]]], dtype=np.float16) + ans1 = np.array( + [ + [ + [0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0], + [0.8413, 0.0998, 0.01, 0.001, 0.5405, 0.995, 1.0, 1.0], + ] + ], + dtype=np.float16, + ) result1 = pos_encoding(2, 8) - assert np.allclose(result1, ans1, atol=1e-3), f"Test case 1 failed: {result1} != {ans1}" - + assert np.allclose(result1, ans1, atol=1e-3), ( + f"Test case 1 failed: {result1} != {ans1}" + ) # Test case 2: ans2 = np.array( - [[[ 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, - 0.000e+00, 0.000e+00, 1.000e+00, 1.000e+00, 1.000e+00, 1.000e+00, - 1.000e+00, 1.000e+00, 1.000e+00, 1.000e+00], - [ 8.413e-01, 3.110e-01, 9.985e-02, 3.162e-02, 1.000e-02, 3.162e-03, - 1.000e-03, 3.161e-04, 5.405e-01, 9.502e-01, 9.951e-01, 9.995e-01, - 1.000e+00, 1.000e+00, 1.000e+00, 1.000e+00], - [ 9.092e-01, 5.913e-01, 1.986e-01, 6.323e-02, 2.000e-02, 6.325e-03, - 2.001e-03, 6.323e-04, -4.163e-01, 8.066e-01, 9.800e-01, 9.980e-01, - 1.000e+00, 1.000e+00, 1.000e+00, 1.000e+00], - [ 1.411e-01, 8.125e-01, 2.954e-01, 9.473e-02, 3.000e-02, 9.483e-03, - 3.000e-03, 9.489e-04, -9.902e-01, 5.825e-01, 9.556e-01, 9.956e-01, - 9.995e-01, 1.000e+00, 1.000e+00, 1.000e+00], - [-7.568e-01, 9.536e-01, 3.894e-01, 1.261e-01, 3.998e-02, 1.265e-02, - 4.002e-03, 1.265e-03, -6.538e-01, 3.010e-01, 9.209e-01, 9.922e-01, - 9.990e-01, 1.000e+00, 1.000e+00, 1.000e+00]]], - dtype=np.float16) + [ + [ + [ + 0.000e00, + 0.000e00, + 0.000e00, + 0.000e00, + 0.000e00, + 0.000e00, + 0.000e00, + 0.000e00, + 1.000e00, + 1.000e00, + 1.000e00, + 1.000e00, + 1.000e00, + 1.000e00, + 1.000e00, + 1.000e00, + ], + [ + 8.413e-01, + 3.110e-01, + 9.985e-02, + 3.162e-02, + 1.000e-02, + 3.162e-03, + 1.000e-03, + 3.161e-04, + 5.405e-01, + 9.502e-01, + 9.951e-01, + 9.995e-01, + 1.000e00, + 1.000e00, + 1.000e00, + 1.000e00, + ], + [ + 9.092e-01, + 5.913e-01, + 1.986e-01, + 6.323e-02, + 2.000e-02, + 6.325e-03, + 2.001e-03, + 6.323e-04, + -4.163e-01, + 8.066e-01, + 9.800e-01, + 9.980e-01, + 1.000e00, + 1.000e00, + 1.000e00, + 1.000e00, + ], + [ + 1.411e-01, + 8.125e-01, + 2.954e-01, + 9.473e-02, + 3.000e-02, + 9.483e-03, + 3.000e-03, + 9.489e-04, + -9.902e-01, + 5.825e-01, + 9.556e-01, + 9.956e-01, + 9.995e-01, + 1.000e00, + 1.000e00, + 1.000e00, + ], + [ + -7.568e-01, + 9.536e-01, + 3.894e-01, + 1.261e-01, + 3.998e-02, + 1.265e-02, + 4.002e-03, + 1.265e-03, + -6.538e-01, + 3.010e-01, + 9.209e-01, + 9.922e-01, + 9.990e-01, + 1.000e00, + 1.000e00, + 1.000e00, + ], + ] + ], + dtype=np.float16, + ) result2 = pos_encoding(5, 16) - assert np.allclose(result2, ans2, atol=1e-3), f"Test case 2 failed: {result2} != {ans2}" - + assert np.allclose(result2, ans2, atol=1e-3), ( + f"Test case 2 failed: {result2} != {ans2}" + ) # Test case 3: ans3 = np.array([]) - assert np.allclose(pos_encoding(0,0), ans3, atol=1e-3), f"Test case 3 failed: {pos_encoding(0,0)} != {ans3}" - + assert np.allclose(pos_encoding(0, 0), ans3, atol=1e-3), ( + f"Test case 3 failed: {pos_encoding(0, 0)} != {ans3}" + ) # Test case 4: ans4 = -1 - assert np.allclose(pos_encoding(2,-1), ans4, atol=1e-3), f"Test case 4 failed: {pos_encoding(2,-1)} != {ans4}" - + assert np.allclose(pos_encoding(2, -1), ans4, atol=1e-3), ( + f"Test case 4 failed: {pos_encoding(2, -1)} != {ans4}" + ) if __name__ == "__main__": test_pos_encoding() - print("All tests passed.") \ No newline at end of file + print("All tests passed.") diff --git a/old_repo/Problems/86_overfitting_underfitting/solution.py b/old_repo/Problems/86_overfitting_underfitting/solution.py index 0b47ad1e..f3fc92c1 100644 --- a/old_repo/Problems/86_overfitting_underfitting/solution.py +++ b/old_repo/Problems/86_overfitting_underfitting/solution.py @@ -12,6 +12,7 @@ def model_fit_quality(training_accuracy: float, test_accuracy: float) -> int: else: return 0 + def test_model_fit_quality() -> None: # Test case 1: Overfitting result1 = model_fit_quality(0.9, 0.6) @@ -33,6 +34,7 @@ def test_model_fit_quality() -> None: result5 = model_fit_quality(0.9, 0.7) assert result5 == 0, f"Test case 5 failed: {result5} != 0" + if __name__ == "__main__": test_model_fit_quality() print("All tests passed.") diff --git a/old_repo/Problems/87_adam_optimizer/solution.py b/old_repo/Problems/87_adam_optimizer/solution.py index 2825378a..ff723988 100644 --- a/old_repo/Problems/87_adam_optimizer/solution.py +++ b/old_repo/Problems/87_adam_optimizer/solution.py @@ -1,6 +1,9 @@ import numpy as np -def adam_optimizer(parameter, grad, m, v, t, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8): + +def adam_optimizer( + parameter, grad, m, v, t, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8 +): """ Update parameters using the Adam optimizer. Adjusts the learning rate based on the moving averages of the gradient and squared gradient. @@ -37,6 +40,7 @@ def adam_optimizer(parameter, grad, m, v, t, learning_rate=0.001, beta1=0.9, bet return parameter, m, v + def test_adam_optimizer(): """Test cases for the Adam optimizer implementation.""" # Test case 1: Scalar inputs @@ -62,11 +66,14 @@ def test_adam_optimizer(): expected_m = np.array([0.01, 0.02]) expected_v = np.array([0.0001, 0.0004]) - assert np.allclose(new_param, expected_param), f"Unexpected parameter values: {new_param}" + assert np.allclose(new_param, expected_param), ( + f"Unexpected parameter values: {new_param}" + ) assert np.allclose(new_m, expected_m), f"Unexpected m values: {new_m}" assert np.allclose(new_v, expected_v), f"Unexpected v values: {new_v}" print("All tests passed!") + if __name__ == "__main__": test_adam_optimizer() diff --git a/old_repo/Problems/88_GPT_2/solution.py b/old_repo/Problems/88_GPT_2/solution.py index 6a77ca04..72ff7e3f 100644 --- a/old_repo/Problems/88_GPT_2/solution.py +++ b/old_repo/Problems/88_GPT_2/solution.py @@ -1,51 +1,66 @@ import numpy as np + np.random.seed(42) + + def gelu(x): return 0.5 * x * (1 + np.tanh(np.sqrt(2 / np.pi) * (x + 0.044715 * x**3))) + def softmax(x): exp_x = np.exp(x - np.max(x, axis=-1, keepdims=True)) return exp_x / np.sum(exp_x, axis=-1, keepdims=True) + def layer_norm(x, g, b, eps=1e-5): mean = np.mean(x, axis=-1, keepdims=True) variance = np.var(x, axis=-1, keepdims=True) return g * (x - mean) / np.sqrt(variance + eps) + b + def linear(x, w, b): return x @ w + b + def ffn(x, c_fc, c_proj): return linear(gelu(linear(x, **c_fc)), **c_proj) + def attention(q, k, v, mask): return softmax(q @ k.T / np.sqrt(q.shape[-1]) + mask) @ v + def mha(x, c_attn, c_proj, n_head): x = linear(x, **c_attn) - qkv_heads = list(map(lambda x: np.split(x, n_head, axis=-1), np.split(x, 3, axis=-1))) + qkv_heads = list( + map(lambda x: np.split(x, n_head, axis=-1), np.split(x, 3, axis=-1)) + ) causal_mask = (1 - np.tri(x.shape[0], dtype=x.dtype)) * -1e10 out_heads = [attention(q, k, v, causal_mask) for q, k, v in zip(*qkv_heads)] x = linear(np.hstack(out_heads), **c_proj) return x + def transformer_block(x, mlp, attn, ln_1, ln_2, n_head): x = x + mha(layer_norm(x, **ln_1), **attn, n_head=n_head) x = x + ffn(layer_norm(x, **ln_2), **mlp) return x + def gpt2(inputs, wte, wpe, blocks, ln_f, n_head): x = wte[inputs] + wpe[range(len(inputs))] for block in blocks: x = transformer_block(x, **block, n_head=n_head) return layer_norm(x, **ln_f) @ wte.T + def generate(inputs, params, n_head, n_tokens_to_generate): for _ in range(n_tokens_to_generate): logits = gpt2(inputs, **params, n_head=n_head) next_id = np.argmax(logits[-1]) inputs.append(int(next_id)) - return inputs[len(inputs) - n_tokens_to_generate:] + return inputs[len(inputs) - n_tokens_to_generate :] + def gen_text(prompt: str, n_tokens_to_generate: int = 40): np.random.seed(42) # Set the random seed for reproducibility @@ -56,23 +71,28 @@ def gen_text(prompt: str, n_tokens_to_generate: int = 40): output_text = encoder.decode(output_ids) return output_text -def load_encoder_hparams_and_params(model_size: str = "124M", models_dir: str = "models"): + +def load_encoder_hparams_and_params( + model_size: str = "124M", models_dir: str = "models" +): class DummyBPE: def __init__(self): self.encoder_dict = {"hello": 1, "world": 2, "": 0} def encode(self, text: str): tokens = text.strip().split() - return [self.encoder_dict.get(token, self.encoder_dict[""]) for token in tokens] + return [ + self.encoder_dict.get(token, self.encoder_dict[""]) + for token in tokens + ] def decode(self, token_ids: list): reversed_dict = {v: k for k, v in self.encoder_dict.items()} - return " ".join([reversed_dict.get(tok_id, "") for tok_id in token_ids]) + return " ".join( + [reversed_dict.get(tok_id, "") for tok_id in token_ids] + ) - hparams = { - "n_ctx": 1024, - "n_head": 12 - } + hparams = {"n_ctx": 1024, "n_head": 12} params = { "wte": np.random.rand(3, 10), @@ -81,12 +101,13 @@ def decode(self, token_ids: list): "ln_f": { "g": np.ones(10), "b": np.zeros(10), - } + }, } encoder = DummyBPE() return encoder, hparams, params + def test_gen_text() -> None: # Test case 1 result1 = gen_text("hello", n_tokens_to_generate=5) @@ -103,6 +124,7 @@ def test_gen_text() -> None: expected3 = "world world world" assert result3 == expected3, f"Test case 3 failed: {result3} != {expected3}" + if __name__ == "__main__": test_gen_text() print("All tests passed.") diff --git a/old_repo/Problems/8_Calculate_2x2_Matrix_Inverse/solution.py b/old_repo/Problems/8_Calculate_2x2_Matrix_Inverse/solution.py index be97f0a8..5b7c3a16 100644 --- a/old_repo/Problems/8_Calculate_2x2_Matrix_Inverse/solution.py +++ b/old_repo/Problems/8_Calculate_2x2_Matrix_Inverse/solution.py @@ -3,9 +3,10 @@ def inverse_2x2(matrix: list[list[float]]) -> list[list[float]]: determinant = a * d - b * c if determinant == 0: return None - inverse = [[d/determinant, -b/determinant], [-c/determinant, a/determinant]] + inverse = [[d / determinant, -b / determinant], [-c / determinant, a / determinant]] return inverse + def test_inverse_2x2() -> None: # Test cases for inverse_2x2 function @@ -17,6 +18,7 @@ def test_inverse_2x2() -> None: matrix = [[2, 1], [6, 2]] assert inverse_2x2(matrix) == [[-1.0, 0.5], [3.0, -1.0]] + if __name__ == "__main__": test_inverse_2x2() print("All inverse_2x2 tests passed.") diff --git a/old_repo/Problems/8_Calculate_2x2_Matrix_Inverse/solution_2.py b/old_repo/Problems/8_Calculate_2x2_Matrix_Inverse/solution_2.py index f8c78d01..c6e7227e 100644 --- a/old_repo/Problems/8_Calculate_2x2_Matrix_Inverse/solution_2.py +++ b/old_repo/Problems/8_Calculate_2x2_Matrix_Inverse/solution_2.py @@ -1,4 +1,5 @@ import numpy as np + def inverse_2x2(matrix: list[list[float]]) -> list[list[float]]: - return np.linalg.inv(np.array(matrix)) \ No newline at end of file + return np.linalg.inv(np.array(matrix)) diff --git a/old_repo/Problems/94_multi_head_attention/solution.py b/old_repo/Problems/94_multi_head_attention/solution.py index 454c6b6c..86d47598 100644 --- a/old_repo/Problems/94_multi_head_attention/solution.py +++ b/old_repo/Problems/94_multi_head_attention/solution.py @@ -1,14 +1,17 @@ import numpy as np from typing import Tuple, List -def compute_qkv(X: np.ndarray, W_q: np.ndarray, W_k: np.ndarray, W_v: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + +def compute_qkv( + X: np.ndarray, W_q: np.ndarray, W_k: np.ndarray, W_v: np.ndarray +) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: """ Compute the Query (Q), Key (K), and Value (V) matrices. - + Args: X: numpy array of shape (seq_len, d_model), input sequence W_q, W_k, W_v: numpy arrays of shape (d_model, d_model), weight matrices for Q, K, and V - + Returns: Q, K, V: numpy arrays of shape (seq_len, d_model) """ @@ -17,106 +20,143 @@ def compute_qkv(X: np.ndarray, W_q: np.ndarray, W_k: np.ndarray, W_v: np.ndarray V = np.dot(X, W_v) # Compute the Value matrix V return Q, K, V + def self_attention(Q: np.ndarray, K: np.ndarray, V: np.ndarray) -> np.ndarray: """ Compute self-attention for a single head. - + Args: Q: numpy array of shape (seq_len, d_k), Query matrix K: numpy array of shape (seq_len, d_k), Key matrix V: numpy array of shape (seq_len, d_k), Value matrix - + Returns: attention_output: numpy array of shape (seq_len, d_k), output of the self-attention mechanism """ d_k = Q.shape[1] # Get the dimension of the keys - scores = np.matmul(Q, K.T) / np.sqrt(d_k) # Compute scaled dot-product attention scores - score_max = np.max(scores, axis=1, keepdims=True) # Find the maximum score for numerical stability - attention_weights = np.exp(scores - score_max) / np.sum(np.exp(scores - score_max), axis=1, keepdims=True) # Compute softmax to get attention weights - attention_output = np.matmul(attention_weights, V) # Compute the final attention output + scores = np.matmul(Q, K.T) / np.sqrt( + d_k + ) # Compute scaled dot-product attention scores + score_max = np.max( + scores, axis=1, keepdims=True + ) # Find the maximum score for numerical stability + attention_weights = np.exp(scores - score_max) / np.sum( + np.exp(scores - score_max), axis=1, keepdims=True + ) # Compute softmax to get attention weights + attention_output = np.matmul( + attention_weights, V + ) # Compute the final attention output return attention_output -def multi_head_attention(Q: np.ndarray, K: np.ndarray, V: np.ndarray, n_heads: int) -> Tuple[np.ndarray, List[np.ndarray]]: + +def multi_head_attention( + Q: np.ndarray, K: np.ndarray, V: np.ndarray, n_heads: int +) -> Tuple[np.ndarray, List[np.ndarray]]: """ Compute multi-head attention. - + Args: Q, K, V: numpy arrays of shape (seq_len, d_model), Query, Key, and Value matrices n_heads: int, number of attention heads - + Returns: attention_output: numpy array of shape (seq_len, d_model), final attention output """ d_model = Q.shape[1] # Get the model dimension assert d_model % n_heads == 0 # Ensure d_model is divisible by n_heads d_k = d_model // n_heads # Dimension for each head - + # Reshape Q, K, V to separate heads - Q_reshaped = Q.reshape(Q.shape[0], n_heads, d_k).transpose(1, 0, 2) # Reshape and transpose to (n_heads, seq_len, d_k) - K_reshaped = K.reshape(K.shape[0], n_heads, d_k).transpose(1, 0, 2) # Reshape and transpose to (n_heads, seq_len, d_k) - V_reshaped = V.reshape(V.shape[0], n_heads, d_k).transpose(1, 0, 2) # Reshape and transpose to (n_heads, seq_len, d_k) + Q_reshaped = Q.reshape(Q.shape[0], n_heads, d_k).transpose( + 1, 0, 2 + ) # Reshape and transpose to (n_heads, seq_len, d_k) + K_reshaped = K.reshape(K.shape[0], n_heads, d_k).transpose( + 1, 0, 2 + ) # Reshape and transpose to (n_heads, seq_len, d_k) + V_reshaped = V.reshape(V.shape[0], n_heads, d_k).transpose( + 1, 0, 2 + ) # Reshape and transpose to (n_heads, seq_len, d_k) # Compute attention scores for each head attentions = [] # Store attention outputs for each head for i in range(n_heads): - attn = self_attention(Q_reshaped[i], K_reshaped[i], V_reshaped[i]) # Compute attention for the i-th head + attn = self_attention( + Q_reshaped[i], K_reshaped[i], V_reshaped[i] + ) # Compute attention for the i-th head attentions.append(attn) # Collect attention output - + # Concatenate all head outputs - attention_output = np.concatenate(attentions, axis=-1) # Concatenate along the last axis (columns) + attention_output = np.concatenate( + attentions, axis=-1 + ) # Concatenate along the last axis (columns) return attention_output # Return the final attention output + def test_multi_head_attention(): # Test case 1: Basic functionality with computed Q, K, V m, n = 6, 8 n_heads = 4 np.random.seed(42) - X = np.arange(m*n).reshape(m,n) + X = np.arange(m * n).reshape(m, n) X = np.random.permutation(X.flatten()).reshape(m, n) - W_q = np.random.randint(0,4,size=(n,n)) - W_k = np.random.randint(0,5,size=(n,n)) - W_v = np.random.randint(0,6,size=(n,n)) + W_q = np.random.randint(0, 4, size=(n, n)) + W_k = np.random.randint(0, 5, size=(n, n)) + W_v = np.random.randint(0, 6, size=(n, n)) Q, K, V = compute_qkv(X, W_q, W_k, W_v) # test multi-head attention actual_output = multi_head_attention(Q, K, V, n_heads) - expected_output = np.array([[500, 463, 399, 495, 377, 450, 531, 362], - [500, 463, 399, 495, 377, 450, 531, 362], - [500, 463, 399, 495, 377, 450, 531, 362], - [500, 463, 399, 495, 377, 450, 531, 362], - [500, 463, 399, 495, 377, 450, 531, 362], - [500, 463, 399, 495, 377, 450, 531, 362]]) - np.testing.assert_array_almost_equal(actual_output, expected_output, decimal=6, err_msg="Test case 1 failed") + expected_output = np.array( + [ + [500, 463, 399, 495, 377, 450, 531, 362], + [500, 463, 399, 495, 377, 450, 531, 362], + [500, 463, 399, 495, 377, 450, 531, 362], + [500, 463, 399, 495, 377, 450, 531, 362], + [500, 463, 399, 495, 377, 450, 531, 362], + [500, 463, 399, 495, 377, 450, 531, 362], + ] + ) + np.testing.assert_array_almost_equal( + actual_output, expected_output, decimal=6, err_msg="Test case 1 failed" + ) # test less number of heads n_heads = 2 actual_output = multi_head_attention(Q, K, V, n_heads) - expected_output = np.array([[547, 490, 399, 495, 377, 450, 531, 362], - [547, 490, 399, 495, 377, 450, 531, 362], - [547, 490, 399, 495, 377, 450, 531, 362], - [547, 490, 399, 495, 377, 450, 531, 362], - [547, 490, 399, 495, 377, 450, 531, 362], - [547, 490, 399, 495, 377, 450, 531, 362]]) - np.testing.assert_array_almost_equal(actual_output, expected_output, decimal=6, err_msg="Test case 2 failed") + expected_output = np.array( + [ + [547, 490, 399, 495, 377, 450, 531, 362], + [547, 490, 399, 495, 377, 450, 531, 362], + [547, 490, 399, 495, 377, 450, 531, 362], + [547, 490, 399, 495, 377, 450, 531, 362], + [547, 490, 399, 495, 377, 450, 531, 362], + [547, 490, 399, 495, 377, 450, 531, 362], + ] + ) + np.testing.assert_array_almost_equal( + actual_output, expected_output, decimal=6, err_msg="Test case 2 failed" + ) # test small size input m, n = 4, 4 n_heads = 2 np.random.seed(42) - X = np.arange(m*n).reshape(m,n) + X = np.arange(m * n).reshape(m, n) X = np.random.permutation(X.flatten()).reshape(m, n) - W_q = np.random.randint(0,4,size=(n,n)) - W_k = np.random.randint(0,5,size=(n,n)) - W_v = np.random.randint(0,6,size=(n,n)) + W_q = np.random.randint(0, 4, size=(n, n)) + W_k = np.random.randint(0, 5, size=(n, n)) + W_v = np.random.randint(0, 6, size=(n, n)) Q, K, V = compute_qkv(X, W_q, W_k, W_v) actual_output = multi_head_attention(Q, K, V, n_heads) - expected_output = np.array([[103, 109, 46, 99], - [103, 109, 46, 99], - [103, 109, 46, 99], - [103, 109, 46, 99]]) - np.testing.assert_array_almost_equal(actual_output, expected_output, decimal=6, err_msg="Test case 3 failed") + expected_output = np.array( + [[103, 109, 46, 99], [103, 109, 46, 99], [103, 109, 46, 99], [103, 109, 46, 99]] + ) + np.testing.assert_array_almost_equal( + actual_output, expected_output, decimal=6, err_msg="Test case 3 failed" + ) + if __name__ == "__main__": test_multi_head_attention() - print("All multi-head-attention tests passed.") \ No newline at end of file + print("All multi-head-attention tests passed.") diff --git a/old_repo/Problems/95_phi_correlation_coefficient/solution.py b/old_repo/Problems/95_phi_correlation_coefficient/solution.py index 6d536b6d..05f50708 100644 --- a/old_repo/Problems/95_phi_correlation_coefficient/solution.py +++ b/old_repo/Problems/95_phi_correlation_coefficient/solution.py @@ -1,33 +1,35 @@ -def phi_corr(x:list[int],y:list[int]): - x1y1=0 - x1y0=0 - x0y1=0 - x0y0=0 +def phi_corr(x: list[int], y: list[int]): + x1y1 = 0 + x1y0 = 0 + x0y1 = 0 + x0y0 = 0 for i in range(len(x)): - if x[i]==1: - if y[i]==1: - x1y1+=1 + if x[i] == 1: + if y[i] == 1: + x1y1 += 1 else: - x1y0+=1 - if x[i]==0: - if y[i]==1: - x0y1+=1 + x1y0 += 1 + if x[i] == 0: + if y[i] == 1: + x0y1 += 1 else: - x0y0+=1 + x0y0 += 1 - dr=((x0y0+x0y1)*(x1y0+x1y1)*(x0y0+x1y0)*(x0y1+x1y1))**0.5 - nr=(x0y0*x1y1)-(x0y1*x1y0) - phi=round(nr/dr,4) + dr = ((x0y0 + x0y1) * (x1y0 + x1y1) * (x0y0 + x1y0) * (x0y1 + x1y1)) ** 0.5 + nr = (x0y0 * x1y1) - (x0y1 * x1y0) + phi = round(nr / dr, 4) return phi + def test_phi_corr(): # Test case 1: z = 0 - assert phi_corr([1,1,0,0],[0,0,1,1]) == -1, "Test case 1 failed" - + assert phi_corr([1, 1, 0, 0], [0, 0, 1, 1]) == -1, "Test case 1 failed" + # Test case 2: z = 1 - assert phi_corr([1,1,0,0],[1,0,1,1]) == -0.5774, "Test case 2 failed" + assert phi_corr([1, 1, 0, 0], [1, 0, 1, 1]) == -0.5774, "Test case 2 failed" + if __name__ == "__main__": test_phi_corr() diff --git a/old_repo/Problems/96_Hard_Sigmoid/solution.py b/old_repo/Problems/96_Hard_Sigmoid/solution.py index 1c4ef36a..cbe8c756 100644 --- a/old_repo/Problems/96_Hard_Sigmoid/solution.py +++ b/old_repo/Problems/96_Hard_Sigmoid/solution.py @@ -1,10 +1,10 @@ def hard_sigmoid(x: float) -> float: """ Implements the Hard Sigmoid activation function. - + Args: x (float): Input value - + Returns: float: The Hard Sigmoid of the input """ @@ -15,22 +15,24 @@ def hard_sigmoid(x: float) -> float: else: return 0.2 * x + 0.5 + def test_hard_sigmoid(): # Test case 1: x <= -2.5 assert hard_sigmoid(-3.0) == 0.0, "Test case 1 failed" - + # Test case 2: x >= 2.5 assert hard_sigmoid(3.0) == 1.0, "Test case 2 failed" - + # Test case 3: -2.5 < x < 2.5 assert abs(hard_sigmoid(0.0) - 0.5) < 1e-6, "Test case 3 failed" assert abs(hard_sigmoid(1.0) - 0.7) < 1e-6, "Test case 4 failed" assert abs(hard_sigmoid(-1.0) - 0.3) < 1e-6, "Test case 5 failed" - + # Test boundary cases assert abs(hard_sigmoid(2.5) - 1.0) < 1e-6, "Test case 6 failed" assert abs(hard_sigmoid(-2.5) - 0.0) < 1e-6, "Test case 7 failed" + if __name__ == "__main__": test_hard_sigmoid() - print("All Hard Sigmoid tests passed.") \ No newline at end of file + print("All Hard Sigmoid tests passed.") diff --git a/old_repo/Problems/97_ELU/solution.py b/old_repo/Problems/97_ELU/solution.py index 731ee693..bf3df24f 100644 --- a/old_repo/Problems/97_ELU/solution.py +++ b/old_repo/Problems/97_ELU/solution.py @@ -1,37 +1,40 @@ import math + def elu(x: float, alpha: float = 1.0) -> float: """ Compute the ELU activation function. - + Args: x (float): Input value alpha (float): ELU parameter for negative values (default: 1.0) - + Returns: float: ELU activation value """ return x if x > 0 else alpha * (math.exp(x) - 1) + def test_elu(): # Test case 1: x = 0 assert abs(elu(0)) < 1e-10, "Test case 1 failed" - + # Test case 2: positive input assert abs(elu(1) - 1) < 1e-10, "Test case 2 failed" - + # Test case 3: negative input assert abs(elu(-1) - (-0.6321205588285577)) < 1e-10, "Test case 3 failed" - + # Test case 4: different alpha value assert abs(elu(-1, alpha=2.0) - (-1.2642411176571154)) < 1e-10, "Test case 4 failed" - + # Test case 5: large positive input assert abs(elu(5) - 5) < 1e-10, "Test case 5 failed" - + # Test case 6: large negative input assert abs(elu(-5) - (-0.9932620530009145)) < 1e-10, "Test case 6 failed" + if __name__ == "__main__": test_elu() - print("All ELU tests passed.") \ No newline at end of file + print("All ELU tests passed.") diff --git a/old_repo/Problems/98_PReLU/solution.py b/old_repo/Problems/98_PReLU/solution.py index c9b30ece..9650f69d 100644 --- a/old_repo/Problems/98_PReLU/solution.py +++ b/old_repo/Problems/98_PReLU/solution.py @@ -1,35 +1,39 @@ def prelu(x: float, alpha: float = 0.25) -> float: """ Implements the PReLU (Parametric ReLU) activation function. - + Args: x: Input value alpha: Slope parameter for negative values (default: 0.25) - + Returns: float: PReLU activation value """ return x if x > 0 else alpha * x + def test_prelu() -> None: # Test positive input (should behave like regular ReLU) assert prelu(2.0) == 2.0, "Test failed for positive input" - + # Test zero input assert prelu(0.0) == 0.0, "Test failed for zero input" - + # Test negative input with default alpha assert prelu(-2.0) == -0.5, "Test failed for negative input with default alpha" - + # Test negative input with custom alpha - assert prelu(-2.0, alpha=0.1) == -0.2, "Test failed for negative input with custom alpha" - + assert prelu(-2.0, alpha=0.1) == -0.2, ( + "Test failed for negative input with custom alpha" + ) + # Test with alpha = 0 (behaves like ReLU) assert prelu(-2.0, alpha=0.0) == 0.0, "Test failed for ReLU behavior" - + # Test with alpha = 1 (behaves like linear function) assert prelu(-2.0, alpha=1.0) == -2.0, "Test failed for linear behavior" + if __name__ == "__main__": test_prelu() print("All PReLU tests passed.") diff --git a/old_repo/Problems/99_Softplus/solution.py b/old_repo/Problems/99_Softplus/solution.py index 01ae35ad..38b92a14 100644 --- a/old_repo/Problems/99_Softplus/solution.py +++ b/old_repo/Problems/99_Softplus/solution.py @@ -1,12 +1,13 @@ import math + def softplus(x: float) -> float: """ Compute the softplus activation function. - + Args: x: Input value - + Returns: The softplus value: log(1 + e^x) """ @@ -16,25 +17,27 @@ def softplus(x: float) -> float: # To prevent underflow for large negative values if x < -100: return 0.0 - + return math.log(1.0 + math.exp(x)) + def test_softplus(): # Test case 1: x = 0 assert abs(softplus(0) - math.log(2)) < 1e-6, "Test case 1 failed" - + # Test case 2: large positive number assert abs(softplus(100) - 100) < 1e-6, "Test case 2 failed" - + # Test case 3: large negative number assert abs(softplus(-100)) < 1e-6, "Test case 3 failed" - + # Test case 4: positive number assert abs(softplus(2) - 2.1269280110429727) < 1e-6, "Test case 4 failed" - + # Test case 5: negative number assert abs(softplus(-2) - 0.12692801104297272) < 1e-6, "Test case 5 failed" + if __name__ == "__main__": test_softplus() - print("All Softplus tests passed.") \ No newline at end of file + print("All Softplus tests passed.") diff --git a/old_repo/Problems/9_matrixmul/solution.py b/old_repo/Problems/9_matrixmul/solution.py index 0df31c2a..6e682e4e 100644 --- a/old_repo/Problems/9_matrixmul/solution.py +++ b/old_repo/Problems/9_matrixmul/solution.py @@ -1,7 +1,9 @@ -def matrixmul(a: list[list[int | float]], b: list[list[int | float]]) -> list[list[int | float]]: +def matrixmul( + a: list[list[int | float]], b: list[list[int | float]] +) -> list[list[int | float]]: if len(a[0]) != len(b): return -1 - + vals = [] for i in range(len(a)): hold = [] @@ -9,12 +11,13 @@ def matrixmul(a: list[list[int | float]], b: list[list[int | float]]) -> list[li val = 0 for k in range(len(b)): val += a[i][k] * b[k][j] - + hold.append(val) vals.append(hold) return vals + def test_matrixmul() -> None: # Test cases for matrixmul function @@ -33,6 +36,7 @@ def test_matrixmul() -> None: b = [[0, 0, 1], [2, 4, 1], [1, 2, 3]] assert matrixmul(a, b) == -1 + if __name__ == "__main__": test_matrixmul() print("All matrixmul tests passed.") diff --git a/old_repo/Problems/BM25/solution.py b/old_repo/Problems/BM25/solution.py index 1ad78176..e2d9fd0e 100644 --- a/old_repo/Problems/BM25/solution.py +++ b/old_repo/Problems/BM25/solution.py @@ -1,89 +1,79 @@ import numpy as np from collections import Counter + def calculate_bm25_scores(corpus, query, k1=1.5, b=0.75): if not corpus or not query: raise ValueError("Corpus and query cannot be empty") - + doc_lengths = [len(doc) for doc in corpus] avg_doc_length = np.mean(doc_lengths) doc_term_counts = [Counter(doc) for doc in corpus] doc_freqs = Counter() for doc in corpus: doc_freqs.update(set(doc)) - + scores = np.zeros(len(corpus)) N = len(corpus) - + for term in query: df = doc_freqs.get(term, 0) + 1 idf = np.log((N + 1) / df) - + for idx, term_counts in enumerate(doc_term_counts): if term not in term_counts: continue - + tf = term_counts[term] doc_len_norm = 1 - b + b * (doc_lengths[idx] / avg_doc_length) term_score = (tf * (k1 + 1)) / (tf + k1 * doc_len_norm) scores[idx] += idf * term_score - + return np.round(scores, 3) + def test_bm25_scores(): # Test case 1 - corpus = [ - ["the", "cat", "sat"], - ["the", "dog", "ran"], - ["the", "bird", "flew"] - ] + corpus = [["the", "cat", "sat"], ["the", "dog", "ran"], ["the", "bird", "flew"]] query = ["the", "cat"] scores = calculate_bm25_scores(corpus, query) expected_scores = np.array([2.283, 1.386, 1.386]) np.testing.assert_array_almost_equal(scores, expected_scores, decimal=3) - + # Test case 2 try: calculate_bm25_scores([], ["test"]) assert False, "Should raise error for empty corpus" except ValueError: pass - + try: calculate_bm25_scores([["test"]], []) assert False, "Should raise error for empty query" except ValueError: pass - + # Test case 3 - corpus = [ - ["the"] * 10, - ["the"] - ] + corpus = [["the"] * 10, ["the"]] query = ["the"] scores = calculate_bm25_scores(corpus, query) assert scores[1] > scores[0], "Shorter document should score higher for same term" - + # Test case 4 - corpus = [ - ["term"] * 10, - ["term"] * 2 - ] + corpus = [["term"] * 10, ["term"] * 2] query = ["term"] scores = calculate_bm25_scores(corpus, query, k1=1.0) expected_scores = np.array([0.579, 0.763]) np.testing.assert_array_almost_equal(scores, expected_scores, decimal=3) - + # Test case 5 - corpus = [ - ["the"] * 10, - ["the"] - ] + corpus = [["the"] * 10, ["the"]] query = ["the"] scores = calculate_bm25_scores(corpus, query) expected_scores = np.array([0.446, 0.893]) np.testing.assert_array_almost_equal(scores, expected_scores, decimal=3) - + + if __name__ == "__main__": test_bm25_scores() print("All test cases passed!") diff --git a/old_repo/Problems/MAE/solution.py b/old_repo/Problems/MAE/solution.py index d9bbfcf6..1baff5f1 100644 --- a/old_repo/Problems/MAE/solution.py +++ b/old_repo/Problems/MAE/solution.py @@ -1,13 +1,14 @@ import numpy as np + def mae(y_true, y_pred): """ Calculate Mean Absolute Error between two arrays. - + Parameters: y_true (numpy.ndarray): Array of true values y_pred (numpy.ndarray): Array of predicted values - + Returns: float: Mean Absolute Error rounded to 3 decimal places """ @@ -15,9 +16,10 @@ def mae(y_true, y_pred): raise ValueError("Arrays must have the same shape") if y_true.size == 0: raise ValueError("Arrays cannot be empty") - + return round(np.mean(np.abs(y_true - y_pred)), 3) + def test_mae(): # Test Case 1: Normal Case y_true1 = np.array([3, -0.5, 2, 7]) @@ -66,6 +68,7 @@ def test_mae(): expected7 = 1.333 assert mae(y_true7, y_pred7) == expected7, "Test Case 7 Failed" + if __name__ == "__main__": test_mae() - print("All Test Cases Passed!") \ No newline at end of file + print("All Test Cases Passed!") diff --git a/old_repo/Problems/interactive_learn/problem-10/notebook.py b/old_repo/Problems/interactive_learn/problem-10/notebook.py index f3d70298..df3ac6db 100644 --- a/old_repo/Problems/interactive_learn/problem-10/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-10/notebook.py @@ -79,9 +79,9 @@ def _(insights): def _(mo): # Key concepts accordion - - insights = mo.accordion({ - "🎯 Understanding Covariance": mo.md(""" + insights = mo.accordion( + { + "🎯 Understanding Covariance": mo.md(""" **Key Concepts:** 1. **Variance**: Measures spread of a single variable @@ -92,8 +92,7 @@ def _(mo): 4. **Interpretation**: Direction and strength of relationships """), - - "📊 Matrix Properties": mo.md(""" + "📊 Matrix Properties": mo.md(""" The covariance matrix has important properties: 1. **Symmetry**: cov(X,Y) = cov(Y,X) @@ -103,8 +102,9 @@ def _(mo): 3. **Off-diagonal Elements**: Show relationships 4. **Positive Semi-definite**: All eigenvalues ≥ 0 - """) - }) + """), + } + ) return (insights,) @@ -128,11 +128,13 @@ def _(Matrix, mo): matrix=[[1, 2, 3], [4, 5, 6]], # default example data rows=2, cols=3, - step=0.1 + step=0.1, + ) + input_controls = mo.hstack( + [ + data_matrix, + ] ) - input_controls = mo.hstack([ - data_matrix, - ]) return data_matrix, input_controls @@ -158,48 +160,43 @@ def _(calculate_button, data_matrix, mo, np, pd, px): cov_matrix = np.cov(data) # 3. visualization with covariance matrix - df = pd.DataFrame({ - 'x': data[0], - 'y': data[1] - }) + df = pd.DataFrame({"x": data[0], "y": data[1]}) scatter_fig = px.scatter( df, - x='x', - y='y', + x="x", + y="y", title="Variable Relationship Pattern", - labels={'x': 'Variable 1', 'y': 'Variable 2'} - ).update_layout( - width=400, - height=400, - showlegend=False - ) + labels={"x": "Variable 1", "y": "Variable 2"}, + ).update_layout(width=400, height=400, showlegend=False) # appropriate trendline coeffs = np.polyfit(data[0], data[1], 1) x_range = np.linspace(min(data[0]), max(data[0]), 100) scatter_fig.add_trace( dict( - type='scatter', + type="scatter", x=x_range, y=coeffs[0] * x_range + coeffs[1], - mode='lines', - line=dict(color='red', dash='dash'), - name='Trend' + mode="lines", + line=dict(color="red", dash="dash"), + name="Trend", ) ) # 4. results with relevant explanations - results = mo.vstack([ - mo.md("## Understanding Your Data's Covariance"), - - # First row: Plot and Matrix - mo.hstack([ - # scatter plot - mo.vstack([scatter_fig]), - - # covariance matrix - mo.vstack([ - mo.md(r""" + results = mo.vstack( + [ + mo.md("## Understanding Your Data's Covariance"), + # First row: Plot and Matrix + mo.hstack( + [ + # scatter plot + mo.vstack([scatter_fig]), + # covariance matrix + mo.vstack( + [ + mo.md( + r""" **Covariance Matrix:** $$ @@ -208,18 +205,24 @@ def _(calculate_button, data_matrix, mo, np, pd, px): %.2f & %.2f \end{pmatrix} $$ - """ % ( - cov_matrix[0,0], cov_matrix[0,1], - cov_matrix[1,0], cov_matrix[1,1] - )) - ]) - ]), - - # interpretation and insights side by side - mo.hstack([ - # Left: Pattern Interpretation - mo.callout( - mo.md(""" + """ + % ( + cov_matrix[0, 0], + cov_matrix[0, 1], + cov_matrix[1, 0], + cov_matrix[1, 1], + ) + ) + ] + ), + ] + ), + # interpretation and insights side by side + mo.hstack( + [ + # Left: Pattern Interpretation + mo.callout( + mo.md(""" **Pattern Interpretation:** @@ -235,20 +238,19 @@ def _(calculate_button, data_matrix, mo, np, pd, px): - Off-diagonal: Show relationship strength """), - kind="info" - ), - - # Right: Key Insights - mo.callout( - mo.md(f""" + kind="info", + ), + # Right: Key Insights + mo.callout( + mo.md(f""" **Key Insights:** - 1. Relationship: {"Positive" if cov_matrix[0,1] > 0 else "Negative" if cov_matrix[0,1] < 0 else "No"} covariance + 1. Relationship: {"Positive" if cov_matrix[0, 1] > 0 else "Negative" if cov_matrix[0, 1] < 0 else "No"} covariance - 2. Strength: {"Strong" if abs(cov_matrix[0,1]) > 1 else "Moderate" if abs(cov_matrix[0,1]) > 0.5 else "Weak"} + 2. Strength: {"Strong" if abs(cov_matrix[0, 1]) > 1 else "Moderate" if abs(cov_matrix[0, 1]) > 0.5 else "Weak"} - 3. Variances: ({cov_matrix[0,0]:.2f}, {cov_matrix[1,1]:.2f}) + 3. Variances: ({cov_matrix[0, 0]:.2f}, {cov_matrix[1, 1]:.2f}) **Centered Data:** ```python @@ -258,10 +260,13 @@ def _(calculate_button, data_matrix, mo, np, pd, px): Var2: {np.round(centered_data[1], 2)} ``` """), - kind="neutral" - ) - ]) - ], justify='center') + kind="neutral", + ), + ] + ), + ], + justify="center", + ) except Exception as e: results = mo.md(f"⚠️ Error: {str(e)}").callout(kind="danger") @@ -289,9 +294,9 @@ def _(exercises): def _(mo): # Practice exercises - exercises = mo.accordion({ - - "🎯 Practice Exercises": mo.md(""" + exercises = mo.accordion( + { + "🎯 Practice Exercises": mo.md(""" Try these examples to understand covariance better: @@ -304,9 +309,7 @@ def _(mo): What do you notice about the covariance matrices? """), - - - "💡 Tips for Interpretation": mo.md(""" + "💡 Tips for Interpretation": mo.md(""" - Large positive values: Strong positive relationship @@ -316,9 +319,9 @@ def _(mo): - Diagonal values: Spread of individual variables - """) - - }) + """), + } + ) return (exercises,) @@ -331,9 +334,10 @@ def _(conclusion): @app.cell(hide_code=True) def _(mo): # Conclusion - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've mastered the key concepts of covariance matrices: @@ -344,12 +348,11 @@ def _(mo): - The importance of centered data """), - kind="success" - ), - - mo.accordion({ - - "🚀 Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "🚀 Next Steps": mo.md(""" 1. Explore correlation matrices (normalized covariance) 2. Apply to real-world datasets @@ -357,14 +360,17 @@ def _(mo): 4. Implement in machine learning projects """) - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(): import marimo as mo + return (mo,) @@ -374,6 +380,7 @@ def _(): import plotly.express as px from wigglystuff import Matrix import pandas as pd + return Matrix, np, pd, px diff --git a/old_repo/Problems/interactive_learn/problem-17/notebook.py b/old_repo/Problems/interactive_learn/problem-17/notebook.py index 917799a6..6db4cc65 100644 --- a/old_repo/Problems/interactive_learn/problem-17/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-17/notebook.py @@ -13,18 +13,20 @@ import marimo __generated_with = "0.10.12" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) def _(mo): mo.md( - f"""# Understanding K-means Clustering + """# Understanding K-means Clustering ## Overview K-means clustering is an [unsupervised learning algorithm](https://en.wikipedia.org/wiki/Unsupervised_learning) that partitions data into k distinct clusters. Each cluster is characterized by its centroid - the mean position of all points in that cluster. """ - ) + ) return @@ -36,8 +38,9 @@ def _(intro): @app.cell(hide_code=True) def _(mo): - intro = mo.accordion({ - "🔄 Algorithm Steps": mo.md(""" + intro = mo.accordion( + { + "🔄 Algorithm Steps": mo.md(""" 1. **Initialization**: Randomly place k centroids in the feature space 2. **Assignment**: Assign each point to the nearest centroid using Euclidean distance (or a suitable distance metric like Manhattan (City Block distance), Minkowski distance, etc.): @@ -48,7 +51,7 @@ def _(mo): 3. **Update**: Recompute centroids as the mean of assigned points 4. **Repeat**: Steps 2-3 until convergence """), - "📐 Mathematical Formulation": mo.md(""" + "📐 Mathematical Formulation": mo.md(""" The objective function (inertia) that K-means minimizes: \\[ @@ -58,15 +61,16 @@ def _(mo): where: - $x_i$ is the i-th data point - $\\mu_j$ is the centroid of cluster $j$ - """) - }) + """), + } + ) return (intro,) @app.cell(hide_code=True) def _(mo): - mo.md(f""" + mo.md(""" ## Implementation Details This implementation uses: @@ -86,7 +90,8 @@ def _(implementation): @app.cell(hide_code=True) def _(mo): - implementation = mo.accordion({ + implementation = mo.accordion( + { "⚙️ Key Parameters": mo.md(""" - **n_clusters**: Number of clusters (k) - **init**: Initialization method ('k-means++' or 'random') @@ -94,16 +99,15 @@ def _(mo): - **tol**: Tolerance for declaring convergence (default=1e-4) - **n_init**: Number of initializations to try (default=10) """) - }) + } + ) return (implementation,) @app.cell def _(mo): method = mo.ui.dropdown( - options=["Random", "Manual"], - value="Random", - label="Generation Method" + options=["Random", "Manual"], value="Random", label="Generation Method" ) return (method,) @@ -161,7 +165,6 @@ def _(mo): def _(np, random, random_button): random_button - def _generate_data(): n_clusters = random.randint(2, 10) np.random.randn() @@ -174,7 +177,6 @@ def _generate_data(): ) return np.vstack(points) - generated_points = _generate_data() return (generated_points,) @@ -479,6 +481,7 @@ def _(callout): @app.cell def _(): import marimo as mo + return (mo,) @@ -491,6 +494,7 @@ def _(): from sklearn.cluster import KMeans import plotly.express as px from drawdata import ScatterWidget + return KMeans, ScatterWidget, np, pd, px, random diff --git a/old_repo/Problems/interactive_learn/problem-22/notebook.py b/old_repo/Problems/interactive_learn/problem-22/notebook.py index 5b05fef4..dbde9e0b 100644 --- a/old_repo/Problems/interactive_learn/problem-22/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-22/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.10" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -44,18 +46,14 @@ def _(mo): - Differentiable everywhere """) - mo.accordion({"### Mathematical Definition" : value}) + mo.accordion({"### Mathematical Definition": value}) return (value,) @app.cell def _(mo): steepness = mo.ui.slider( - start=0.1, - stop=5.0, - value=1.0, - step=0.1, - label="Steepness Factor (β)" + start=0.1, stop=5.0, value=1.0, step=0.1, label="Steepness Factor (β)" ) _callout = mo.callout( @@ -70,62 +68,62 @@ def _(mo): - This affects how quickly the function transitions from 0 to 1 """), - kind="info" + kind="info", ) x_range = mo.ui.range_slider( - start=-10, - stop=10, - step=0.5, - value=[-5, 5], - label="X-axis Range" + start=-10, stop=10, step=0.5, value=[-5, 5], label="X-axis Range" ) - controls = mo.vstack([ - mo.md("### Adjust Parameters"), - mo.hstack([ - mo.vstack([ - steepness, - mo.accordion({ - "About Steepness": _callout - }) - ]), - mo.vstack([ - x_range, - mo.accordion({ - "About Range": "Adjust to see different regions of the S-shaped curve." - }) - ]) - ]) - ]) + controls = mo.vstack( + [ + mo.md("### Adjust Parameters"), + mo.hstack( + [ + mo.vstack([steepness, mo.accordion({"About Steepness": _callout})]), + mo.vstack( + [ + x_range, + mo.accordion( + { + "About Range": "Adjust to see different regions of the S-shaped curve." + } + ), + ] + ), + ] + ), + ] + ) return controls, steepness, x_range @app.cell def _(mo): test_input = mo.ui.number( - value=0.0, - start=-10, - stop=10, - step=0.1, - label="Test Input Value" + value=0.0, start=-10, stop=10, step=0.1, label="Test Input Value" ) - input_controls = mo.vstack([ - mo.md("### Test Specific Values"), - test_input, - mo.accordion({ - "About Testing": "Enter specific values to see their Sigmoid outputs (always between 0 and 1)." - }) - ]) + input_controls = mo.vstack( + [ + mo.md("### Test Specific Values"), + test_input, + mo.accordion( + { + "About Testing": "Enter specific values to see their Sigmoid outputs (always between 0 and 1)." + } + ), + ] + ) return input_controls, test_input @app.cell def _(mo, steepness): - formula_display = mo.vstack([ - mo.md( - f""" + formula_display = mo.vstack( + [ + mo.md( + f""" ### Current Sigmoid Configuration With steepness parameter $\\beta = {steepness.value:.2f}$, the current Sigmoid function is: @@ -142,8 +140,9 @@ def _(mo, steepness): - As z → -∞, σ(z) → 0 """ - ), - ]) + ), + ] + ) return (formula_display,) @@ -158,7 +157,9 @@ def _(mo, np, plt, steepness, test_input, x_range): @mo.cache(pin_modules=True) def plot_sigmoid(): if x_range.value[0] >= x_range.value[1]: - raise ValueError("Invalid x_range: start value must be less than stop value.") + raise ValueError( + "Invalid x_range: start value must be less than stop value." + ) x = np.linspace(x_range.value[0], x_range.value[1], 1000) y = 1 / (1 + np.exp(-steepness.value * x)) @@ -166,42 +167,56 @@ def plot_sigmoid(): plt.figure(figsize=(12, 7)) # Plot main sigmoid curve - plt.plot(x, y, - label=f'Sigmoid (β = {steepness.value:.2f})', - color='blue', - linewidth=2) + plt.plot( + x, + y, + label=f"Sigmoid (β = {steepness.value:.2f})", + color="blue", + linewidth=2, + ) # Plot horizontal asymptotes - plt.axhline(y=1, color='gray', linestyle='--', alpha=0.5, label='Upper Asymptote (y=1)') - plt.axhline(y=0, color='gray', linestyle='--', alpha=0.5, label='Lower Asymptote (y=0)') + plt.axhline( + y=1, color="gray", linestyle="--", alpha=0.5, label="Upper Asymptote (y=1)" + ) + plt.axhline( + y=0, color="gray", linestyle="--", alpha=0.5, label="Lower Asymptote (y=0)" + ) # Plot midpoint - plt.plot([0], [0.5], 'ro', label='Midpoint (0, 0.5)') + plt.plot([0], [0.5], "ro", label="Midpoint (0, 0.5)") # Plot test point if within range if x_range.value[0] <= test_input.value <= x_range.value[1]: test_output = 1 / (1 + np.exp(-steepness.value * test_input.value)) - plt.scatter([test_input.value], [test_output], - color='green', s=100, - label=f'Test point: σ({test_input.value:.2f}) = {test_output:.4f}') + plt.scatter( + [test_input.value], + [test_output], + color="green", + s=100, + label=f"Test point: σ({test_input.value:.2f}) = {test_output:.4f}", + ) plt.grid(True, alpha=0.3) - plt.title(f'Sigmoid Function (β = {steepness.value:.2f})') - plt.xlabel('Input (z)') - plt.ylabel('Output (σ(z))') - plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') + plt.title(f"Sigmoid Function (β = {steepness.value:.2f})") + plt.xlabel("Input (z)") + plt.ylabel("Output (σ(z))") + plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") # Add vertical zero line - plt.axvline(x=0, color='k', linestyle='--', alpha=0.3) + plt.axvline(x=0, color="k", linestyle="--", alpha=0.3) # Set y-axis limits with some padding plt.ylim(-0.1, 1.1) - plot_display = mo.vstack([ - mo.as_html(plt.gca()), - ]) + plot_display = mo.vstack( + [ + mo.as_html(plt.gca()), + ] + ) return plot_display + return (plot_sigmoid,) @@ -225,9 +240,10 @@ def _(plot_sigmoid): @app.cell def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the Sigmoid function interactively. You've learned: @@ -236,30 +252,33 @@ def _(mo): - Why it's useful for binary classification - Its symmetric properties around the midpoint """), - kind="success" - ), - mo.accordion({ - "Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "Next Steps": mo.md(""" 1. **Implementation:** Try implementing Sigmoid from scratch 2. **Compare:** Explore how it differs from tanh and softmax 3. **Practice:** Use it in a binary classification task 4. **Advanced:** Learn about vanishing gradient problems """), - "🎯 Common Applications": mo.md(""" + "🎯 Common Applications": mo.md(""" - Binary classification output layers - Logistic regression - Neural network hidden layers (historically) - Probability estimation - Feature scaling between 0 and 1 """), - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(mo): - mo.md(f""" + mo.md(""" This interactive learning experience was designed to help you understand the Sigmoid activation function. Hope this helps in your deep learning journey! """) return @@ -274,6 +293,7 @@ def _(conclusion): @app.cell def _(): import marimo as mo + return (mo,) @@ -281,6 +301,7 @@ def _(): def _(): import numpy as np import matplotlib.pyplot as plt + return np, plt diff --git a/old_repo/Problems/interactive_learn/problem-23/notebook.py b/old_repo/Problems/interactive_learn/problem-23/notebook.py index ffc4d120..d83c5097 100644 --- a/old_repo/Problems/interactive_learn/problem-23/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-23/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.9" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -38,7 +40,7 @@ def _(mo): where $i$ ranges from 1 to $n$, and each output $\text{softmax}(z_i)$ represents the probability of class $i$. """) - mo.accordion({"### Mathematical Definition" : value}) + mo.accordion({"### Mathematical Definition": value}) return (value,) @@ -46,19 +48,11 @@ def _(mo): def _(mo): # Interactive elements for formula exploration temperature = mo.ui.slider( - start=0.5, - stop=5.0, - value=1.0, - step=0.1, - label="Temperature (τ)" + start=0.5, stop=5.0, value=1.0, step=0.1, label="Temperature (τ)" ) vector_size = mo.ui.slider( - start=2, - stop=5, - value=3, - step=1, - label="Vector Size (n)" + start=2, stop=5, value=3, step=1, label="Vector Size (n)" ) _callout = mo.callout( @@ -71,47 +65,64 @@ def _(mo): - Lower temperature amplifies differences between inputs """), - kind="info" + kind="info", + ) + controls = mo.vstack( + [ + mo.md("### Adjust Parameters"), + mo.hstack( + [ + mo.vstack( + [temperature, mo.accordion({"About Temperature": _callout})] + ), + mo.vstack( + [ + vector_size, + mo.accordion( + { + "About Vector Size": "Change to see how Softmax handles different input dimensions." + } + ), + ] + ), + ] + ), + ] ) - controls = mo.vstack([ - mo.md("### Adjust Parameters"), - mo.hstack([ - mo.vstack([ - temperature, - mo.accordion({ - "About Temperature": _callout - }) - ]), - mo.vstack([ - vector_size, - mo.accordion({ - "About Vector Size": "Change to see how Softmax handles different input dimensions." - }) - ]) - ]) - ]) return controls, temperature, vector_size @app.cell def _(array_nums, mo, x_range): - input_controls = mo.vstack([ - mo.md("### Input Values"), - mo.hstack([ - mo.vstack([ - x_range, - mo.accordion({ - "About Range": "Adjust the range of input values shown in the plot." - }) - ]), - mo.vstack([ - array_nums, - mo.accordion({ - "About Inputs": "Set specific input values to see their Softmax probabilities." - }) - ]) - ]) - ]) + input_controls = mo.vstack( + [ + mo.md("### Input Values"), + mo.hstack( + [ + mo.vstack( + [ + x_range, + mo.accordion( + { + "About Range": "Adjust the range of input values shown in the plot." + } + ), + ] + ), + mo.vstack( + [ + array_nums, + mo.accordion( + { + "About Inputs": "Set specific input values to see their Softmax probabilities." + } + ), + ] + ), + ] + ), + ] + ) return (input_controls,) @@ -123,9 +134,10 @@ def _(formula_display): @app.cell def _(mo, temperature, vector_size): - formula_display = mo.vstack([ - mo.md( - f""" + formula_display = mo.vstack( + [ + mo.md( + f""" ### Temperature-Scaled Softmax With temperature parameter $\\tau = {temperature.value:.1f}$ and vector size $n = {vector_size.value}$, @@ -139,8 +151,9 @@ def _(mo, temperature, vector_size): - Lower temperature ($\\tau < 1$) makes the distribution more peaked """ - ), - ]) + ), + ] + ) return (formula_display,) @@ -148,22 +161,12 @@ def _(mo, temperature, vector_size): def _(mo, vector_size): # Input range control x_range = mo.ui.range_slider( - start=-10, - stop=10, - step=0.5, - value=[-5, 5], - label="X-axis Range" + start=-10, stop=10, step=0.5, value=[-5, 5], label="X-axis Range" ) # Array of number inputs dynamically based on vector_size input_numbers = [ - mo.ui.number( - value=1.0, - start=-10, - stop=10, - step=0.1, - label=f"Value {i+1}" - ) + mo.ui.number(value=1.0, start=-10, stop=10, step=0.1, label=f"Value {i + 1}") for i in range(vector_size.value) ] @@ -175,7 +178,7 @@ def _(mo, vector_size): ### Sample Input Values Current vector: {inputs} """), - {"inputs": array_nums} + {"inputs": array_nums}, ) return array_nums, input_numbers, input_values, x_range @@ -193,7 +196,9 @@ def _(array_nums, mo, np, plt, temperature, vector_size, x_range): def plot_softmax(): # Validate x_range if x_range.value[0] >= x_range.value[1]: - raise ValueError("Invalid x_range: start value must be less than stop value.") + raise ValueError( + "Invalid x_range: start value must be less than stop value." + ) x = np.linspace(x_range.value[0], x_range.value[1], 1000) scores = np.vstack([x] + [np.zeros_like(x)] * (vector_size.value - 1)) @@ -205,33 +210,36 @@ def plot_softmax(): plt.figure(figsize=(12, 7)) for i in range(vector_size.value): - plt.plot(x, softmax_values[i], - label=f'Class {i+1}', - linewidth=2) + plt.plot(x, softmax_values[i], label=f"Class {i + 1}", linewidth=2) # Plot current input values input_array = np.array([num.value for num in array_nums.elements]) if len(input_array) >= vector_size.value: - exp_inputs = np.exp(input_array[:vector_size.value] / temperature.value) + exp_inputs = np.exp(input_array[: vector_size.value] / temperature.value) softmax_inputs = exp_inputs / np.sum(exp_inputs) - plt.scatter(input_array[:vector_size.value], - softmax_inputs, - c='red', - s=100, - label='Current inputs') + plt.scatter( + input_array[: vector_size.value], + softmax_inputs, + c="red", + s=100, + label="Current inputs", + ) plt.grid(True, alpha=0.3) - plt.title(f'Softmax Function (τ = {temperature.value:.1f})') - plt.xlabel('Input values (z)') - plt.ylabel('Softmax probabilities') - plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') + plt.title(f"Softmax Function (τ = {temperature.value:.1f})") + plt.xlabel("Input values (z)") + plt.ylabel("Softmax probabilities") + plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") plt.ylim(-0.1, 1.1) - plot_display = mo.vstack([ - mo.as_html(plt.gca()), - ]) + plot_display = mo.vstack( + [ + mo.as_html(plt.gca()), + ] + ) return plot_display + return (plot_softmax,) @@ -255,9 +263,10 @@ def _(plot_softmax): @app.cell def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the Softmax function interactively. You've learned: @@ -267,30 +276,33 @@ def _(mo): - How different input values affect the output distribution """), - kind="success" - ), - mo.accordion({ - "Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "Next Steps": mo.md(""" 1. **Problem solving:** Head over to the Problem Decsription tab and start solving the problem! 2. **Apply**: Think about where you might use Softmax in your own projects 3. **Explore**: Learn about variants like Sparsemax and Gumbel-Softmax 4. **Practice**: Implement Softmax from scratch in your preferred framework """), - " 🎯 Common Applications": mo.md(""" + " 🎯 Common Applications": mo.md(""" - Classification layers in neural networks - Attention mechanisms in transformers - Policy networks in reinforcement learning - Knowledge distillation - Temperature scaling for model calibration """), - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(mo): - mo.md(f""" + mo.md(""" This interactive learning experience was designed to help you understand the Softmax activation function. Hope this resource proves valuable in your exploration of this important topic. """) return @@ -307,6 +319,7 @@ def _(): import marimo as mo import numpy as np import matplotlib.pyplot as plt + return mo, np, plt diff --git a/old_repo/Problems/interactive_learn/problem-24/notebook.py b/old_repo/Problems/interactive_learn/problem-24/notebook.py index afd62677..cc0b4a9f 100644 --- a/old_repo/Problems/interactive_learn/problem-24/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-24/notebook.py @@ -65,8 +65,9 @@ def _(insights): @app.cell(hide_code=True) def _(mo): # insights accordion - insights = mo.accordion({ - "🧠 Understanding the Components": mo.md(""" + insights = mo.accordion( + { + "🧠 Understanding the Components": mo.md(""" **Key Concepts:** 1. **Input Features**: Multiple numerical values representing different aspects of the data @@ -74,16 +75,16 @@ def _(mo): 3. **Bias**: Offset term that helps the model fit the data better 4. **Sigmoid Function**: Squashes input to probability between 0 and 1 """), - - "📊 Model Behavior": mo.md(""" + "📊 Model Behavior": mo.md(""" The neuron's behavior is influenced by: 1. **Feature Values**: Input data characteristics 2. **Weight Magnitudes**: Control feature influence 3. **Bias Term**: Shifts the decision boundary 4. **Sigmoid Activation**: Creates non-linear output - """) - }) + """), + } + ) return (insights,) @@ -96,38 +97,39 @@ def _(feature_inputs): @app.cell(hide_code=True) def _(mo): # input controls: features - features_1 = mo.ui.array([ - mo.ui.number(value=0.5, label="Feature 1", step=0.1), - mo.ui.number(value=1.0, label="Feature 2", step=0.1) - ]) - - features_2 = mo.ui.array([ - mo.ui.number(value=-1.5, label="Feature 1", step=0.1), - mo.ui.number(value=-2.0, label="Feature 2", step=0.1) - ]) - - features_3 = mo.ui.array([ - mo.ui.number(value=2.0, label="Feature 1", step=0.1), - mo.ui.number(value=1.5, label="Feature 2", step=0.1) - ]) - - feature_inputs = mo.vstack([ - mo.md("### Input Features"), - mo.hstack([ - mo.vstack([ - mo.md("**Example 1**"), - features_1 - ]), - mo.vstack([ - mo.md("**Example 2**"), - features_2 - ]), - mo.vstack([ - mo.md("**Example 3**"), - features_3 - ]) - ]) - ]) + features_1 = mo.ui.array( + [ + mo.ui.number(value=0.5, label="Feature 1", step=0.1), + mo.ui.number(value=1.0, label="Feature 2", step=0.1), + ] + ) + + features_2 = mo.ui.array( + [ + mo.ui.number(value=-1.5, label="Feature 1", step=0.1), + mo.ui.number(value=-2.0, label="Feature 2", step=0.1), + ] + ) + + features_3 = mo.ui.array( + [ + mo.ui.number(value=2.0, label="Feature 1", step=0.1), + mo.ui.number(value=1.5, label="Feature 2", step=0.1), + ] + ) + + feature_inputs = mo.vstack( + [ + mo.md("### Input Features"), + mo.hstack( + [ + mo.vstack([mo.md("**Example 1**"), features_1]), + mo.vstack([mo.md("**Example 2**"), features_2]), + mo.vstack([mo.md("**Example 3**"), features_3]), + ] + ), + ] + ) return feature_inputs, features_1, features_2, features_3 @@ -140,29 +142,18 @@ def _(weight_controls): @app.cell(hide_code=True) def _(mo): # Weight and bias (wandb) controls - w1 = mo.ui.number( - value=0.7, - label="Weight 1", - step=0.1 - ) + w1 = mo.ui.number(value=0.7, label="Weight 1", step=0.1) - w2 = mo.ui.number( - value=-0.4, - label="Weight 2", - step=0.1 - ) + w2 = mo.ui.number(value=-0.4, label="Weight 2", step=0.1) - bias = mo.ui.number( - value=-0.1, - label="Bias", - step=0.1 - ) + bias = mo.ui.number(value=-0.1, label="Bias", step=0.1) - weight_controls = mo.vstack([ - mo.md("### Model Parameters"), - mo.hstack([w1, w2, bias]), - mo.callout( - mo.md(""" + weight_controls = mo.vstack( + [ + mo.md("### Model Parameters"), + mo.hstack([w1, w2, bias]), + mo.callout( + mo.md(""" Adjust weights and bias to see how they affect the neuron's output: - Positive weights increase output for positive features @@ -171,9 +162,10 @@ def _(mo): - Bias shifts the decision boundary """), - kind="info" - ) - ]) + kind="info", + ), + ] + ) return bias, w1, w2, weight_controls @@ -208,7 +200,7 @@ def _( w2, ): def sigmoid(z): - return 1 / (1 + np.exp(-z)) + return 1 / (1 + np.exp(-z)) def compute_neuron_output(features, weights, bias): z = np.dot(features, weights) + bias @@ -226,7 +218,7 @@ def compute_neuron_output(features, weights, bias): feature_vectors = [ [f.value for f in features_1.elements], [f.value for f in features_2.elements], - [f.value for f in features_3.elements] + [f.value for f in features_3.elements], ] predictions = [] @@ -238,18 +230,22 @@ def compute_neuron_output(features, weights, bias): mse = round(np.mean((np.array(predictions) - true_labels) ** 2), 4) results = predictions - results_display = mo.vstack([ - mo.md(f"### Results"), - mo.md(f"**Predictions:** {results}"), - mo.md(f"**Mean Squared Error:** {mse}"), - mo.accordion({ - "🔍 Understanding the Results": mo.md(f""" + results_display = mo.vstack( + [ + mo.md("### Results"), + mo.md(f"**Predictions:** {results}"), + mo.md(f"**Mean Squared Error:** {mse}"), + mo.accordion( + { + "🔍 Understanding the Results": mo.md(""" - Predictions close to 0 indicate class 0 - Predictions close to 1 indicate class 1 - Lower MSE means better model performance """) - }) - ]) + } + ), + ] + ) return ( compute_neuron_output, feature_vectors, @@ -289,49 +285,43 @@ def plot_decision_boundary(): # Z values calculated using the neuron model Z = 1 / (1 + np.exp(-(w1.value * X + w2.value * Y + bias.value))) - df = pd.DataFrame({ - 'x': X.flatten(), - 'y': Y.flatten(), - 'z': Z.flatten() - }) + df = pd.DataFrame({"x": X.flatten(), "y": Y.flatten(), "z": Z.flatten()}) # Plot decision boundary using density contour fig = px.density_contour( - df, x='x', y='y', z='z', - title='Decision Boundary Visualization', - labels={'x': 'Feature 1', 'y': 'Feature 2', 'z': 'Probability'} + df, + x="x", + y="y", + z="z", + title="Decision Boundary Visualization", + labels={"x": "Feature 1", "y": "Feature 2", "z": "Probability"}, ) # Add scatter points for input examples - feature_points = pd.DataFrame({ - 'Feature 1': [ - features_1.elements[0].value, - features_2.elements[0].value, - features_3.elements[0].value - ], - 'Feature 2': [ - features_1.elements[1].value, - features_2.elements[1].value, - features_3.elements[1].value - ], - 'Label': ['Example 1', 'Example 2', 'Example 3'] - }) - - scatter = px.scatter( - feature_points, - x='Feature 1', - y='Feature 2', - text='Label' + feature_points = pd.DataFrame( + { + "Feature 1": [ + features_1.elements[0].value, + features_2.elements[0].value, + features_3.elements[0].value, + ], + "Feature 2": [ + features_1.elements[1].value, + features_2.elements[1].value, + features_3.elements[1].value, + ], + "Label": ["Example 1", "Example 2", "Example 3"], + } ) + scatter = px.scatter(feature_points, x="Feature 1", y="Feature 2", text="Label") + for trace in scatter.data: fig.add_trace(trace) - fig.update_layout( - width=800, - height=600 - ) + fig.update_layout(width=800, height=600) return fig + return (plot_decision_boundary,) @@ -353,9 +343,10 @@ def _(conclusion): @app.cell(hide_code=True) def _(mo): # Conclusion and next steps - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the single neuron model with sigmoid activation. You've learned: @@ -363,29 +354,33 @@ def _(mo): - How sigmoid activation converts linear combinations to probabilities - How to evaluate performance using MSE """), - kind="success" - ), - mo.accordion({ - "🎯 Applications": mo.md(""" + kind="success", + ), + mo.accordion( + { + "🎯 Applications": mo.md(""" - Binary classification tasks - Feature importance analysis - Basic pattern recognition - Building blocks for larger neural networks """), - "🚀 Next Steps": mo.md(""" + "🚀 Next Steps": mo.md(""" 1. Implement the neuron in a real project 2. Explore other activation functions 3. Add more features to handle complex patterns 4. Learn about gradient descent for training - """) - }) - ]) + """), + } + ), + ] + ) return (conclusion,) @app.cell def _(): import marimo as mo + return (mo,) @@ -394,6 +389,7 @@ def _(): import numpy as np import pandas as pd import plotly.express as px + return np, pd, px diff --git a/old_repo/Problems/interactive_learn/problem-4/notebook.py b/old_repo/Problems/interactive_learn/problem-4/notebook.py index f5742f6c..2d622504 100644 --- a/old_repo/Problems/interactive_learn/problem-4/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-4/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.9" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -43,7 +45,7 @@ def _(column_content, mo, row_content): @app.cell(hide_code=True) def _(mo): row_content = mo.md( - r''' + r""" For a row \(i\), the sum is: \[ @@ -55,11 +57,11 @@ def _(mo): \[ \overline{R}_i = \frac{R_i}{n} \] - ''' + """ ) column_content = mo.md( - r''' + r""" For a column \(j\), the sum is: \[ @@ -71,7 +73,7 @@ def _(mo): \[ \overline{C}_j = \frac{C_j}{m} \] - ''' + """ ) return column_content, row_content @@ -110,17 +112,13 @@ def calculate_stats(matrix, dimension): if dimension == "row": sums = np.sum(arr, axis=1) means = np.mean(arr, axis=1) - labels = [f"Row {i+1}" for i in range(arr.shape[0])] + labels = [f"Row {i + 1}" for i in range(arr.shape[0])] else: sums = np.sum(arr, axis=0) means = np.mean(arr, axis=0) - labels = [f"Column {i+1}" for i in range(arr.shape[1])] + labels = [f"Column {i + 1}" for i in range(arr.shape[1])] - return { - "Dimension": labels, - "Sum": list(sums), - "Mean": list(means) - } + return {"Dimension": labels, "Sum": list(sums), "Mean": list(means)} # Calculate both row and column statistics row_stats = calculate_stats(matrix.matrix, "row") @@ -132,7 +130,6 @@ def calculate_stats(matrix, dimension): def step_by_step_display(col_stats, matrix, mo, np, row_stats): arr = np.array(matrix.matrix) - def generate_row_steps(): steps = "" for i in range(arr.shape[0]): @@ -143,12 +140,11 @@ def generate_row_steps(): steps += rf""" \[ - \text{{Row {i+1}}}: {sum_expr} = {sum_val:.1f} \text{{ (sum)}}, \frac{{{sum_val:.1f}}}{{{len(row)}}} = {mean_val:.1f} \text{{ (mean)}} + \text{{Row {i + 1}}}: {sum_expr} = {sum_val:.1f} \text{{ (sum)}}, \frac{{{sum_val:.1f}}}{{{len(row)}}} = {mean_val:.1f} \text{{ (mean)}} \] """ return mo.md(steps) - def generate_column_steps(): steps = "" for j in range(arr.shape[1]): @@ -159,12 +155,11 @@ def generate_column_steps(): steps += rf""" \[ - \text{{Column {j+1}}}: {sum_expr} = {sum_val:.1f} \text{{ (sum)}}, \frac{{{sum_val:.1f}}}{{{len(col)}}} = {mean_val:.1f} \text{{ (mean)}} + \text{{Column {j + 1}}}: {sum_expr} = {sum_val:.1f} \text{{ (sum)}}, \frac{{{sum_val:.1f}}}{{{len(col)}}} = {mean_val:.1f} \text{{ (mean)}} \] """ return mo.md(steps) - # Create tabs for row and column calculations tabs_content = { "📊 Row Operations": mo.vstack( @@ -207,6 +202,7 @@ def _(mo): @app.cell def _(): import marimo as mo + return (mo,) @@ -214,6 +210,7 @@ def _(): def _(): import numpy as np from wigglystuff import Matrix + return Matrix, np diff --git a/old_repo/Problems/interactive_learn/problem-42/notebook.py b/old_repo/Problems/interactive_learn/problem-42/notebook.py index 823308f2..91219224 100644 --- a/old_repo/Problems/interactive_learn/problem-42/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-42/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.12" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -46,11 +48,7 @@ def _(mo): @app.cell def _(mo): x_range = mo.ui.range_slider( - start=-10, - stop=10, - step=0.5, - value=[-5, 5], - label="X-axis Range" + start=-10, stop=10, step=0.5, value=[-5, 5], label="X-axis Range" ) _callout = mo.callout( @@ -63,65 +61,60 @@ def _(mo): - Positive inputs remain unchanged - This creates non-linearity in neural networks """), - kind="info" + kind="info", ) - controls = mo.vstack([ - mo.md("### Adjust Parameters"), - mo.hstack([ - mo.vstack([ - x_range, - mo.accordion({ - "About Range": _callout - }) - ]) - ]) - ]) + controls = mo.vstack( + [ + mo.md("### Adjust Parameters"), + mo.hstack([mo.vstack([x_range, mo.accordion({"About Range": _callout})])]), + ] + ) return controls, x_range @app.cell def _(mo): test_input = mo.ui.number( - value=0.0, - start=-10, - stop=10, - step=0.1, - label="Test Input Value" + value=0.0, start=-10, stop=10, step=0.1, label="Test Input Value" ) - input_controls = mo.vstack([ - mo.md("### Test Specific Values"), - test_input, - mo.accordion({ - "About Testing": "Enter specific values to see their ReLU outputs." - }) - ]) + input_controls = mo.vstack( + [ + mo.md("### Test Specific Values"), + test_input, + mo.accordion( + {"About Testing": "Enter specific values to see their ReLU outputs."} + ), + ] + ) return input_controls, test_input @app.cell def _(mo): - formula_display = mo.vstack([ - mo.md( - f""" + formula_display = mo.vstack( + [ + mo.md( + """ ### Current ReLU Configuration The ReLU function is defined as: \[ - f(z) = \max(0, z) = \\begin{{cases}} - z & \\text{{if }} z > 0 \\\\ - 0 & \\text{{if }} z \\leq 0 - \\end{{cases}} + f(z) = \max(0, z) = \\begin{cases} + z & \\text{if } z > 0 \\\\ + 0 & \\text{if } z \\leq 0 + \\end{cases} \] - For positive inputs: output = input - For negative inputs: output = 0 """ - ), - ]) + ), + ] + ) return (formula_display,) @@ -136,7 +129,9 @@ def _(mo, np, plt, test_input, x_range): @mo.cache(pin_modules=True) def plot_relu(): if x_range.value[0] >= x_range.value[1]: - raise ValueError("Invalid x_range: start value must be less than stop value.") + raise ValueError( + "Invalid x_range: start value must be less than stop value." + ) x = np.linspace(x_range.value[0], x_range.value[1], 1000) y = np.maximum(0, x) @@ -145,40 +140,53 @@ def plot_relu(): # Plot -ve region mask_neg = x <= 0 - plt.plot(x[mask_neg], y[mask_neg], - label='Zero region (ReLU = 0)', - color='red', - linewidth=2) + plt.plot( + x[mask_neg], + y[mask_neg], + label="Zero region (ReLU = 0)", + color="red", + linewidth=2, + ) # Plot +ve region mask_pos = x > 0 - plt.plot(x[mask_pos], y[mask_pos], - label='Linear region (ReLU = x)', - color='blue', - linewidth=2) + plt.plot( + x[mask_pos], + y[mask_pos], + label="Linear region (ReLU = x)", + color="blue", + linewidth=2, + ) # Plot test point if within range (expand slider if it doesn't appear) if x_range.value[0] <= test_input.value <= x_range.value[1]: test_output = max(0, test_input.value) - plt.scatter([test_input.value], [test_output], - color='green', s=100, - label=f'Test point: ReLU({test_input.value:.2f}) = {test_output:.2f}') + plt.scatter( + [test_input.value], + [test_output], + color="green", + s=100, + label=f"Test point: ReLU({test_input.value:.2f}) = {test_output:.2f}", + ) plt.grid(True, alpha=0.3) - plt.title('ReLU Function') - plt.xlabel('Input (z)') - plt.ylabel('Output (ReLU(z))') - plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') + plt.title("ReLU Function") + plt.xlabel("Input (z)") + plt.ylabel("Output (ReLU(z))") + plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") # Add zero lines - plt.axhline(y=0, color='k', linestyle='--', alpha=0.3) - plt.axvline(x=0, color='k', linestyle='--', alpha=0.3) + plt.axhline(y=0, color="k", linestyle="--", alpha=0.3) + plt.axvline(x=0, color="k", linestyle="--", alpha=0.3) - plot_display = mo.vstack([ - mo.as_html(plt.gca()), - ]) + plot_display = mo.vstack( + [ + mo.as_html(plt.gca()), + ] + ) return plot_display + return (plot_relu,) @@ -202,9 +210,10 @@ def _(plot_relu): @app.cell def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the ReLU function interactively. You've learned: @@ -213,30 +222,33 @@ def _(mo): - The relationship between input values and their corresponding outputs - How to test specific input values and observe their ReLU transformations """), - kind="success" - ), - mo.accordion({ - "Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "Next Steps": mo.md(""" 1. **Implementation:** Try implementing ReLU from scratch 2. **Compare:** Explore how it differs from other activation functions 3. **Experiment:** Test ReLU in a simple neural network 4. **Advanced:** Learn about variants like Leaky ReLU and ELU """), - "🎯 Common Applications": mo.md(""" + "🎯 Common Applications": mo.md(""" - Deep neural networks - Convolutional neural networks (CNNs) - Hidden layers in deep learning - Feature extraction - Modern computer vision models """), - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(mo): - mo.md(f""" + mo.md(""" This interactive learning experience was designed to help you understand the ReLU activation function. Hope this helps in your deep learning journey! """) return @@ -251,6 +263,7 @@ def _(conclusion): @app.cell(hide_code=True) def _(): import marimo as mo + return (mo,) @@ -258,6 +271,7 @@ def _(): def _(): import numpy as np import matplotlib.pyplot as plt + return np, plt diff --git a/old_repo/Problems/interactive_learn/problem-43/notebook.py b/old_repo/Problems/interactive_learn/problem-43/notebook.py index 0eab24c7..5b875dd1 100644 --- a/old_repo/Problems/interactive_learn/problem-43/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-43/notebook.py @@ -56,8 +56,9 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - insights = mo.accordion({ - "🔍 Key Components": mo.md(""" + insights = mo.accordion( + { + "🔍 Key Components": mo.md(""" **1. Mean Squared Error (MSE)** - Measures prediction accuracy - Penalizes larger errors more heavily @@ -68,53 +69,38 @@ def _(mo): - Prevents coefficient values from becoming too large - Helps prevent overfitting """), - - "⚙️ Role of Alpha (λ)": mo.md(""" + "⚙️ Role of Alpha (λ)": mo.md(""" The regularization parameter α controls: 1. α = 0: Equivalent to standard linear regression 2. Small α: Slight regularization effect 3. Large α: Strong regularization, coefficients approach zero """), - - "🧮 Coefficient Shrinkage": mo.md(""" + "🧮 Coefficient Shrinkage": mo.md(""" Ridge regression shrinks coefficients by adding a penalty proportional to their squared magnitude: - Larger coefficients incur higher penalties - The penalty applies to all coefficients equally - Unlike Lasso, Ridge typically keeps all features but with reduced magnitudes - Mathematically, Ridge finds the minimum of: ||y - Xβ||² + λ||β||² - """) - }) + """), + } + ) return (insights,) @app.cell(hide_code=True) def _(mo): # controls for sample data - sample_size = mo.ui.slider( - start=4, - stop=20, - value=10, - step=1, - label="Sample Size" - ) + sample_size = mo.ui.slider(start=4, stop=20, value=10, step=1, label="Sample Size") alpha = mo.ui.number( - value=0.1, - start=0, - stop=10, - step=0.1, - label="Regularization Parameter (α)" + value=0.1, start=0, stop=10, step=0.1, label="Regularization Parameter (α)" ) - controls = mo.hstack([ - mo.vstack([ - mo.md("### Data Parameters"), - sample_size, - alpha - ]) - ]) + controls = mo.hstack( + [mo.vstack([mo.md("### Data Parameters"), sample_size, alpha])] + ) return alpha, controls, sample_size @@ -132,18 +118,23 @@ def _(mo): @app.cell def _(mo): - coefficient_inputs = mo.ui.array([ - mo.ui.number(value=0.2, label="Coefficient 1", step=0.1), - mo.ui.number(value=2.0, label="Coefficient 2", step=0.1) - ], label="Model Coefficients") - - coefficient_section = mo.hstack([ - coefficient_inputs, - mo.callout( - mo.md("Adjust coefficients to see how they affect the loss value."), - kind="warn" - ) - ]) + coefficient_inputs = mo.ui.array( + [ + mo.ui.number(value=0.2, label="Coefficient 1", step=0.1), + mo.ui.number(value=2.0, label="Coefficient 2", step=0.1), + ], + label="Model Coefficients", + ) + + coefficient_section = mo.hstack( + [ + coefficient_inputs, + mo.callout( + mo.md("Adjust coefficients to see how they affect the loss value."), + kind="warn", + ), + ] + ) return coefficient_inputs, coefficient_section @@ -167,16 +158,19 @@ def ridge_loss(X, w, y_true, alpha): Returns: float: Ridge loss value """ - n_samples = X.shape[0] + X.shape[0] # Check dimension compatibility if X.shape[1] != len(w): - raise ValueError(f"Coefficient count ({len(w)}) must match feature count ({X.shape[1]})") + raise ValueError( + f"Coefficient count ({len(w)}) must match feature count ({X.shape[1]})" + ) y_pred = X @ w mse = np.mean((y_true - y_pred) ** 2) - regularization = alpha * np.sum(w ** 2) + regularization = alpha * np.sum(w**2) return mse + regularization + return (ridge_loss,) @@ -189,10 +183,9 @@ def _(mo): @app.cell def _(alpha, coefficient_inputs, mo, np, ridge_loss, sample_size): # Generate sample data - X = np.column_stack([ - np.arange(1, sample_size.value + 1), - np.ones(sample_size.value) - ]) + X = np.column_stack( + [np.arange(1, sample_size.value + 1), np.ones(sample_size.value)] + ) y_true = np.arange(2, sample_size.value + 2) w = np.array(coefficient_inputs.value) @@ -202,26 +195,26 @@ def _(alpha, coefficient_inputs, mo, np, ridge_loss, sample_size): # Calculate components for display mse_component = np.mean((y_true - X @ w) ** 2) - reg_component = alpha.value * np.sum(w ** 2) + reg_component = alpha.value * np.sum(w**2) # Display results - result_display = mo.vstack([ - mo.md("### Current Loss Value"), - mo.callout( - mo.md(f"Ridge Loss: **{current_loss:.4f}**\n\n" - f"- MSE Component: {mse_component:.4f}\n" - f"- Regularization Component: {reg_component:.4f}"), - kind="info" - ) - ]) + result_display = mo.vstack( + [ + mo.md("### Current Loss Value"), + mo.callout( + mo.md( + f"Ridge Loss: **{current_loss:.4f}**\n\n" + f"- MSE Component: {mse_component:.4f}\n" + f"- Regularization Component: {reg_component:.4f}" + ), + kind="info", + ), + ] + ) except Exception as e: - result_display = mo.vstack([ - mo.md("### Error"), - mo.callout( - mo.md(f"Error: {str(e)}"), - kind="danger" - ) - ]) + result_display = mo.vstack( + [mo.md("### Error"), mo.callout(mo.md(f"Error: {str(e)}"), kind="danger")] + ) current_loss = None return ( X, @@ -246,28 +239,39 @@ def plot_predictions(X, w, y_true): y_pred = X @ w # Use pandas DataFrame for better compatibility with plotly - df = pd.DataFrame({ - 'x': X[:, 0], - 'True Values': y_true, - 'Predictions': y_pred - }) + df = pd.DataFrame({"x": X[:, 0], "True Values": y_true, "Predictions": y_pred}) # Prepare data for plotting - plot_df = pd.melt(df, id_vars=['x'], value_vars=['True Values', 'Predictions'], - var_name='Type', value_name='Value') + plot_df = pd.melt( + df, + id_vars=["x"], + value_vars=["True Values", "Predictions"], + var_name="Type", + value_name="Value", + ) - fig = px.scatter(plot_df, x='x', y='Value', color='Type', - title='True Values vs Predictions', - labels={'Value': 'Value', 'x': 'Sample Index'}) + fig = px.scatter( + plot_df, + x="x", + y="Value", + color="Type", + title="True Values vs Predictions", + labels={"Value": "Value", "x": "Sample Index"}, + ) # Add lines connecting points - for series_name in ['True Values', 'Predictions']: - series_data = df[['x', series_name]].sort_values('x') - fig.add_scatter(x=series_data['x'], y=series_data[series_name], - mode='lines', name=f'{series_name} (line)', - line=dict(dash='dash')) + for series_name in ["True Values", "Predictions"]: + series_data = df[["x", series_name]].sort_values("x") + fig.add_scatter( + x=series_data["x"], + y=series_data[series_name], + mode="lines", + name=f"{series_name} (line)", + line=dict(dash="dash"), + ) return fig + return (plot_predictions,) @@ -284,16 +288,19 @@ def _(X, mo, plot_predictions, visualize_button, w, y_true): try: plot_results = plot_predictions(X, w, y_true) except Exception as e: - plot_results = mo.md(f"Error generating plot: {str(e)}").callout(kind="danger") + plot_results = mo.md(f"Error generating plot: {str(e)}").callout( + kind="danger" + ) plot_results return (plot_results,) @app.cell(hide_code=True) def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the Ridge Regression loss function interactively. Key takeaways: @@ -302,23 +309,26 @@ def _(mo): - How coefficients affect predictions and loss - How Ridge regression shrinks coefficients toward zero """), - kind="success" - ), - mo.accordion({ - "🎯 Applications": mo.md(""" + kind="success", + ), + mo.accordion( + { + "🎯 Applications": mo.md(""" - High-dimensional data analysis - Feature selection - Preventing overfitting in linear models - Multicollinearity handling """), - "🚀 Next Steps": mo.md(""" + "🚀 Next Steps": mo.md(""" 1. Implement gradient descent optimization 2. Compare with Lasso regression 3. Explore cross-validation for α selection 4. Apply to real-world datasets - """) - }) - ]) + """), + } + ), + ] + ) return (conclusion,) @@ -331,6 +341,7 @@ def _(conclusion): @app.cell def _(): import marimo as mo + return (mo,) @@ -339,6 +350,7 @@ def _(): import numpy as np import plotly.express as px import pandas as pd + return np, pd, px diff --git a/old_repo/Problems/interactive_learn/problem-44/notebook.py b/old_repo/Problems/interactive_learn/problem-44/notebook.py index 2a935df2..fb44c687 100644 --- a/old_repo/Problems/interactive_learn/problem-44/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-44/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.10" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -39,19 +41,13 @@ def _(mo): where $\alpha$ is typically a small positive value (default is 0.01) that determines the slope for negative inputs. """) - mo.accordion({"### Mathematical Definition" : value}) + mo.accordion({"### Mathematical Definition": value}) return (value,) @app.cell def _(mo): - alpha = mo.ui.slider( - start=0.01, - stop=0.5, - value=0.01, - step=0.01, - label="Alpha (α)" - ) + alpha = mo.ui.slider(start=0.01, stop=0.5, value=0.01, step=0.01, label="Alpha (α)") _callout = mo.callout( mo.md(""" @@ -63,62 +59,62 @@ def _(mo): - Lower alpha values make the function more similar to regular ReLU """), - kind="info" + kind="info", ) x_range = mo.ui.range_slider( - start=-10, - stop=10, - step=0.5, - value=[-5, 5], - label="X-axis Range" + start=-10, stop=10, step=0.5, value=[-5, 5], label="X-axis Range" ) - controls = mo.vstack([ - mo.md("### Adjust Parameters"), - mo.hstack([ - mo.vstack([ - alpha, - mo.accordion({ - "About Alpha": _callout - }) - ]), - mo.vstack([ - x_range, - mo.accordion({ - "About Range": "Adjust to see different regions of the function." - }) - ]) - ]) - ]) + controls = mo.vstack( + [ + mo.md("### Adjust Parameters"), + mo.hstack( + [ + mo.vstack([alpha, mo.accordion({"About Alpha": _callout})]), + mo.vstack( + [ + x_range, + mo.accordion( + { + "About Range": "Adjust to see different regions of the function." + } + ), + ] + ), + ] + ), + ] + ) return alpha, controls, x_range @app.cell def _(mo): test_input = mo.ui.number( - value=0.0, - start=-10, - stop=10, - step=0.1, - label="Test Input Value" + value=0.0, start=-10, stop=10, step=0.1, label="Test Input Value" ) - input_controls = mo.vstack([ - mo.md("### Test Specific Values"), - test_input, - mo.accordion({ - "About Testing": "Enter specific values to see their Leaky ReLU outputs." - }) - ]) + input_controls = mo.vstack( + [ + mo.md("### Test Specific Values"), + test_input, + mo.accordion( + { + "About Testing": "Enter specific values to see their Leaky ReLU outputs." + } + ), + ] + ) return input_controls, test_input @app.cell def _(alpha, mo): - formula_display = mo.vstack([ - mo.md( - f""" + formula_display = mo.vstack( + [ + mo.md( + f""" ### Current Leaky ReLU Configuration With alpha parameter $\\alpha = {alpha.value:.3f}$, the current Leaky ReLU function is: @@ -134,8 +130,9 @@ def _(alpha, mo): - For negative inputs: output = {alpha.value:.3f} × input """ - ), - ]) + ), + ] + ) return (formula_display,) @@ -150,7 +147,9 @@ def _(alpha, mo, np, plt, test_input, x_range): @mo.cache(pin_modules=True) def plot_leaky_relu(): if x_range.value[0] >= x_range.value[1]: - raise ValueError("Invalid x_range: start value must be less than stop value.") + raise ValueError( + "Invalid x_range: start value must be less than stop value." + ) x = np.linspace(x_range.value[0], x_range.value[1], 1000) y = np.where(x > 0, x, alpha.value * x) @@ -159,40 +158,57 @@ def plot_leaky_relu(): # Plot negative region mask_neg = x <= 0 - plt.plot(x[mask_neg], y[mask_neg], - label=f'Negative region (slope = {alpha.value:.3f})', - color='red', - linewidth=2) + plt.plot( + x[mask_neg], + y[mask_neg], + label=f"Negative region (slope = {alpha.value:.3f})", + color="red", + linewidth=2, + ) # Plot positive region mask_pos = x > 0 - plt.plot(x[mask_pos], y[mask_pos], - label='Positive region (slope = 1.0)', - color='blue', - linewidth=2) + plt.plot( + x[mask_pos], + y[mask_pos], + label="Positive region (slope = 1.0)", + color="blue", + linewidth=2, + ) # Plot test point if within range if x_range.value[0] <= test_input.value <= x_range.value[1]: - test_output = test_input.value if test_input.value > 0 else alpha.value * test_input.value - plt.scatter([test_input.value], [test_output], - color='green', s=100, - label=f'Test point: f({test_input.value:.2f}) = {test_output:.2f}') + test_output = ( + test_input.value + if test_input.value > 0 + else alpha.value * test_input.value + ) + plt.scatter( + [test_input.value], + [test_output], + color="green", + s=100, + label=f"Test point: f({test_input.value:.2f}) = {test_output:.2f}", + ) plt.grid(True, alpha=0.3) - plt.title(f'Leaky ReLU Function (α = {alpha.value:.3f})') - plt.xlabel('Input (z)') - plt.ylabel('Output (LeakyReLU(z))') - plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') + plt.title(f"Leaky ReLU Function (α = {alpha.value:.3f})") + plt.xlabel("Input (z)") + plt.ylabel("Output (LeakyReLU(z))") + plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") # Add zero lines - plt.axhline(y=0, color='k', linestyle='--', alpha=0.3) - plt.axvline(x=0, color='k', linestyle='--', alpha=0.3) + plt.axhline(y=0, color="k", linestyle="--", alpha=0.3) + plt.axvline(x=0, color="k", linestyle="--", alpha=0.3) - plot_display = mo.vstack([ - mo.as_html(plt.gca()), - ]) + plot_display = mo.vstack( + [ + mo.as_html(plt.gca()), + ] + ) return plot_display + return (plot_leaky_relu,) @@ -216,9 +232,10 @@ def _(plot_leaky_relu): @app.cell def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the Leaky ReLU function interactively. You've learned: @@ -226,30 +243,33 @@ def _(mo): - The effect of the alpha parameter - Why this helps prevent the "dying ReLU" problem """), - kind="success" - ), - mo.accordion({ - "Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "Next Steps": mo.md(""" 1. **Implementation:** Try implementing Leaky ReLU from scratch 2. **Compare:** Explore how it differs from other ReLU variants 3. **Experiment:** Test different alpha values in a neural network 4. **Advanced:** Learn about other solutions to the dying ReLU problem """), - "🎯 Common Applications": mo.md(""" + "🎯 Common Applications": mo.md(""" - Deep neural networks - Convolutional neural networks (CNNs) - Feature extraction layers - When regular ReLU causes dead neurons - Training very deep networks """), - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(mo): - mo.md(f""" + mo.md(""" This interactive learning experience was designed to help you understand the Leaky ReLU activation function. Hope this helps in your deep learning journey! """) return @@ -264,6 +284,7 @@ def _(conclusion): @app.cell(hide_code=True) def _(): import marimo as mo + return (mo,) @@ -271,6 +292,7 @@ def _(): def _(): import numpy as np import matplotlib.pyplot as plt + return np, plt diff --git a/old_repo/Problems/interactive_learn/problem-75/notebook.py b/old_repo/Problems/interactive_learn/problem-75/notebook.py index c191ccf6..0a2348c9 100644 --- a/old_repo/Problems/interactive_learn/problem-75/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-75/notebook.py @@ -95,14 +95,18 @@ def _(data_controls): def _(mo): # Create number inputs for 12 individuals n_samples = 12 - actual_inputs = mo.ui.array([ - mo.ui.number(value=0, start=0, stop=1, label=f"Actual {i+1}") - for i in range(n_samples) - ]) - predicted_inputs = mo.ui.array([ - mo.ui.number(value=0, start=0, stop=1, label=f"Predicted {i+1}") - for i in range(n_samples) - ]) + actual_inputs = mo.ui.array( + [ + mo.ui.number(value=0, start=0, stop=1, label=f"Actual {i + 1}") + for i in range(n_samples) + ] + ) + predicted_inputs = mo.ui.array( + [ + mo.ui.number(value=0, start=0, stop=1, label=f"Predicted {i + 1}") + for i in range(n_samples) + ] + ) # Create data table using markdown with LaTeX data_table = mo.md(r""" @@ -120,20 +124,23 @@ def _(mo): """) # Stack inputs horizontally and data table below - data_controls = mo.vstack([ - mo.hstack([ - mo.vstack([ - mo.md("**Actual Classifications:**"), - actual_inputs - ]), - mo.vstack([ - mo.md("**Predicted Classifications:**"), - predicted_inputs - ]) - ], justify="start", align="start"), - mo.md("### Data Table:"), - data_table - ], gap=2) # Added gap for better spacing + data_controls = mo.vstack( + [ + mo.hstack( + [ + mo.vstack([mo.md("**Actual Classifications:**"), actual_inputs]), + mo.vstack( + [mo.md("**Predicted Classifications:**"), predicted_inputs] + ), + ], + justify="start", + align="start", + ), + mo.md("### Data Table:"), + data_table, + ], + gap=2, + ) # Added gap for better spacing return ( actual_inputs, data_controls, @@ -197,49 +204,58 @@ def _( accuracy = (tp + tn) / total if total > 0 else 0 precision = tp / (tp + fp) if (tp + fp) > 0 else 0 recall = tp / (tp + fn) if (tp + fn) > 0 else 0 - f1 = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0 + f1 = ( + 2 * (precision * recall) / (precision + recall) + if (precision + recall) > 0 + else 0 + ) # results table using markdown with LaTeX - results_table = mo.md(r""" + results_table = mo.md( + r""" $$ \begin{array}{|c|c|c|c|c|c|c|c|c|c|c|c|c|} \hline \text{Individual} & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 & 11 & 12 \\ \hline - \text{Actual} & """ + " & ".join(str(v) for v in actual_values) + r""" \\ + \text{Actual} & """ + + " & ".join(str(v) for v in actual_values) + + r""" \\ \hline - \text{Predicted} & """ + " & ".join(str(v) for v in predicted_values) + r""" \\ + \text{Predicted} & """ + + " & ".join(str(v) for v in predicted_values) + + r""" \\ \hline - \text{Result} & """ + " & ".join(results_array) + r""" \\ + \text{Result} & """ + + " & ".join(results_array) + + r""" \\ \hline \end{array} $$ - """) + """ + ) # Create confusion matrix visualization fig = px.imshow( conf_matrix, labels=dict(x="Predicted", y="Actual"), - x=['Positive', 'Negative'], - y=['Positive', 'Negative'], + x=["Positive", "Negative"], + y=["Positive", "Negative"], aspect="auto", title="Confusion Matrix Heatmap", color_continuous_scale="RdBu", width=500, height=500, - text_auto=True + text_auto=True, ) fig.update_traces( texttemplate="%{z}", textfont={"size": 20}, hoverongaps=False, - hovertemplate="
".join([ - "Actual: %{y}", - "Predicted: %{x}", - "Count: %{z}", - "" - ]) + hovertemplate="
".join( + ["Actual: %{y}", "Predicted: %{x}", "Count: %{z}", ""] + ), ) # matrix interpretation @@ -265,18 +281,16 @@ def _( - F1 Score: {f1:.2f} """) - results = mo.vstack([ - mo.md("### Results"), - results_table, - # confusion matrix and interpretation side-by-side - mo.hstack([ - fig, - matrix_interpretation - ], justify="start", align="start"), - explanation, - # final callout - mo.callout( - mo.md(""" + results = mo.vstack( + [ + mo.md("### Results"), + results_table, + # confusion matrix and interpretation side-by-side + mo.hstack([fig, matrix_interpretation], justify="start", align="start"), + explanation, + # final callout + mo.callout( + mo.md(""" 🎉 Congratulations! You've successfully: - Understood how confusion matrices work in binary classification @@ -287,9 +301,10 @@ def _( - Gained hands-on experience with interactive confusion matrix analysis """), - kind="success" - ) - ]) + kind="success", + ), + ] + ) results return ( accuracy, @@ -317,8 +332,9 @@ def _( @app.cell(hide_code=True) def _(mo): - explanation = mo.accordion({ - "🎯 Understanding the Results": mo.md(""" + explanation = mo.accordion( + { + "🎯 Understanding the Results": mo.md(""" **Interpreting the Confusion Matrix:** 1. **Top-left (TP)**: Correctly identified positive cases @@ -326,27 +342,27 @@ def _(mo): 3. **Bottom-left (FP)**: False alarms 4. **Bottom-right (TN)**: Correctly identified negative cases """), - - "📊 Derived Metrics": mo.md(""" + "📊 Derived Metrics": mo.md(""" - **Accuracy**: Overall correctness (TP + TN) / Total - **Precision**: Positive predictive value TP / (TP + FP) - **Recall**: True positive rate TP / (TP + FN) - **F1 Score**: Harmonic mean of precision and recall """), - - "💡 Best Practices": mo.md(""" + "💡 Best Practices": mo.md(""" 1. Consider class imbalance 2. Look at all metrics, not just accuracy 3. Choose metrics based on your problem context 4. Use confusion matrix for model debugging - """) - }) + """), + } + ) return (explanation,) @app.cell def _(): import marimo as mo + return (mo,) @@ -354,6 +370,7 @@ def _(): def _(): import numpy as np import plotly.express as px + return np, px diff --git a/old_repo/Problems/interactive_learn/problem-82/notebook.py b/old_repo/Problems/interactive_learn/problem-82/notebook.py index ec2a6703..a2c9c5f9 100644 --- a/old_repo/Problems/interactive_learn/problem-82/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-82/notebook.py @@ -11,7 +11,9 @@ import marimo __generated_with = "0.10.11" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -130,7 +132,6 @@ def compress_image(img, max_size=(400, 400)): img.thumbnail(max_size, Image.Resampling.LANCZOS) return img - @mo.cache def process_image(image_data=None, use_sample=False): # TODO: Image path needs to be fixed for sample image; rerun when new version is rolled out @@ -152,7 +153,6 @@ def process_image(image_data=None, use_sample=False): return img_array, img_display - def calculate_contrast(img_array, method): if img_array is None: return 0 @@ -165,6 +165,7 @@ def calculate_contrast(img_array, method): else: # Michelson Contrast Imax, Imin = np.max(img_array), np.min(img_array) return (Imax - Imin) / (Imax + Imin + 1e-6) + return calculate_contrast, compress_image, process_image @@ -260,7 +261,6 @@ def _(calculate_contrast, img_array, io, mo, np, plt): ] ) - michelson_tab = mo.vstack( [ mo.md(rf""" @@ -323,7 +323,7 @@ def _(display): @app.cell def _(mo): - conclusion = mo.md(f""" + conclusion = mo.md(""" **Congratulations!** You've explored the Grayscale Image Contrast Calculator interactively. @@ -342,8 +342,9 @@ def _(mo): @app.cell def _(mo): - mo.accordion({ - "🌟 Applications and Relevance": mo.md(r""" + mo.accordion( + { + "🌟 Applications and Relevance": mo.md(r""" ### Relevance in Signal and Image Processing Contrast calculations play a vital role in enhancing image quality for better visualization and analysis. They are used in: @@ -354,7 +355,8 @@ def _(mo): Contrast is a cornerstone of image and signal processing, enabling improved functionality across diverse fields from healthcare to autonomous systems. """), - }) + } + ) return @@ -374,6 +376,7 @@ def _(callout, img_data, mo, source_selector): @app.cell def _(): import marimo as mo + return (mo,) @@ -383,6 +386,7 @@ def _(): from PIL import Image import matplotlib.pyplot as plt import io + return Image, io, np, plt diff --git a/old_repo/Problems/interactive_learn/problem-96/notebook.py b/old_repo/Problems/interactive_learn/problem-96/notebook.py index 2b748e42..34702859 100644 --- a/old_repo/Problems/interactive_learn/problem-96/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-96/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.12" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -40,18 +42,14 @@ def _(mo): This piece-wise linear function approximates the smooth sigmoid curve with straight lines. """) - mo.accordion({"### Mathematical Definition" : value}) + mo.accordion({"### Mathematical Definition": value}) return (value,) @app.cell def _(mo): x_range = mo.ui.range_slider( - start=-5, - stop=5, - step=0.5, - value=[-3, 3], - label="X-axis Range" + start=-5, stop=5, step=0.5, value=[-3, 3], label="X-axis Range" ) _callout = mo.callout( @@ -62,48 +60,50 @@ def _(mo): - Between -2.5 and 2.5: Linear interpolation (0.2x + 0.5) - Above 2.5: Output is 1 """), - kind="info" + kind="info", ) - controls = mo.vstack([ - mo.md("### Adjust Parameters"), - mo.hstack([ - mo.vstack([ - x_range, - mo.accordion({ - "About Function Regions": _callout - }) - ]) - ]) - ]) + controls = mo.vstack( + [ + mo.md("### Adjust Parameters"), + mo.hstack( + [ + mo.vstack( + [x_range, mo.accordion({"About Function Regions": _callout})] + ) + ] + ), + ] + ) return controls, x_range @app.cell def _(mo): test_input = mo.ui.number( - value=0.0, - start=-5, - stop=5, - step=0.1, - label="Test Input Value" + value=0.0, start=-5, stop=5, step=0.1, label="Test Input Value" ) - input_controls = mo.vstack([ - mo.md("### Test Specific Values"), - test_input, - mo.accordion({ - "About Testing": "Enter specific values to see their Hard Sigmoid outputs." - }) - ]) + input_controls = mo.vstack( + [ + mo.md("### Test Specific Values"), + test_input, + mo.accordion( + { + "About Testing": "Enter specific values to see their Hard Sigmoid outputs." + } + ), + ] + ) return input_controls, test_input @app.cell def _(mo): - formula_display = mo.vstack([ - mo.md( - r""" + formula_display = mo.vstack( + [ + mo.md( + r""" ### Current Hard Sigmoid Configuration The Hard Sigmoid function is defined piece-wise: @@ -120,8 +120,9 @@ def _(mo): - For -2.5 < x < 2.5: output = 0.2x + 0.5 - For x ≥ 2.5: output = 1 """ - ), - ]) + ), + ] + ) return (formula_display,) @@ -136,7 +137,9 @@ def _(mo, np, plt, test_input, x_range): @mo.cache(pin_modules=True) def plot_hard_sigmoid(): if x_range.value[0] >= x_range.value[1]: - raise ValueError("Invalid x_range: start value must be less than stop value.") + raise ValueError( + "Invalid x_range: start value must be less than stop value." + ) x = np.linspace(x_range.value[0], x_range.value[1], 1000) y = np.clip(0.2 * x + 0.5, 0, 1) @@ -148,41 +151,57 @@ def plot_hard_sigmoid(): mask_middle = (x > -2.5) & (x < 2.5) mask_right = x >= 2.5 - plt.plot(x[mask_left], y[mask_left], - label='Lower saturation (y = 0)', - color='red', - linewidth=2) - plt.plot(x[mask_middle], y[mask_middle], - label='Linear region (y = 0.2x + 0.5)', - color='blue', - linewidth=2) - plt.plot(x[mask_right], y[mask_right], - label='Upper saturation (y = 1)', - color='green', - linewidth=2) + plt.plot( + x[mask_left], + y[mask_left], + label="Lower saturation (y = 0)", + color="red", + linewidth=2, + ) + plt.plot( + x[mask_middle], + y[mask_middle], + label="Linear region (y = 0.2x + 0.5)", + color="blue", + linewidth=2, + ) + plt.plot( + x[mask_right], + y[mask_right], + label="Upper saturation (y = 1)", + color="green", + linewidth=2, + ) # Plot test point if within range (extend slider range accordingly) if x_range.value[0] <= test_input.value <= x_range.value[1]: test_output = np.clip(0.2 * test_input.value + 0.5, 0, 1) - plt.scatter([test_input.value], [test_output], - color='purple', s=100, - label=f'Test point: f({test_input.value:.2f}) = {test_output:.2f}') + plt.scatter( + [test_input.value], + [test_output], + color="purple", + s=100, + label=f"Test point: f({test_input.value:.2f}) = {test_output:.2f}", + ) plt.grid(True, alpha=0.3) - plt.title('Hard Sigmoid Function') - plt.xlabel('Input (x)') - plt.ylabel('Output (HardSigmoid(x))') - plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') + plt.title("Hard Sigmoid Function") + plt.xlabel("Input (x)") + plt.ylabel("Output (HardSigmoid(x))") + plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") # Add zero lines - plt.axhline(y=0, color='k', linestyle='--', alpha=0.3) - plt.axvline(x=0, color='k', linestyle='--', alpha=0.3) + plt.axhline(y=0, color="k", linestyle="--", alpha=0.3) + plt.axvline(x=0, color="k", linestyle="--", alpha=0.3) - plot_display = mo.vstack([ - mo.as_html(plt.gca()), - ]) + plot_display = mo.vstack( + [ + mo.as_html(plt.gca()), + ] + ) return plot_display + return (plot_hard_sigmoid,) @@ -206,9 +225,10 @@ def _(plot_hard_sigmoid): @app.cell def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the Hard Sigmoid function interactively. You've learned: @@ -216,30 +236,33 @@ def _(mo): - The three distinct regions of the function - The simplicity of the function -> only requires basic arithmetic operations -> making it computationally cheaper """), - kind="success" - ), - mo.accordion({ - "Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "Next Steps": mo.md(""" 1. **Implementation:** Try implementing Hard Sigmoid from scratch 2. **Compare:** Explore how it differs from regular sigmoid 3. **Experiment:** Test performance benefits in a neural network 4. **Advanced:** Learn about other sigmoid approximations """), - "🎯 Common Applications": mo.md(""" + "🎯 Common Applications": mo.md(""" - Neural networks requiring fast computation - Embedded systems with limited resources - Mobile applications - Real-time inference systems - Hardware implementations of neural networks """), - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(mo): - mo.md(f""" + mo.md(""" This interactive learning experience was designed to help you understand the Hard Sigmoid activation function. Hope this helps in your deep learning journey! """) return @@ -254,6 +277,7 @@ def _(conclusion): @app.cell(hide_code=True) def _(): import marimo as mo + return (mo,) @@ -261,6 +285,7 @@ def _(): def _(): import numpy as np import matplotlib.pyplot as plt + return np, plt diff --git a/old_repo/Problems/interactive_learn/problem-97/notebook.py b/old_repo/Problems/interactive_learn/problem-97/notebook.py index e87c8500..58362b3a 100644 --- a/old_repo/Problems/interactive_learn/problem-97/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-97/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.12" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -45,13 +47,7 @@ def _(mo): @app.cell def _(mo): - alpha = mo.ui.slider( - start=0.1, - stop=3.0, - value=1.0, - step=0.1, - label="Alpha (α)" - ) + alpha = mo.ui.slider(start=0.1, stop=3.0, value=1.0, step=0.1, label="Alpha (α)") _callout = mo.callout( mo.md(""" @@ -63,62 +59,60 @@ def _(mo): - The function smoothly transitions at z = 0 - Negative values are bounded by -α """), - kind="info" + kind="info", ) x_range = mo.ui.range_slider( - start=-10, - stop=10, - step=0.5, - value=[-5, 5], - label="X-axis Range" + start=-10, stop=10, step=0.5, value=[-5, 5], label="X-axis Range" ) - controls = mo.vstack([ - mo.md("### Adjust Parameters"), - mo.hstack([ - mo.vstack([ - alpha, - mo.accordion({ - "About Alpha": _callout - }) - ]), - mo.vstack([ - x_range, - mo.accordion({ - "About Range": "Adjust to see different regions of the function." - }) - ]) - ]) - ]) + controls = mo.vstack( + [ + mo.md("### Adjust Parameters"), + mo.hstack( + [ + mo.vstack([alpha, mo.accordion({"About Alpha": _callout})]), + mo.vstack( + [ + x_range, + mo.accordion( + { + "About Range": "Adjust to see different regions of the function." + } + ), + ] + ), + ] + ), + ] + ) return alpha, controls, x_range @app.cell def _(mo): test_input = mo.ui.number( - value=0.0, - start=-10, - stop=10, - step=0.1, - label="Test Input Value" + value=0.0, start=-10, stop=10, step=0.1, label="Test Input Value" ) - input_controls = mo.vstack([ - mo.md("### Test Specific Values"), - test_input, - mo.accordion({ - "About Testing": "Enter specific values to see their ELU outputs." - }) - ]) + input_controls = mo.vstack( + [ + mo.md("### Test Specific Values"), + test_input, + mo.accordion( + {"About Testing": "Enter specific values to see their ELU outputs."} + ), + ] + ) return input_controls, test_input @app.cell def _(alpha, mo): - formula_display = mo.vstack([ - mo.md( - f""" + formula_display = mo.vstack( + [ + mo.md( + f""" ### Current ELU Configuration With alpha parameter $\\alpha = {alpha.value:.3f}$, the current ELU function is: @@ -134,8 +128,9 @@ def _(alpha, mo): - For negative inputs: output = {alpha.value:.3f}(e^z - 1) """ - ), - ]) + ), + ] + ) return (formula_display,) @@ -150,7 +145,9 @@ def _(alpha, mo, np, plt, test_input, x_range): @mo.cache(pin_modules=True) def plot_elu(): if x_range.value[0] >= x_range.value[1]: - raise ValueError("Invalid x_range: start value must be less than stop value.") + raise ValueError( + "Invalid x_range: start value must be less than stop value." + ) x = np.linspace(x_range.value[0], x_range.value[1], 1000) y = np.where(x > 0, x, alpha.value * (np.exp(x) - 1)) @@ -159,41 +156,58 @@ def plot_elu(): # Plot -ve region mask_neg = x <= 0 - plt.plot(x[mask_neg], y[mask_neg], - label=f'Negative region (exponential decay)', - color='red', - linewidth=2) + plt.plot( + x[mask_neg], + y[mask_neg], + label="Negative region (exponential decay)", + color="red", + linewidth=2, + ) # Plot +ve region mask_pos = x > 0 - plt.plot(x[mask_pos], y[mask_pos], - label='Positive region (linear)', - color='blue', - linewidth=2) + plt.plot( + x[mask_pos], + y[mask_pos], + label="Positive region (linear)", + color="blue", + linewidth=2, + ) # Plot test point if within range (expand x slider range to show test point) if x_range.value[0] <= test_input.value <= x_range.value[1]: - test_output = test_input.value if test_input.value > 0 else alpha.value * (np.exp(test_input.value) - 1) - plt.scatter([test_input.value], [test_output], - color='green', s=100, - label=f'Test point: ELU({test_input.value:.2f}) = {test_output:.2f}') + test_output = ( + test_input.value + if test_input.value > 0 + else alpha.value * (np.exp(test_input.value) - 1) + ) + plt.scatter( + [test_input.value], + [test_output], + color="green", + s=100, + label=f"Test point: ELU({test_input.value:.2f}) = {test_output:.2f}", + ) plt.grid(True, alpha=0.3) - plt.title(f'ELU Function (α = {alpha.value:.3f})') - plt.xlabel('Input (z)') - plt.ylabel('Output (ELU(z))') - plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') + plt.title(f"ELU Function (α = {alpha.value:.3f})") + plt.xlabel("Input (z)") + plt.ylabel("Output (ELU(z))") + plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") # Add zero lines - plt.axhline(y=0, color='k', linestyle='--', alpha=0.3) - plt.axvline(x=0, color='k', linestyle='--', alpha=0.3) + plt.axhline(y=0, color="k", linestyle="--", alpha=0.3) + plt.axvline(x=0, color="k", linestyle="--", alpha=0.3) - plot_display = mo.vstack([ - mo.as_html(plt.gca()), - ]) + plot_display = mo.vstack( + [ + mo.as_html(plt.gca()), + ] + ) return plot_display + return (plot_elu,) @@ -217,9 +231,10 @@ def _(plot_elu): @app.cell def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the ELU function interactively. You've learned: @@ -228,30 +243,33 @@ def _(mo): - Why it can help with mean unit activations - How it combines the benefits of ReLU with negative values """), - kind="success" - ), - mo.accordion({ - "Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "Next Steps": mo.md(""" 1. **Implementation:** Try implementing ELU from scratch 2. **Compare:** Explore how it differs from ReLU and Leaky ReLU 3. **Experiment:** Test different alpha values in a neural network 4. **Advanced:** Learn about variants like SELU """), - "🎯 Common Applications": mo.md(""" + "🎯 Common Applications": mo.md(""" - Deep neural networks - When faster learning is desired - When negative values are important - When dealing with vanishing gradients - When mean activations closer to zero are beneficial """), - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(mo): - mo.md(f""" + mo.md(""" This interactive learning experience was designed to help you understand the ELU activation function. Hope this helps in your deep learning journey! """) return @@ -266,6 +284,7 @@ def _(conclusion): @app.cell(hide_code=True) def _(): import marimo as mo + return (mo,) @@ -273,6 +292,7 @@ def _(): def _(): import numpy as np import matplotlib.pyplot as plt + return np, plt diff --git a/old_repo/Problems/interactive_learn/problem-98/notebook.py b/old_repo/Problems/interactive_learn/problem-98/notebook.py index a8adbcbf..102dcffa 100644 --- a/old_repo/Problems/interactive_learn/problem-98/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-98/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.12" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -39,19 +41,13 @@ def _(mo): where $\alpha$ is a learnable parameter that can be optimized during training, unlike Leaky ReLU where it's fixed. """) - mo.accordion({"### Mathematical Definition" : value}) + mo.accordion({"### Mathematical Definition": value}) return (value,) @app.cell def _(mo): - alpha = mo.ui.slider( - start=0.01, - stop=1.0, - value=0.25, - step=0.01, - label="Alpha (α)" - ) + alpha = mo.ui.slider(start=0.01, stop=1.0, value=0.25, step=0.01, label="Alpha (α)") _callout = mo.callout( mo.md(""" @@ -63,62 +59,60 @@ def _(mo): - Can adapt to the data distribution - May have different values for different channels """), - kind="info" + kind="info", ) x_range = mo.ui.range_slider( - start=-10, - stop=10, - step=0.5, - value=[-5, 5], - label="X-axis Range" + start=-10, stop=10, step=0.5, value=[-5, 5], label="X-axis Range" ) - controls = mo.vstack([ - mo.md("### Adjust Parameters"), - mo.hstack([ - mo.vstack([ - alpha, - mo.accordion({ - "About Alpha": _callout - }) - ]), - mo.vstack([ - x_range, - mo.accordion({ - "About Range": "Adjust to see different regions of the function." - }) - ]) - ]) - ]) + controls = mo.vstack( + [ + mo.md("### Adjust Parameters"), + mo.hstack( + [ + mo.vstack([alpha, mo.accordion({"About Alpha": _callout})]), + mo.vstack( + [ + x_range, + mo.accordion( + { + "About Range": "Adjust to see different regions of the function." + } + ), + ] + ), + ] + ), + ] + ) return alpha, controls, x_range @app.cell def _(mo): test_input = mo.ui.number( - value=0.0, - start=-10, - stop=10, - step=0.1, - label="Test Input Value" + value=0.0, start=-10, stop=10, step=0.1, label="Test Input Value" ) - input_controls = mo.vstack([ - mo.md("### Test Specific Values"), - test_input, - mo.accordion({ - "About Testing": "Enter specific values to see their PReLU outputs." - }) - ]) + input_controls = mo.vstack( + [ + mo.md("### Test Specific Values"), + test_input, + mo.accordion( + {"About Testing": "Enter specific values to see their PReLU outputs."} + ), + ] + ) return input_controls, test_input @app.cell def _(alpha, mo): - formula_display = mo.vstack([ - mo.md( - f""" + formula_display = mo.vstack( + [ + mo.md( + f""" ### Current PReLU Configuration With learnable parameter $\\alpha = {alpha.value:.3f}$, the current PReLU function is: @@ -134,8 +128,9 @@ def _(alpha, mo): - For negative inputs: output = {alpha.value:.3f} × input (learnable) """ - ), - ]) + ), + ] + ) return (formula_display,) @@ -150,7 +145,9 @@ def _(alpha, mo, np, plt, test_input, x_range): @mo.cache(pin_modules=True) def plot_prelu(): if x_range.value[0] >= x_range.value[1]: - raise ValueError("Invalid x_range: start value must be less than stop value.") + raise ValueError( + "Invalid x_range: start value must be less than stop value." + ) x = np.linspace(x_range.value[0], x_range.value[1], 1000) y = np.where(x > 0, x, alpha.value * x) @@ -159,40 +156,57 @@ def plot_prelu(): # Plot -ve region mask_neg = x <= 0 - plt.plot(x[mask_neg], y[mask_neg], - label=f'Negative region (learned slope = {alpha.value:.3f})', - color='purple', - linewidth=2) + plt.plot( + x[mask_neg], + y[mask_neg], + label=f"Negative region (learned slope = {alpha.value:.3f})", + color="purple", + linewidth=2, + ) # Plot +ve region mask_pos = x > 0 - plt.plot(x[mask_pos], y[mask_pos], - label='Positive region (slope = 1.0)', - color='green', - linewidth=2) + plt.plot( + x[mask_pos], + y[mask_pos], + label="Positive region (slope = 1.0)", + color="green", + linewidth=2, + ) # Plot test point if within range (modify x range slider accordingly) if x_range.value[0] <= test_input.value <= x_range.value[1]: - test_output = test_input.value if test_input.value > 0 else alpha.value * test_input.value - plt.scatter([test_input.value], [test_output], - color='orange', s=100, - label=f'Test point: f({test_input.value:.2f}) = {test_output:.2f}') + test_output = ( + test_input.value + if test_input.value > 0 + else alpha.value * test_input.value + ) + plt.scatter( + [test_input.value], + [test_output], + color="orange", + s=100, + label=f"Test point: f({test_input.value:.2f}) = {test_output:.2f}", + ) plt.grid(True, alpha=0.3) - plt.title(f'PReLU Function (learned α = {alpha.value:.3f})') - plt.xlabel('Input (z)') - plt.ylabel('Output (PReLU(z))') - plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') + plt.title(f"PReLU Function (learned α = {alpha.value:.3f})") + plt.xlabel("Input (z)") + plt.ylabel("Output (PReLU(z))") + plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") # Add zero lines - plt.axhline(y=0, color='k', linestyle='--', alpha=0.3) - plt.axvline(x=0, color='k', linestyle='--', alpha=0.3) + plt.axhline(y=0, color="k", linestyle="--", alpha=0.3) + plt.axvline(x=0, color="k", linestyle="--", alpha=0.3) - plot_display = mo.vstack([ - mo.as_html(plt.gca()), - ]) + plot_display = mo.vstack( + [ + mo.as_html(plt.gca()), + ] + ) return plot_display + return (plot_prelu,) @@ -216,9 +230,10 @@ def _(plot_prelu): @app.cell def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the PReLU activation function interactively. You've learned: @@ -226,30 +241,33 @@ def _(mo): - The effect of adaptive alpha parameters - Why this helps improve model performance """), - kind="success" - ), - mo.accordion({ - "Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "Next Steps": mo.md(""" 1. **Implementation:** Try implementing PReLU in a neural network 2. **Compare:** Test against ReLU and Leaky ReLU 3. **Experiment:** Observe learned alpha values after training 4. **Advanced:** Implement channel-wise PReLU parameters """), - "🎯 Common Applications": mo.md(""" + "🎯 Common Applications": mo.md(""" - Deep Convolutional Neural Networks - Image Classification Tasks - Feature Extraction Networks - When adaptive negative slopes are beneficial - Performance-critical deep learning models """), - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(mo): - mo.md(f""" + mo.md(""" This interactive learning experience was designed to help you understand the PReLU activation function. Hope this helps in your deep learning journey! """) return @@ -264,6 +282,7 @@ def _(conclusion): @app.cell(hide_code=True) def _(): import marimo as mo + return (mo,) @@ -271,6 +290,7 @@ def _(): def _(): import numpy as np import matplotlib.pyplot as plt + return np, plt diff --git a/old_repo/Problems/interactive_learn/problem-99/notebook.py b/old_repo/Problems/interactive_learn/problem-99/notebook.py index 29a98f11..deedb4a9 100644 --- a/old_repo/Problems/interactive_learn/problem-99/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-99/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.12" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -36,18 +38,14 @@ def _(mo): where $\log$ is the natural logarithm. This function provides a smooth, differentiable alternative to ReLU. """) - mo.accordion({"### Mathematical Definition" : value}) + mo.accordion({"### Mathematical Definition": value}) return (value,) @app.cell def _(mo): x_range = mo.ui.range_slider( - start=-5, - stop=5, - step=0.5, - value=[-3, 3], - label="X-axis Range" + start=-5, stop=5, step=0.5, value=[-3, 3], label="X-axis Range" ) _callout = mo.callout( @@ -58,48 +56,46 @@ def _(mo): - Around 0: Smooth transition - For large positive values: Approaches linear (similar to ReLU) """), - kind="info" + kind="info", ) - controls = mo.vstack([ - mo.md("### Adjust Range"), - mo.hstack([ - mo.vstack([ - x_range, - mo.accordion({ - "About Function": _callout - }) - ]) - ]) - ]) + controls = mo.vstack( + [ + mo.md("### Adjust Range"), + mo.hstack( + [mo.vstack([x_range, mo.accordion({"About Function": _callout})])] + ), + ] + ) return controls, x_range @app.cell def _(mo): test_input = mo.ui.number( - value=0.0, - start=-5, - stop=5, - step=0.1, - label="Test Input Value" + value=0.0, start=-5, stop=5, step=0.1, label="Test Input Value" ) - input_controls = mo.vstack([ - mo.md("### Test Specific Values"), - test_input, - mo.accordion({ - "About Testing": "Enter specific values to see their Softplus outputs and compare with ReLU." - }) - ]) + input_controls = mo.vstack( + [ + mo.md("### Test Specific Values"), + test_input, + mo.accordion( + { + "About Testing": "Enter specific values to see their Softplus outputs and compare with ReLU." + } + ), + ] + ) return input_controls, test_input @app.cell def _(mo): - formula_display = mo.vstack([ - mo.md( - r""" + formula_display = mo.vstack( + [ + mo.md( + r""" ### Softplus Function Properties The Softplus function $f(x) = \log(1 + e^x)$ has these key properties: @@ -108,8 +104,9 @@ def _(mo): - Smooth and differentiable everywhere - Derivative is the logistic sigmoid function: $f'(x) = \frac{1}{1 + e^{-x}}$ """ - ), - ]) + ), + ] + ) return (formula_display,) @@ -124,7 +121,9 @@ def _(mo, np, plt, test_input, x_range): @mo.cache(pin_modules=True) def plot_softplus(): if x_range.value[0] >= x_range.value[1]: - raise ValueError("Invalid x_range: start value must be less than stop value.") + raise ValueError( + "Invalid x_range: start value must be less than stop value." + ) x = np.linspace(x_range.value[0], x_range.value[1], 1000) y_softplus = np.log1p(np.exp(x)) # numerically stable version @@ -133,41 +132,48 @@ def plot_softplus(): plt.figure(figsize=(12, 7)) # Plot Softplus - plt.plot(x, y_softplus, - label='Softplus', - color='blue', - linewidth=2) + plt.plot(x, y_softplus, label="Softplus", color="blue", linewidth=2) # Plot ReLU for comparison (to see the smooth approximation) - plt.plot(x, y_relu, - label='ReLU (for comparison)', - color='red', - linestyle='--', - alpha=0.5, - linewidth=2) + plt.plot( + x, + y_relu, + label="ReLU (for comparison)", + color="red", + linestyle="--", + alpha=0.5, + linewidth=2, + ) # Plot test point if within range (adjust slider value accordingly) if x_range.value[0] <= test_input.value <= x_range.value[1]: test_output = np.log1p(np.exp(test_input.value)) - plt.scatter([test_input.value], [test_output], - color='green', s=100, - label=f'Test point: f({test_input.value:.2f}) = {test_output:.2f}') + plt.scatter( + [test_input.value], + [test_output], + color="green", + s=100, + label=f"Test point: f({test_input.value:.2f}) = {test_output:.2f}", + ) plt.grid(True, alpha=0.3) - plt.title('Softplus Function vs ReLU') - plt.xlabel('Input (x)') - plt.ylabel('Output (Softplus(x))') - plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') + plt.title("Softplus Function vs ReLU") + plt.xlabel("Input (x)") + plt.ylabel("Output (Softplus(x))") + plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") # Add zero lines - plt.axhline(y=0, color='k', linestyle='--', alpha=0.3) - plt.axvline(x=0, color='k', linestyle='--', alpha=0.3) + plt.axhline(y=0, color="k", linestyle="--", alpha=0.3) + plt.axvline(x=0, color="k", linestyle="--", alpha=0.3) - plot_display = mo.vstack([ - mo.as_html(plt.gca()), - ]) + plot_display = mo.vstack( + [ + mo.as_html(plt.gca()), + ] + ) return plot_display + return (plot_softplus,) @@ -191,9 +197,10 @@ def _(plot_softplus): @app.cell def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the Softplus activation function interactively. You've learned: @@ -202,23 +209,26 @@ def _(mo): - How it compares to ReLU visually - Its behavior in different input regions """), - kind="success" - ), - mo.accordion({ - "Key Takeaways": mo.md(""" + kind="success", + ), + mo.accordion( + { + "Key Takeaways": mo.md(""" - Softplus is always positive - Provides smooth transitions (differentiable everywhere) - Approaches ReLU for large positive values - More computationally expensive than ReLU """), - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(mo): - mo.md(f""" + mo.md(""" This interactive learning experience was designed to help you understand the Softplus activation function. Hope this helps in your deep learning journey! """) return @@ -233,6 +243,7 @@ def _(conclusion): @app.cell(hide_code=True) def _(): import marimo as mo + return (mo,) @@ -240,6 +251,7 @@ def _(): def _(): import numpy as np import matplotlib.pyplot as plt + return np, plt diff --git a/old_repo/Problems/interactive_learn/problem-Mish/notebook.py b/old_repo/Problems/interactive_learn/problem-Mish/notebook.py index 848762ef..69187ad9 100644 --- a/old_repo/Problems/interactive_learn/problem-Mish/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-Mish/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.12" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -36,18 +38,14 @@ def _(mo): It combines the characteristics of the softplus function ($\ln(1 + e^x)$) with hyperbolic tangent, creating a smooth and non-monotonic activation function. """) - mo.accordion({"### Mathematical Definition" : value}) + mo.accordion({"### Mathematical Definition": value}) return (value,) @app.cell def _(mo): x_range = mo.ui.range_slider( - start=-5, - stop=5, - step=0.5, - value=[-3, 3], - label="X-axis Range" + start=-5, stop=5, step=0.5, value=[-3, 3], label="X-axis Range" ) _callout = mo.callout( @@ -62,62 +60,60 @@ def _(mo): - Preserves small negative gradients - Smoother than ReLU and its variants """), - kind="info" + kind="info", ) smoothing = mo.ui.slider( - start=0.1, - stop=2.0, - value=1.0, - step=0.1, - label="Smoothing Factor" + start=0.1, stop=2.0, value=1.0, step=0.1, label="Smoothing Factor" ) - controls = mo.vstack([ - mo.md("### Adjust Parameters"), - mo.hstack([ - mo.vstack([ - smoothing, - mo.accordion({ - "About Smoothing": _callout - }) - ]), - mo.vstack([ - x_range, - mo.accordion({ - "About Range": "Adjust to see different regions of the function." - }) - ]) - ]) - ]) + controls = mo.vstack( + [ + mo.md("### Adjust Parameters"), + mo.hstack( + [ + mo.vstack([smoothing, mo.accordion({"About Smoothing": _callout})]), + mo.vstack( + [ + x_range, + mo.accordion( + { + "About Range": "Adjust to see different regions of the function." + } + ), + ] + ), + ] + ), + ] + ) return controls, smoothing, x_range @app.cell def _(mo): test_input = mo.ui.number( - value=0.0, - start=-5, - stop=5, - step=0.1, - label="Test Input Value" + value=0.0, start=-5, stop=5, step=0.1, label="Test Input Value" ) - input_controls = mo.vstack([ - mo.md("### Test Specific Values"), - test_input, - mo.accordion({ - "About Testing": "Enter specific values to see their Mish outputs." - }) - ]) + input_controls = mo.vstack( + [ + mo.md("### Test Specific Values"), + test_input, + mo.accordion( + {"About Testing": "Enter specific values to see their Mish outputs."} + ), + ] + ) return input_controls, test_input @app.cell def _(mo, smoothing): - formula_display = mo.vstack([ - mo.md( - f""" + formula_display = mo.vstack( + [ + mo.md( + f""" ### Current Mish Configuration With smoothing factor $\\beta = {smoothing.value:.3f}$, the current Mish function is: @@ -131,8 +127,9 @@ def _(mo, smoothing): - Non-monotonic near x = 0 - Preserves small negative gradients """ - ), - ]) + ), + ] + ) return (formula_display,) @@ -147,7 +144,9 @@ def _(mo, np, plt, smoothing, test_input, x_range): @mo.cache(pin_modules=True) def plot_mish(): if x_range.value[0] >= x_range.value[1]: - raise ValueError("Invalid x_range: start value must be less than stop value.") + raise ValueError( + "Invalid x_range: start value must be less than stop value." + ) x = np.linspace(x_range.value[0], x_range.value[1], 1000) softplus = np.log1p(np.exp(x)) @@ -156,34 +155,40 @@ def plot_mish(): plt.figure(figsize=(12, 7)) # Main function - plt.plot(x, y, - label=f'Mish (β={smoothing.value:.2f})', - color='purple', - linewidth=2) + plt.plot( + x, y, label=f"Mish (β={smoothing.value:.2f})", color="purple", linewidth=2 + ) # Plot test point if within range (vary slider accordingly) if x_range.value[0] <= test_input.value <= x_range.value[1]: test_softplus = np.log1p(np.exp(test_input.value)) test_output = test_input.value * np.tanh(smoothing.value * test_softplus) - plt.scatter([test_input.value], [test_output], - color='orange', s=100, - label=f'Test point: f({test_input.value:.2f}) = {test_output:.2f}') + plt.scatter( + [test_input.value], + [test_output], + color="orange", + s=100, + label=f"Test point: f({test_input.value:.2f}) = {test_output:.2f}", + ) plt.grid(True, alpha=0.3) - plt.title(f'Mish Function (β = {smoothing.value:.2f})') - plt.xlabel('Input (x)') - plt.ylabel('Output (Mish(x))') - plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') + plt.title(f"Mish Function (β = {smoothing.value:.2f})") + plt.xlabel("Input (x)") + plt.ylabel("Output (Mish(x))") + plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") # Add zero lines - plt.axhline(y=0, color='k', linestyle='--', alpha=0.3) - plt.axvline(x=0, color='k', linestyle='--', alpha=0.3) + plt.axhline(y=0, color="k", linestyle="--", alpha=0.3) + plt.axvline(x=0, color="k", linestyle="--", alpha=0.3) - plot_display = mo.vstack([ - mo.as_html(plt.gca()), - ]) + plot_display = mo.vstack( + [ + mo.as_html(plt.gca()), + ] + ) return plot_display + return (plot_mish,) @@ -207,9 +212,10 @@ def _(plot_mish): @app.cell def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the Mish activation function interactively. You've learned: @@ -217,30 +223,33 @@ def _(mo): - Its smooth, non-monotonic behavior - Why it's effective in deep networks """), - kind="success" - ), - mo.accordion({ - "Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "Next Steps": mo.md(""" 1. **Implementation:** Try implementing Mish in a neural network 2. **Compare:** Test against ReLU and other modern activations 3. **Experiment:** Observe training stability improvements 4. **Advanced:** Study the gradients and their behavior """), - "🎯 Common Applications": mo.md(""" + "🎯 Common Applications": mo.md(""" - Deep Neural Networks - Computer Vision Tasks - Classification Problems - When smooth gradients are crucial - Problems requiring self-regularization """), - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(mo): - mo.md(f""" + mo.md(""" This interactive learning experience was designed to help you understand the Mish activation function. Hope this helps in your deep learning journey! """) return @@ -255,6 +264,7 @@ def _(conclusion): @app.cell(hide_code=True) def _(): import marimo as mo + return (mo,) @@ -262,6 +272,7 @@ def _(): def _(): import numpy as np import matplotlib.pyplot as plt + return np, plt diff --git a/old_repo/Problems/interactive_learn/problem-SELU/notebook.py b/old_repo/Problems/interactive_learn/problem-SELU/notebook.py index 80a2722a..cfedc044 100644 --- a/old_repo/Problems/interactive_learn/problem-SELU/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-SELU/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.12" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -39,7 +41,7 @@ def _(mo): where $\lambda \approx 1.0507$ is a scaling parameter and $\alpha \approx 1.6733$ is the default shape parameter for self-normalization. """) - mo.accordion({"### Mathematical Definition" : value}) + mo.accordion({"### Mathematical Definition": value}) return (value,) @@ -50,7 +52,7 @@ def _(mo): stop=3.0, value=1.6732632423543772, # Default SELU alpha step=0.01, - label="Alpha (α)" + label="Alpha (α)", ) _callout = mo.callout( @@ -64,62 +66,60 @@ def _(mo): - Experiment with different α values to understand impact - Standard SELU uses fixed parameters for optimal performance """), - kind="info" + kind="info", ) x_range = mo.ui.range_slider( - start=-5, - stop=5, - step=0.5, - value=[-3, 3], - label="X-axis Range" + start=-5, stop=5, step=0.5, value=[-3, 3], label="X-axis Range" ) - controls = mo.vstack([ - mo.md("### Adjust Parameters"), - mo.hstack([ - mo.vstack([ - alpha, - mo.accordion({ - "About Alpha": _callout - }) - ]), - mo.vstack([ - x_range, - mo.accordion({ - "About Range": "Adjust to see different regions of the function." - }) - ]) - ]) - ]) + controls = mo.vstack( + [ + mo.md("### Adjust Parameters"), + mo.hstack( + [ + mo.vstack([alpha, mo.accordion({"About Alpha": _callout})]), + mo.vstack( + [ + x_range, + mo.accordion( + { + "About Range": "Adjust to see different regions of the function." + } + ), + ] + ), + ] + ), + ] + ) return alpha, controls, x_range @app.cell def _(mo): test_input = mo.ui.number( - value=0.0, - start=-5, - stop=5, - step=0.1, - label="Test Input Value" + value=0.0, start=-5, stop=5, step=0.1, label="Test Input Value" ) - input_controls = mo.vstack([ - mo.md("### Test Specific Values"), - test_input, - mo.accordion({ - "About Testing": "Enter specific values to see their SELU outputs." - }) - ]) + input_controls = mo.vstack( + [ + mo.md("### Test Specific Values"), + test_input, + mo.accordion( + {"About Testing": "Enter specific values to see their SELU outputs."} + ), + ] + ) return input_controls, test_input @app.cell def _(alpha, mo): - formula_display = mo.vstack([ - mo.md( - f""" + formula_display = mo.vstack( + [ + mo.md( + f""" ### Current SELU Configuration With parameter $\\alpha = {alpha.value:.3f}$ and fixed $\\lambda = 1.0507$, the current SELU function is: @@ -134,8 +134,9 @@ def _(alpha, mo): - For positive inputs: output = 1.0507 × input - For negative inputs: output = 1.0507 × {alpha.value:.3f} × (e^input - 1) """ - ), - ]) + ), + ] + ) return (formula_display,) @@ -150,7 +151,9 @@ def _(alpha, mo, np, plt, test_input, x_range): @mo.cache(pin_modules=True) def plot_selu(): if x_range.value[0] >= x_range.value[1]: - raise ValueError("Invalid x_range: start value must be less than stop value.") + raise ValueError( + "Invalid x_range: start value must be less than stop value." + ) scale = 1.0507009873554804 @@ -161,17 +164,23 @@ def plot_selu(): # Plot -ve region mask_neg = x <= 0 - plt.plot(x[mask_neg], y[mask_neg], - label=f'Negative region (α={alpha.value:.3f})', - color='darkred', - linewidth=2) + plt.plot( + x[mask_neg], + y[mask_neg], + label=f"Negative region (α={alpha.value:.3f})", + color="darkred", + linewidth=2, + ) # Plot +ve region mask_pos = x > 0 - plt.plot(x[mask_pos], y[mask_pos], - label='Positive region (λx)', - color='darkgreen', - linewidth=2) + plt.plot( + x[mask_pos], + y[mask_pos], + label="Positive region (λx)", + color="darkgreen", + linewidth=2, + ) # Plot test point if within range (extend range to show point if needed) if x_range.value[0] <= test_input.value <= x_range.value[1]: @@ -179,25 +188,32 @@ def plot_selu(): test_output = scale * test_input.value else: test_output = scale * alpha.value * (np.exp(test_input.value) - 1) - plt.scatter([test_input.value], [test_output], - color='orange', s=100, - label=f'Test point: f({test_input.value:.2f}) = {test_output:.2f}') + plt.scatter( + [test_input.value], + [test_output], + color="orange", + s=100, + label=f"Test point: f({test_input.value:.2f}) = {test_output:.2f}", + ) plt.grid(True, alpha=0.3) - plt.title(f'SELU Function (α = {alpha.value:.3f})') - plt.xlabel('Input (z)') - plt.ylabel('Output (SELU(z))') - plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') + plt.title(f"SELU Function (α = {alpha.value:.3f})") + plt.xlabel("Input (z)") + plt.ylabel("Output (SELU(z))") + plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") # Add zero lines - plt.axhline(y=0, color='k', linestyle='--', alpha=0.3) - plt.axvline(x=0, color='k', linestyle='--', alpha=0.3) + plt.axhline(y=0, color="k", linestyle="--", alpha=0.3) + plt.axvline(x=0, color="k", linestyle="--", alpha=0.3) - plot_display = mo.vstack([ - mo.as_html(plt.gca()), - ]) + plot_display = mo.vstack( + [ + mo.as_html(plt.gca()), + ] + ) return plot_display + return (plot_selu,) @@ -221,9 +237,10 @@ def _(plot_selu): @app.cell def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the SELU activation function interactively. You've learned: @@ -231,30 +248,33 @@ def _(mo): - The role of λ and α parameters - Why specific parameter values are chosen """), - kind="success" - ), - mo.accordion({ - "Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "Next Steps": mo.md(""" 1. **Implementation:** Try implementing SELU in a neural network 2. **Compare:** Test against other activation functions 3. **Experiment:** Observe self-normalizing properties 4. **Advanced:** Learn about proper initialization with SELU """), - "🎯 Common Applications": mo.md(""" + "🎯 Common Applications": mo.md(""" - Deep Neural Networks - Self-Normalizing Neural Networks (SNNs) - Networks requiring stable training - Deep architectures sensitive to normalization - Cases where batch normalization is impractical """), - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(mo): - mo.md(f""" + mo.md(""" This interactive learning experience was designed to help you understand the SELU activation function. Hope this helps in your deep learning journey! """) return @@ -269,6 +289,7 @@ def _(conclusion): @app.cell(hide_code=True) def _(): import marimo as mo + return (mo,) @@ -276,6 +297,7 @@ def _(): def _(): import numpy as np import matplotlib.pyplot as plt + return np, plt diff --git a/old_repo/Problems/interactive_learn/problem-softsign/notebook.py b/old_repo/Problems/interactive_learn/problem-softsign/notebook.py index 5e0753c1..48cb92d6 100644 --- a/old_repo/Problems/interactive_learn/problem-softsign/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-softsign/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.12" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -44,18 +46,14 @@ def _(mo): While both functions map inputs to the range (-1, 1), Softsign approaches its asymptotes more slowly than tanh, which can help maintain better gradient flow during training. """) - mo.accordion({"### Mathematical Definition" : value}) + mo.accordion({"### Mathematical Definition": value}) return (value,) @app.cell def _(mo): x_range = mo.ui.range_slider( - start=-10, - stop=10, - step=0.5, - value=[-5, 5], - label="X-axis Range" + start=-10, stop=10, step=0.5, value=[-5, 5], label="X-axis Range" ) _callout = mo.callout( @@ -70,46 +68,54 @@ def _(mo): - Shows slower saturation than tanh """), - kind="info" + kind="info", ) - controls = mo.hstack([ - mo.vstack([ - mo.md("### Adjust Parameters"), - x_range, - mo.accordion({ - "About Range": "Adjust to see different regions of the function and how it approaches its asymptotes.", - }) - ]), _callout.right() - ]) + controls = mo.hstack( + [ + mo.vstack( + [ + mo.md("### Adjust Parameters"), + x_range, + mo.accordion( + { + "About Range": "Adjust to see different regions of the function and how it approaches its asymptotes.", + } + ), + ] + ), + _callout.right(), + ] + ) return controls, x_range @app.cell def _(mo): test_input = mo.ui.number( - value=0.0, - start=-10, - stop=10, - step=0.1, - label="Test Input Value" + value=0.0, start=-10, stop=10, step=0.1, label="Test Input Value" ) - input_controls = mo.vstack([ - mo.md("### Test Specific Values"), - test_input, - mo.accordion({ - "About Testing": "Enter specific values to see their Softsign outputs." - }) - ]) + input_controls = mo.vstack( + [ + mo.md("### Test Specific Values"), + test_input, + mo.accordion( + { + "About Testing": "Enter specific values to see their Softsign outputs." + } + ), + ] + ) return input_controls, test_input @app.cell def _(mo): - formula_display = mo.vstack([ - mo.md( - r""" + formula_display = mo.vstack( + [ + mo.md( + r""" ### Current Softsign Configuration The Softsign function is defined as: @@ -119,8 +125,9 @@ def _(mo): \] """ - ), - ]) + ), + ] + ) return (formula_display,) @@ -135,7 +142,9 @@ def _(mo, np, plt, test_input, x_range): @mo.cache(pin_modules=True) def plot_softsign(): if x_range.value[0] >= x_range.value[1]: - raise ValueError("Invalid x_range: start value must be less than stop value.") + raise ValueError( + "Invalid x_range: start value must be less than stop value." + ) x = np.linspace(x_range.value[0], x_range.value[1], 1000) y_softsign = x / (1 + np.abs(x)) @@ -144,43 +153,48 @@ def plot_softsign(): plt.figure(figsize=(12, 7)) # Plot tanh first (as reference) - plt.plot(x, y_tanh, - label='tanh', - color='red', - linewidth=2, - linestyle='--', - alpha=0.6) + plt.plot( + x, y_tanh, label="tanh", color="red", linewidth=2, linestyle="--", alpha=0.6 + ) # Plot Softsign - plt.plot(x, y_softsign, - label='Softsign', - color='blue', - linewidth=2) + plt.plot(x, y_softsign, label="Softsign", color="blue", linewidth=2) # Plot test point if within range (adjust sliders accordingly) if x_range.value[0] <= test_input.value <= x_range.value[1]: test_output = test_input.value / (1 + abs(test_input.value)) - plt.scatter([test_input.value], [test_output], - color='green', s=100, - label=f'Test point: f({test_input.value:.2f}) = {test_output:.2f}') + plt.scatter( + [test_input.value], + [test_output], + color="green", + s=100, + label=f"Test point: f({test_input.value:.2f}) = {test_output:.2f}", + ) plt.grid(True, alpha=0.3) - plt.title('Softsign Activation Function') - plt.xlabel('Input (x)') - plt.ylabel('Output (Softsign(x))') - plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') + plt.title("Softsign Activation Function") + plt.xlabel("Input (x)") + plt.ylabel("Output (Softsign(x))") + plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") # Add zero lines and asymptotes - plt.axhline(y=0, color='k', linestyle='--', alpha=0.3) - plt.axvline(x=0, color='k', linestyle='--', alpha=0.3) - plt.axhline(y=1, color='r', linestyle=':', alpha=0.3, label='Upper asymptote (y=1)') - plt.axhline(y=-1, color='r', linestyle=':', alpha=0.3, label='Lower asymptote (y=-1)') - - plot_display = mo.vstack([ - mo.as_html(plt.gca()), - ]) + plt.axhline(y=0, color="k", linestyle="--", alpha=0.3) + plt.axvline(x=0, color="k", linestyle="--", alpha=0.3) + plt.axhline( + y=1, color="r", linestyle=":", alpha=0.3, label="Upper asymptote (y=1)" + ) + plt.axhline( + y=-1, color="r", linestyle=":", alpha=0.3, label="Lower asymptote (y=-1)" + ) + + plot_display = mo.vstack( + [ + mo.as_html(plt.gca()), + ] + ) return plot_display + return (plot_softsign,) @@ -204,9 +218,10 @@ def _(plot_softsign): @app.cell def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've explored the Softsign activation function interactively. You've learned: @@ -214,30 +229,33 @@ def _(mo): - Its smooth behavior and slower saturation - Why it can be an alternative to tanh """), - kind="success" - ), - mo.accordion({ - "Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "Next Steps": mo.md(""" 1. **Implementation:** Try implementing Softsign from scratch 2. **Compare:** Explore how it differs from tanh 3. **Experiment:** Test it in a neural network 4. **Advanced:** Learn about other bounded activation functions """), - "🎯 Common Applications": mo.md(""" + "🎯 Common Applications": mo.md(""" - Deep neural networks - When smooth gradients are important - Situations where bounded outputs are needed - Alternative to tanh activation - When slower saturation is beneficial """), - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(mo): - mo.md(f""" + mo.md(""" This interactive learning experience was designed to help you understand the Softsign activation function. Hope this helps in your deep learning journey! """) return @@ -252,6 +270,7 @@ def _(conclusion): @app.cell(hide_code=True) def _(): import marimo as mo + return (mo,) @@ -259,6 +278,7 @@ def _(): def _(): import numpy as np import matplotlib.pyplot as plt + return np, plt diff --git a/old_repo/Problems/interactive_learn/problem-tanh/notebook.py b/old_repo/Problems/interactive_learn/problem-tanh/notebook.py index 80c56048..0173ce47 100644 --- a/old_repo/Problems/interactive_learn/problem-tanh/notebook.py +++ b/old_repo/Problems/interactive_learn/problem-tanh/notebook.py @@ -10,7 +10,9 @@ import marimo __generated_with = "0.10.12" -app = marimo.App(css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css") +app = marimo.App( + css_file="/Users/adityakhalkar/Library/Application Support/mtheme/themes/deepml.css" +) @app.cell(hide_code=True) @@ -42,18 +44,14 @@ def _(mo): where $\sigma(x)$ is the sigmoid function. This creates a smooth, S-shaped function that maps inputs to the range [-1, 1]. """) - mo.accordion({"### Mathematical Definition" : value}) + mo.accordion({"### Mathematical Definition": value}) return (value,) @app.cell def _(mo): steepness = mo.ui.slider( - start=0.1, - stop=2.0, - value=1.0, - step=0.1, - label="Steepness" + start=0.1, stop=2.0, value=1.0, step=0.1, label="Steepness" ) _callout = mo.callout( @@ -66,62 +64,60 @@ def _(mo): - Lower values make the transition more gradual - Default value of 1.0 gives the standard tanh """), - kind="info" + kind="info", ) x_range = mo.ui.range_slider( - start=-10, - stop=10, - step=0.5, - value=[-5, 5], - label="X-axis Range" + start=-10, stop=10, step=0.5, value=[-5, 5], label="X-axis Range" ) - controls = mo.vstack([ - mo.md("### Adjust Parameters"), - mo.hstack([ - mo.vstack([ - steepness, - mo.accordion({ - "About Steepness": _callout - }) - ]), - mo.vstack([ - x_range, - mo.accordion({ - "About Range": "Adjust to see different regions of the function." - }) - ]) - ]) - ]) + controls = mo.vstack( + [ + mo.md("### Adjust Parameters"), + mo.hstack( + [ + mo.vstack([steepness, mo.accordion({"About Steepness": _callout})]), + mo.vstack( + [ + x_range, + mo.accordion( + { + "About Range": "Adjust to see different regions of the function." + } + ), + ] + ), + ] + ), + ] + ) return controls, steepness, x_range @app.cell def _(mo): test_input = mo.ui.number( - value=0.0, - start=-10, - stop=10, - step=0.1, - label="Test Input Value" + value=0.0, start=-10, stop=10, step=0.1, label="Test Input Value" ) - input_controls = mo.vstack([ - mo.md("### Test Specific Values"), - test_input, - mo.accordion({ - "About Testing": "Enter specific values to see their tanh outputs." - }) - ]) + input_controls = mo.vstack( + [ + mo.md("### Test Specific Values"), + test_input, + mo.accordion( + {"About Testing": "Enter specific values to see their tanh outputs."} + ), + ] + ) return input_controls, test_input @app.cell def _(mo, steepness): - formula_display = mo.vstack([ - mo.md( - f""" + formula_display = mo.vstack( + [ + mo.md( + f""" ### Current Tanh Configuration With steepness parameter $s = {steepness.value:.1f}$, the current tanh function is: @@ -136,8 +132,9 @@ def _(mo, steepness): - Steeper gradient near origin compared to sigmoid - Outputs centered around zero """ - ), - ]) + ), + ] + ) return (formula_display,) @@ -152,7 +149,9 @@ def _(mo, np, plt, steepness, test_input, x_range): @mo.cache(pin_modules=True) def plot_tanh(): if x_range.value[0] >= x_range.value[1]: - raise ValueError("Invalid x_range: start value must be less than stop value.") + raise ValueError( + "Invalid x_range: start value must be less than stop value." + ) x = np.linspace(x_range.value[0], x_range.value[1], 1000) y = np.tanh(steepness.value * x) @@ -160,44 +159,46 @@ def plot_tanh(): plt.figure(figsize=(12, 7)) # Plot main function - plt.plot(x, y, - label='tanh function', - color='blue', - linewidth=2) + plt.plot(x, y, label="tanh function", color="blue", linewidth=2) # Plot derivative (serves as a reference) derivative = steepness.value * (1 - y**2) - plt.plot(x, derivative, - label='Derivative', - color='red', - linestyle='--', - alpha=0.5) + plt.plot( + x, derivative, label="Derivative", color="red", linestyle="--", alpha=0.5 + ) # Plot test point if within range (adjust if needed accordingly) if x_range.value[0] <= test_input.value <= x_range.value[1]: test_output = np.tanh(steepness.value * test_input.value) - plt.scatter([test_input.value], [test_output], - color='green', s=100, - label=f'Test point: f({test_input.value:.2f}) = {test_output:.2f}') + plt.scatter( + [test_input.value], + [test_output], + color="green", + s=100, + label=f"Test point: f({test_input.value:.2f}) = {test_output:.2f}", + ) plt.grid(True, alpha=0.3) - plt.title(f'Tanh Function (steepness = {steepness.value:.1f})') - plt.xlabel('Input (x)') - plt.ylabel('Output (tanh(x))') - plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') + plt.title(f"Tanh Function (steepness = {steepness.value:.1f})") + plt.xlabel("Input (x)") + plt.ylabel("Output (tanh(x))") + plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") # Add horizontal bounds at -1 and 1 - plt.axhline(y=-1, color='gray', linestyle=':', alpha=0.5) - plt.axhline(y=1, color='gray', linestyle=':', alpha=0.5) + plt.axhline(y=-1, color="gray", linestyle=":", alpha=0.5) + plt.axhline(y=1, color="gray", linestyle=":", alpha=0.5) # Add zero lines - plt.axhline(y=0, color='k', linestyle='--', alpha=0.3) - plt.axvline(x=0, color='k', linestyle='--', alpha=0.3) + plt.axhline(y=0, color="k", linestyle="--", alpha=0.3) + plt.axvline(x=0, color="k", linestyle="--", alpha=0.3) - plot_display = mo.vstack([ - mo.as_html(plt.gca()), - ]) + plot_display = mo.vstack( + [ + mo.as_html(plt.gca()), + ] + ) return plot_display + return (plot_tanh,) @@ -221,9 +222,10 @@ def _(plot_tanh): @app.cell def _(mo): - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Key Takeaways!** Through this interactive exploration of the tanh function, you've learned: @@ -231,30 +233,33 @@ def _(mo): - The effect of steepness on the function's shape - The symmetric nature of the function """), - kind="success" - ), - mo.accordion({ - "Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "Next Steps": mo.md(""" 1. **Implementation:** Try using tanh in your neural networks 2. **Compare:** Analyze performance vs sigmoid and other activations 3. **Experiment:** Study the vanishing gradient problem 4. **Advanced:** Explore tanh in RNNs and LSTMs """), - "🎯 Common Applications": mo.md(""" + "🎯 Common Applications": mo.md(""" - Recurrent Neural Networks (RNNs) - Long Short-Term Memory (LSTM) networks - Binary classification tasks - When zero-centered outputs are needed - Financial time series prediction """), - }) - ]) + } + ), + ] + ) return (conclusion,) @app.cell def _(mo): - mo.md(f""" + mo.md(""" This interactive learning experience was designed to help you understand the hyperbolic tangent (tanh) activation function. Hope this helps in your deep learning journey! """) return @@ -269,6 +274,7 @@ def _(conclusion): @app.cell(hide_code=True) def _(): import marimo as mo + return (mo,) @@ -276,6 +282,7 @@ def _(): def _(): import numpy as np import matplotlib.pyplot as plt + return np, plt diff --git a/old_repo/app.py b/old_repo/app.py index 2c86cbd7..40114c7d 100644 --- a/old_repo/app.py +++ b/old_repo/app.py @@ -4,13 +4,14 @@ import os import re + def render_learn_section(learn_section): # Replace LaTeX delimiters with the appropriate format for MathJax - learn_section = re.sub(r'\\\(', r'$', learn_section) - learn_section = re.sub(r'\\\)', r'$', learn_section) - learn_section = re.sub(r'\\\[', r'$$', learn_section) - learn_section = re.sub(r'\\\]', r'$$', learn_section) - + learn_section = re.sub(r"\\\(", r"$", learn_section) + learn_section = re.sub(r"\\\)", r"$", learn_section) + learn_section = re.sub(r"\\\[", r"$$", learn_section) + learn_section = re.sub(r"\\\]", r"$$", learn_section) + st.subheader("Learn Section Preview") components.html( f""" @@ -36,24 +37,28 @@ def render_learn_section(learn_section): height=1000, ) + # Define the directory containing the learn.html files LEARN_HTML_DIR = "Problems" + def load_file(file_path): try: - with open(file_path, 'r', encoding='utf-8') as file: + with open(file_path, "r", encoding="utf-8") as file: return file.read() except Exception as e: st.error(f"Error loading file {file_path}: {e}") return "" + def save_file(file_path, content): try: - with open(file_path, 'w', encoding='utf-8') as file: + with open(file_path, "w", encoding="utf-8") as file: file.write(content) except Exception as e: st.error(f"Error saving file {file_path}: {e}") + # Streamlit app st.title("Learn Section Editor") @@ -68,7 +73,9 @@ def save_file(file_path, content): st.warning("No learn.html files found.") else: # File selector - selected_file = st.selectbox("Select an HTML file to edit", html_files, key="file_selector") + selected_file = st.selectbox( + "Select an HTML file to edit", html_files, key="file_selector" + ) if selected_file: # Load the content of the selected file @@ -79,7 +86,9 @@ def save_file(file_path, content): editor_key = f"editor_{selected_file}" # Display the editor with the current file content - edited_content = st_ace(value=content, language='html', theme='monokai', key=editor_key) + edited_content = st_ace( + value=content, language="html", theme="monokai", key=editor_key + ) if st.button("RENDER"): st.session_state["rendered_html"] = edited_content diff --git a/old_repo/example_problem/solution.py b/old_repo/example_problem/solution.py index 4a03ea8c..1d8147ff 100644 --- a/old_repo/example_problem/solution.py +++ b/old_repo/example_problem/solution.py @@ -28,12 +28,13 @@ def test_matrix_dot_vector() -> None: a: list[list[int | float]] = [[1, 2], [2, 4]] b: list[int | float] = [1, 2] assert matrix_dot_vector(a, b) == [5, 10] - - # valid product with rectangular matrix (non-square) -- > if we changed "for j in range(len(a[i]))" to "for j in range(len(a))" previous tests will pass + + # valid product with rectangular matrix (non-square) -- > if we changed "for j in range(len(a[i]))" to "for j in range(len(a))" previous tests will pass a: list[list[int | float]] = [[1, 2, 3], [2, 4, 6]] b: list[int | float] = [1, 2, 3] assert matrix_dot_vector(a, b) == [14, 28] + if __name__ == "__main__": test_matrix_dot_vector() print("All tests passed.") diff --git a/old_repo/notebook.py b/old_repo/notebook.py index e05ac49c..27a68299 100644 --- a/old_repo/notebook.py +++ b/old_repo/notebook.py @@ -14,13 +14,14 @@ __generated_with = "0.11.31" app = marimo.App(width="medium") + @app.cell(hide_code=True) def _(mo): # Key concepts accordion - - insights = mo.accordion({ - "🎯 Understanding Covariance": mo.md(""" + insights = mo.accordion( + { + "🎯 Understanding Covariance": mo.md(""" **Key Concepts:** 1. **Variance**: Measures spread of a single variable @@ -31,8 +32,7 @@ def _(mo): 4. **Interpretation**: Direction and strength of relationships """), - - "📊 Matrix Properties": mo.md(""" + "📊 Matrix Properties": mo.md(""" The covariance matrix has important properties: 1. **Symmetry**: cov(X,Y) = cov(Y,X) @@ -43,8 +43,7 @@ def _(mo): 4. **Positive Semi-definite**: All eigenvalues ≥ 0 """), - - "🔄 Covariance vs. Correlation": mo.md(""" + "🔄 Covariance vs. Correlation": mo.md(""" **Important Distinction:** 1. **Covariance**: Depends on the scale of the variables @@ -56,17 +55,19 @@ def _(mo): - Always ranges from -1 to 1 - Easier to interpret: 1 (perfect positive), -1 (perfect negative), 0 (no relationship) - Formula: $corr(X,Y) = \\frac{cov(X,Y)}{\\sigma_X \\sigma_Y}$ - """) - }) + """), + } + ) return (insights,) + @app.cell(hide_code=True) def _(mo): # Practice exercises - exercises = mo.accordion({ - - "🎯 Practice Exercises": mo.md(""" + exercises = mo.accordion( + { + "🎯 Practice Exercises": mo.md(""" Try these examples to understand covariance better: @@ -85,9 +86,7 @@ def _(mo): What do you notice about the covariance vs correlation matrices? """), - - - "💡 Tips for Interpretation": mo.md(""" + "💡 Tips for Interpretation": mo.md(""" - Large positive values: Strong positive relationship @@ -101,11 +100,12 @@ def _(mo): - Correlation is easier to interpret consistently (-1 to 1) - Covariance magnitude depends on your variable units - """) - - }) + """), + } + ) return (exercises,) + @app.cell def _(calculate_button, data_matrix, mo, np, pd, px): results = None @@ -115,7 +115,7 @@ def _(calculate_button, data_matrix, mo, np, pd, px): data = np.array(data_matrix.matrix, dtype=float) if data.shape[0] != 2: raise ValueError("Data must have exactly 2 rows (variables)") - + # Check if we have enough data points if data.shape[1] < 2: raise ValueError("Need at least 2 data points for analysis") @@ -126,22 +126,15 @@ def _(calculate_button, data_matrix, mo, np, pd, px): cov_matrix = np.cov(data) # 3. visualization with covariance matrix - df = pd.DataFrame({ - 'x': data[0], - 'y': data[1] - }) + df = pd.DataFrame({"x": data[0], "y": data[1]}) scatter_fig = px.scatter( df, - x='x', - y='y', + x="x", + y="y", title="Variable Relationship Pattern", - labels={'x': 'Variable 1', 'y': 'Variable 2'} - ).update_layout( - width=400, - height=400, - showlegend=False - ) + labels={"x": "Variable 1", "y": "Variable 2"}, + ).update_layout(width=400, height=400, showlegend=False) # appropriate trendline - with error handling for edge cases try: @@ -150,36 +143,42 @@ def _(calculate_button, data_matrix, mo, np, pd, px): x_range = np.linspace(min(data[0]), max(data[0]), 100) scatter_fig.add_trace( dict( - type='scatter', + type="scatter", x=x_range, y=coeffs[0] * x_range + coeffs[1], - mode='lines', - line=dict(color='red', dash='dash'), - name='Trend' + mode="lines", + line=dict(color="red", dash="dash"), + name="Trend", ) ) else: coeffs = (0, 0) # Default no slope - x_range = np.array([min(data[0]), max(data[0])]) if len(data[0]) > 0 else np.array([0, 1]) - except Exception as trend_error: + x_range = ( + np.array([min(data[0]), max(data[0])]) + if len(data[0]) > 0 + else np.array([0, 1]) + ) + except Exception: coeffs = (0, 0) # Default fallback x_range = np.array([0, 1]) - + # Calculate correlation coefficient corr_matrix = np.corrcoef(data) # 4. results with relevant explanations - results = mo.vstack([ - mo.md("## Understanding Your Data's Covariance"), - - # First row: Plot and Matrix - mo.hstack([ - # scatter plot - mo.vstack([scatter_fig]), - - # covariance matrix - mo.vstack([ - mo.md(r""" + results = mo.vstack( + [ + mo.md("## Understanding Your Data's Covariance"), + # First row: Plot and Matrix + mo.hstack( + [ + # scatter plot + mo.vstack([scatter_fig]), + # covariance matrix + mo.vstack( + [ + mo.md( + r""" **Covariance Matrix:** $$ @@ -188,12 +187,16 @@ def _(calculate_button, data_matrix, mo, np, pd, px): %.2f & %.2f \end{pmatrix} $$ - """ % ( - cov_matrix[0,0], cov_matrix[0,1], - cov_matrix[1,0], cov_matrix[1,1] - )), - - mo.md(r""" + """ + % ( + cov_matrix[0, 0], + cov_matrix[0, 1], + cov_matrix[1, 0], + cov_matrix[1, 1], + ) + ), + mo.md( + r""" **Correlation Matrix:** $$ @@ -202,18 +205,24 @@ def _(calculate_button, data_matrix, mo, np, pd, px): %.2f & %.2f \end{pmatrix} $$ - """ % ( - corr_matrix[0,0], corr_matrix[0,1], - corr_matrix[1,0], corr_matrix[1,1] - )) - ]) - ]), - - # interpretation and insights side by side - mo.hstack([ - # Left: Pattern Interpretation - mo.callout( - mo.md(""" + """ + % ( + corr_matrix[0, 0], + corr_matrix[0, 1], + corr_matrix[1, 0], + corr_matrix[1, 1], + ) + ), + ] + ), + ] + ), + # interpretation and insights side by side + mo.hstack( + [ + # Left: Pattern Interpretation + mo.callout( + mo.md(""" **Pattern Interpretation:** @@ -229,20 +238,19 @@ def _(calculate_button, data_matrix, mo, np, pd, px): - Off-diagonal: Show relationship strength """), - kind="info" - ), - - # Right: Key Insights - mo.callout( - mo.md(f""" + kind="info", + ), + # Right: Key Insights + mo.callout( + mo.md(f""" **Key Insights:** - 1. Relationship: {"Positive" if cov_matrix[0,1] > 0 else "Negative" if cov_matrix[0,1] < 0 else "No"} covariance + 1. Relationship: {"Positive" if cov_matrix[0, 1] > 0 else "Negative" if cov_matrix[0, 1] < 0 else "No"} covariance - 2. Strength: {"Strong" if abs(corr_matrix[0,1]) > 0.7 else "Moderate" if abs(corr_matrix[0,1]) > 0.3 else "Weak"} correlation ({corr_matrix[0,1]:.2f}) + 2. Strength: {"Strong" if abs(corr_matrix[0, 1]) > 0.7 else "Moderate" if abs(corr_matrix[0, 1]) > 0.3 else "Weak"} correlation ({corr_matrix[0, 1]:.2f}) - 3. Variances: ({cov_matrix[0,0]:.2f}, {cov_matrix[1,1]:.2f}) + 3. Variances: ({cov_matrix[0, 0]:.2f}, {cov_matrix[1, 1]:.2f}) **Centered Data:** ```python @@ -252,15 +260,20 @@ def _(calculate_button, data_matrix, mo, np, pd, px): Var2: {np.round(centered_data[1], 2)} ``` """), - kind="neutral" - ) - ]) - ], justify='center') + kind="neutral", + ), + ] + ), + ], + justify="center", + ) except Exception as e: results = mo.md(f"⚠️ Error: {str(e)}").callout(kind="danger") # Initialize variables to None to avoid reference errors in case of exception - centered_data = coeffs = cov_matrix = data = df = means = scatter_fig = x_range = corr_matrix = None + centered_data = coeffs = cov_matrix = data = df = means = scatter_fig = ( + x_range + ) = corr_matrix = None results return ( centered_data, @@ -275,12 +288,14 @@ def _(calculate_button, data_matrix, mo, np, pd, px): x_range, ) + @app.cell(hide_code=True) def _(mo): # Conclusion - conclusion = mo.vstack([ - mo.callout( - mo.md(""" + conclusion = mo.vstack( + [ + mo.callout( + mo.md(""" **Congratulations!** You've mastered the key concepts of covariance matrices: @@ -292,12 +307,11 @@ def _(mo): - The importance of centered data """), - kind="success" - ), - - mo.accordion({ - - "🚀 Next Steps": mo.md(""" + kind="success", + ), + mo.accordion( + { + "🚀 Next Steps": mo.md(""" 1. Work with multivariate datasets (3+ variables) 2. Apply to real-world datasets with different scales @@ -305,6 +319,8 @@ def _(mo): 4. Implement in machine learning projects """) - }) - ]) - return (conclusion,) \ No newline at end of file + } + ), + ] + ) + return (conclusion,) diff --git a/questions/100_implement-the-softsign-activation-function/starter_code.py b/questions/100_implement-the-softsign-activation-function/starter_code.py index 28ec96a5..694a0b70 100644 --- a/questions/100_implement-the-softsign-activation-function/starter_code.py +++ b/questions/100_implement-the-softsign-activation-function/starter_code.py @@ -1,12 +1,12 @@ def softsign(x: float) -> float: - """ - Implements the Softsign activation function. + """ + Implements the Softsign activation function. - Args: - x (float): Input value + Args: + x (float): Input value - Returns: - float: The Softsign of the input """ - # Your code here - pass - return round(val,4) + Returns: + float: The Softsign of the input""" + # Your code here + pass + return round(val, 4) diff --git a/questions/101_implement-the-grpo-objective-function/solution.py b/questions/101_implement-the-grpo-objective-function/solution.py index 32d5432b..9747d201 100644 --- a/questions/101_implement-the-grpo-objective-function/solution.py +++ b/questions/101_implement-the-grpo-objective-function/solution.py @@ -1,6 +1,9 @@ import numpy as np -def grpo_objective(rhos, A, pi_theta_old, pi_theta_ref, epsilon=0.2, beta=0.01) -> float: + +def grpo_objective( + rhos, A, pi_theta_old, pi_theta_ref, epsilon=0.2, beta=0.01 +) -> float: """ Compute the GRPO objective function. @@ -18,27 +21,29 @@ def grpo_objective(rhos, A, pi_theta_old, pi_theta_ref, epsilon=0.2, beta=0.01) G = len(rhos) if not (len(A) == len(pi_theta_old) == len(pi_theta_ref) == G): raise ValueError("All input lists must have the same length.") - + # Compute clipped likelihood ratios clipped_rhos = np.clip(rhos, 1 - epsilon, 1 + epsilon) - + # Compute the minimum terms for the objective unclipped = np.array(rhos) * np.array(A) clipped = clipped_rhos * np.array(A) min_terms = np.minimum(unclipped, clipped) average_min = np.mean(min_terms) - + # Compute pi_theta from rhos and pi_theta_old pi_theta = np.array(rhos) * np.array(pi_theta_old) - + # Normalize pi_theta and pi_theta_ref to ensure they are valid probability distributions pi_theta /= np.sum(pi_theta) pi_theta_ref /= np.sum(pi_theta_ref) - + # Compute KL divergence D_KL(pi_theta || pi_theta_ref) - kl_divergence = np.sum(pi_theta * np.log(pi_theta / pi_theta_ref + 1e-10)) # Added epsilon to avoid log(0) - + kl_divergence = np.sum( + pi_theta * np.log(pi_theta / pi_theta_ref + 1e-10) + ) # Added epsilon to avoid log(0) + # Compute the final objective objective = average_min - beta * kl_divergence - + return objective diff --git a/questions/101_implement-the-grpo-objective-function/starter_code.py b/questions/101_implement-the-grpo-objective-function/starter_code.py index ccde54a2..311c92a4 100644 --- a/questions/101_implement-the-grpo-objective-function/starter_code.py +++ b/questions/101_implement-the-grpo-objective-function/starter_code.py @@ -1,19 +1,19 @@ -import numpy as np +def grpo_objective( + rhos, A, pi_theta_old, pi_theta_ref, epsilon=0.2, beta=0.01 +) -> float: + """ + Compute the GRPO objective function. -def grpo_objective(rhos, A, pi_theta_old, pi_theta_ref, epsilon=0.2, beta=0.01) -> float: - """ - Compute the GRPO objective function. + Args: + rhos: List of likelihood ratios (p_i) = pi_theta(o_i | q) / pi_theta_old(o_i | q). + A: List of advantage estimates (A_i). + pi_theta_old: List representing the old policy probabilities pi_theta_old(o_i | q). + pi_theta_ref: List representing the reference policy probabilities pi_ref(o_i | q). + epsilon: Clipping parameter (eps). + beta: KL divergence penalty coefficient (beta). - Args: - rhos: List of likelihood ratios (p_i) = pi_theta(o_i | q) / pi_theta_old(o_i | q). - A: List of advantage estimates (A_i). - pi_theta_old: List representing the old policy probabilities pi_theta_old(o_i | q). - pi_theta_ref: List representing the reference policy probabilities pi_ref(o_i | q). - epsilon: Clipping parameter (eps). - beta: KL divergence penalty coefficient (beta). - - Returns: - The computed GRPO objective value. - """ - # Your code here - pass + Returns: + The computed GRPO objective value. + """ + # Your code here + pass diff --git a/questions/102_implement-the-swish-activation-function/solution.py b/questions/102_implement-the-swish-activation-function/solution.py index e510aac8..be3e93fe 100644 --- a/questions/102_implement-the-swish-activation-function/solution.py +++ b/questions/102_implement-the-swish-activation-function/solution.py @@ -1,5 +1,6 @@ import math + def swish(x: float) -> float: """ Implements the Swish activation function. diff --git a/questions/102_implement-the-swish-activation-function/starter_code.py b/questions/102_implement-the-swish-activation-function/starter_code.py index a198140f..86949b83 100644 --- a/questions/102_implement-the-swish-activation-function/starter_code.py +++ b/questions/102_implement-the-swish-activation-function/starter_code.py @@ -1,12 +1,12 @@ def swish(x: float) -> float: - """ - Implements the Swish activation function. + """ + Implements the Swish activation function. - Args: - x: Input value + Args: + x: Input value - Returns: - The Swish activation value - """ - # Your code here - pass + Returns: + The Swish activation value + """ + # Your code here + pass diff --git a/questions/103_implement-the-selu-activation-function/solution.py b/questions/103_implement-the-selu-activation-function/solution.py index 41caa2c8..37552ea9 100644 --- a/questions/103_implement-the-selu-activation-function/solution.py +++ b/questions/103_implement-the-selu-activation-function/solution.py @@ -1,5 +1,6 @@ import math + def selu(x: float) -> float: """ Implements the SELU (Scaled Exponential Linear Unit) activation function. diff --git a/questions/103_implement-the-selu-activation-function/starter_code.py b/questions/103_implement-the-selu-activation-function/starter_code.py index 5827c91b..38c25950 100644 --- a/questions/103_implement-the-selu-activation-function/starter_code.py +++ b/questions/103_implement-the-selu-activation-function/starter_code.py @@ -1,14 +1,12 @@ def selu(x: float) -> float: - """ - Implements the SELU (Scaled Exponential Linear Unit) activation function. + """ + Implements the SELU (Scaled Exponential Linear Unit) activation function. - Args: - x: Input value + Args: + x: Input value - Returns: - SELU activation value - """ - alpha = 1.6732632423543772 - scale = 1.0507009873554804 - # Your code here - pass + Returns: + SELU activation value + """ + # Your code here + pass diff --git a/questions/104_binary-classification-with-logistic-regression/solution.py b/questions/104_binary-classification-with-logistic-regression/solution.py index ed5de9a2..030c45ae 100644 --- a/questions/104_binary-classification-with-logistic-regression/solution.py +++ b/questions/104_binary-classification-with-logistic-regression/solution.py @@ -1,5 +1,6 @@ import numpy as np + def predict_logistic(X: np.ndarray, weights: np.ndarray, bias: float) -> np.ndarray: """ Implements binary classification prediction using Logistic Regression. diff --git a/questions/104_binary-classification-with-logistic-regression/starter_code.py b/questions/104_binary-classification-with-logistic-regression/starter_code.py index 7af3a008..720e9aef 100644 --- a/questions/104_binary-classification-with-logistic-regression/starter_code.py +++ b/questions/104_binary-classification-with-logistic-regression/starter_code.py @@ -1,16 +1,17 @@ import numpy as np + def predict_logistic(X: np.ndarray, weights: np.ndarray, bias: float) -> np.ndarray: - """ - Implements binary classification prediction using Logistic Regression. + """ + Implements binary classification prediction using Logistic Regression. - Args: - X: Input feature matrix (shape: N x D) - weights: Model weights (shape: D) - bias: Model bias + Args: + X: Input feature matrix (shape: N x D) + weights: Model weights (shape: D) + bias: Model bias - Returns: - Binary predictions (0 or 1) - """ - # Your code here - pass + Returns: + Binary predictions (0 or 1) + """ + # Your code here + pass diff --git a/questions/105_train-softmax-regression-with-gradient-descent/solution.py b/questions/105_train-softmax-regression-with-gradient-descent/solution.py index 55b2ea21..2f886ec7 100644 --- a/questions/105_train-softmax-regression-with-gradient-descent/solution.py +++ b/questions/105_train-softmax-regression-with-gradient-descent/solution.py @@ -1,9 +1,10 @@ import numpy as np -def train_softmaxreg(X: np.ndarray, y: np.ndarray, - learning_rate: float, iterations: int) -> tuple[list[float], ...]: - ''' +def train_softmaxreg( + X: np.ndarray, y: np.ndarray, learning_rate: float, iterations: int +) -> tuple[list[float], ...]: + """ Gradient-descent training algorithm for softmax regression, that collects mean-reduced CE losses, accuracies. Returns @@ -12,20 +13,22 @@ def train_softmaxreg(X: np.ndarray, y: np.ndarray, CxM updated parameter vector rounded to 4 floating points losses : list[float] collected values of a Cross Entropy rounded to 4 floating points - ''' + """ def softmax(z): return np.exp(z) / np.sum(np.exp(z), axis=1, keepdims=True) def accuracy(y_pred, y_true): - return (np.argmax(y_true, axis=1) == np.argmax(y_pred, axis=1)).sum() / len(y_true) + return (np.argmax(y_true, axis=1) == np.argmax(y_pred, axis=1)).sum() / len( + y_true + ) def ce_loss(y_pred, y_true): true_labels_idx = np.argmax(y_true, axis=1) - return -np.sum(np.log(y_pred)[list(range(len(y_pred))),true_labels_idx]) + return -np.sum(np.log(y_pred)[list(range(len(y_pred))), true_labels_idx]) y = y.astype(int) - C = y.max()+1 # we assume that classes start from 0 + C = y.max() + 1 # we assume that classes start from 0 y = np.eye(C)[y] X = np.hstack((np.ones((X.shape[0], 1)), X)) B = np.zeros((X.shape[1], C)) diff --git a/questions/105_train-softmax-regression-with-gradient-descent/starter_code.py b/questions/105_train-softmax-regression-with-gradient-descent/starter_code.py index 0e93e504..3f984a8d 100644 --- a/questions/105_train-softmax-regression-with-gradient-descent/starter_code.py +++ b/questions/105_train-softmax-regression-with-gradient-descent/starter_code.py @@ -1,8 +1,11 @@ import numpy as np -def train_softmaxreg(X: np.ndarray, y: np.ndarray, learning_rate: float, iterations: int) -> tuple[list[float], ...]: - """ - Gradient-descent training algorithm for Softmax regression, optimizing parameters with Cross Entropy loss. - """ - # Your code here - pass + +def train_softmaxreg( + X: np.ndarray, y: np.ndarray, learning_rate: float, iterations: int +) -> tuple[list[float], ...]: + """ + Gradient-descent training algorithm for Softmax regression, optimizing parameters with Cross Entropy loss. + """ + # Your code here + pass diff --git a/questions/106_train-logistic-regression-with-gradient-descent/solution.py b/questions/106_train-logistic-regression-with-gradient-descent/solution.py index 8db5fae1..742283a7 100644 --- a/questions/106_train-logistic-regression-with-gradient-descent/solution.py +++ b/questions/106_train-logistic-regression-with-gradient-descent/solution.py @@ -1,9 +1,13 @@ import numpy as np -def train_logreg(X: np.ndarray, y: np.ndarray, learning_rate: float, iterations: int) -> tuple[list[float], ...]: + +def train_logreg( + X: np.ndarray, y: np.ndarray, learning_rate: float, iterations: int +) -> tuple[list[float], ...]: """ Gradient-descent training algorithm for logistic regression, optimizing parameters with Binary Cross Entropy loss. """ + def sigmoid(x): return 1 / (1 + np.exp(-x)) diff --git a/questions/106_train-logistic-regression-with-gradient-descent/starter_code.py b/questions/106_train-logistic-regression-with-gradient-descent/starter_code.py index 29bd086c..71eb660f 100644 --- a/questions/106_train-logistic-regression-with-gradient-descent/starter_code.py +++ b/questions/106_train-logistic-regression-with-gradient-descent/starter_code.py @@ -1,8 +1,11 @@ import numpy as np -def train_logreg(X: np.ndarray, y: np.ndarray, learning_rate: float, iterations: int) -> tuple[list[float], ...]: - """ - Gradient-descent training algorithm for logistic regression, optimizing parameters with Binary Cross Entropy loss. - """ - # Your code here - pass + +def train_logreg( + X: np.ndarray, y: np.ndarray, learning_rate: float, iterations: int +) -> tuple[list[float], ...]: + """ + Gradient-descent training algorithm for logistic regression, optimizing parameters with Binary Cross Entropy loss. + """ + # Your code here + pass diff --git a/questions/107_implement-masked-self-attention/solution.py b/questions/107_implement-masked-self-attention/solution.py index c78be60f..291bbf5f 100644 --- a/questions/107_implement-masked-self-attention/solution.py +++ b/questions/107_implement-masked-self-attention/solution.py @@ -1,15 +1,21 @@ import numpy as np + def compute_qkv(X: np.ndarray, W_q: np.ndarray, W_k: np.ndarray, W_v: np.ndarray): Q = np.dot(X, W_q) K = np.dot(X, W_k) V = np.dot(X, W_v) return Q, K, V -def masked_attention(Q: np.ndarray, K: np.ndarray, V: np.ndarray, mask: np.ndarray) -> np.ndarray: + +def masked_attention( + Q: np.ndarray, K: np.ndarray, V: np.ndarray, mask: np.ndarray +) -> np.ndarray: d_k = Q.shape[1] scores = np.matmul(Q, K.T) / np.sqrt(d_k) scores = scores + mask # Apply mask attention_weights = np.exp(scores - np.max(scores, axis=1, keepdims=True)) - attention_weights = attention_weights / np.sum(attention_weights, axis=1, keepdims=True) + attention_weights = attention_weights / np.sum( + attention_weights, axis=1, keepdims=True + ) return np.matmul(attention_weights, V) diff --git a/questions/107_implement-masked-self-attention/starter_code.py b/questions/107_implement-masked-self-attention/starter_code.py index 48a14241..2f5aeabe 100644 --- a/questions/107_implement-masked-self-attention/starter_code.py +++ b/questions/107_implement-masked-self-attention/starter_code.py @@ -1,14 +1,18 @@ import numpy as np + def compute_qkv(X: np.ndarray, W_q: np.ndarray, W_k: np.ndarray, W_v: np.ndarray): - """ - Compute Query (Q), Key (K), and Value (V) matrices. - """ - return np.dot(X, W_q), np.dot(X, W_k), np.dot(X, W_v) - -def masked_attention(Q: np.ndarray, K: np.ndarray, V: np.ndarray, mask: np.ndarray) -> np.ndarray: - """ - Compute masked self-attention. - """ - # Your code here - pass + """ + Compute Query (Q), Key (K), and Value (V) matrices. + """ + return np.dot(X, W_q), np.dot(X, W_k), np.dot(X, W_v) + + +def masked_attention( + Q: np.ndarray, K: np.ndarray, V: np.ndarray, mask: np.ndarray +) -> np.ndarray: + """ + Compute masked self-attention. + """ + # Your code here + pass diff --git a/questions/108_measure-disorder-in-apple-colors/starter_code.py b/questions/108_measure-disorder-in-apple-colors/starter_code.py index 8c8f45cc..f7ea83ec 100644 --- a/questions/108_measure-disorder-in-apple-colors/starter_code.py +++ b/questions/108_measure-disorder-in-apple-colors/starter_code.py @@ -1,6 +1,6 @@ def disorder(apples: list) -> float: - """ - Compute the disorder in a basket of apples. - """ - # Your code here - pass + """ + Compute the disorder in a basket of apples. + """ + # Your code here + pass diff --git a/questions/109_implement-layer-normalization-for-sequence-data/solution.py b/questions/109_implement-layer-normalization-for-sequence-data/solution.py index 7e7c8afb..6cb956f6 100644 --- a/questions/109_implement-layer-normalization-for-sequence-data/solution.py +++ b/questions/109_implement-layer-normalization-for-sequence-data/solution.py @@ -1,6 +1,9 @@ import numpy as np -def layer_normalization(X: np.ndarray, gamma: np.ndarray, beta: np.ndarray, epsilon: float = 1e-5) -> np.ndarray: + +def layer_normalization( + X: np.ndarray, gamma: np.ndarray, beta: np.ndarray, epsilon: float = 1e-5 +) -> np.ndarray: """ Perform Layer Normalization. """ diff --git a/questions/109_implement-layer-normalization-for-sequence-data/starter_code.py b/questions/109_implement-layer-normalization-for-sequence-data/starter_code.py index 113b2986..b2de3d93 100644 --- a/questions/109_implement-layer-normalization-for-sequence-data/starter_code.py +++ b/questions/109_implement-layer-normalization-for-sequence-data/starter_code.py @@ -1,8 +1,11 @@ import numpy as np -def layer_normalization(X: np.ndarray, gamma: np.ndarray, beta: np.ndarray, epsilon: float = 1e-5) -> np.ndarray: - """ - Perform Layer Normalization. - """ - # Your code here - pass + +def layer_normalization( + X: np.ndarray, gamma: np.ndarray, beta: np.ndarray, epsilon: float = 1e-5 +) -> np.ndarray: + """ + Perform Layer Normalization. + """ + # Your code here + pass diff --git a/questions/10_calculate-covariance-matrix/pytorch/solution.py b/questions/10_calculate-covariance-matrix/pytorch/solution.py index d21cbe1d..1b89a196 100644 --- a/questions/10_calculate-covariance-matrix/pytorch/solution.py +++ b/questions/10_calculate-covariance-matrix/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def calculate_covariance_matrix(vectors) -> torch.Tensor: """ Calculate the covariance matrix for given feature vectors using PyTorch. diff --git a/questions/10_calculate-covariance-matrix/pytorch/starter_code.py b/questions/10_calculate-covariance-matrix/pytorch/starter_code.py index a0a8e878..a5f6e66c 100644 --- a/questions/10_calculate-covariance-matrix/pytorch/starter_code.py +++ b/questions/10_calculate-covariance-matrix/pytorch/starter_code.py @@ -1,11 +1,12 @@ import torch + def calculate_covariance_matrix(vectors) -> torch.Tensor: """ Calculate the covariance matrix for given feature vectors using PyTorch. Input: 2D array-like of shape (n_features, n_observations). Returns a tensor of shape (n_features, n_features). """ - v_t = torch.as_tensor(vectors, dtype=torch.float) + torch.as_tensor(vectors, dtype=torch.float) # Your implementation here pass diff --git a/questions/10_calculate-covariance-matrix/solution.py b/questions/10_calculate-covariance-matrix/solution.py index 3a7d9b92..24ce4d52 100644 --- a/questions/10_calculate-covariance-matrix/solution.py +++ b/questions/10_calculate-covariance-matrix/solution.py @@ -1,5 +1,3 @@ -import numpy as np - def calculate_covariance_matrix(vectors: list[list[float]]) -> list[list[float]]: n_observations = len(vectors) n_features = len(vectors[0]) diff --git a/questions/10_calculate-covariance-matrix/starter_code.py b/questions/10_calculate-covariance-matrix/starter_code.py index d19a47d4..3e1585ae 100644 --- a/questions/10_calculate-covariance-matrix/starter_code.py +++ b/questions/10_calculate-covariance-matrix/starter_code.py @@ -1,3 +1,3 @@ def calculate_covariance_matrix(vectors: list[list[float]]) -> list[list[float]]: - # Your code here - return [] + # Your code here + return [] diff --git a/questions/10_calculate-covariance-matrix/tinygrad/solution.py b/questions/10_calculate-covariance-matrix/tinygrad/solution.py index 17fd97bd..0f20a93e 100644 --- a/questions/10_calculate-covariance-matrix/tinygrad/solution.py +++ b/questions/10_calculate-covariance-matrix/tinygrad/solution.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def calculate_covariance_matrix_tg(vectors) -> Tensor: """ Calculate the covariance matrix for given feature vectors using tinygrad. @@ -9,7 +10,7 @@ def calculate_covariance_matrix_tg(vectors) -> Tensor: v_t = Tensor(vectors).float() n_features, n_obs = v_t.shape # compute feature means - means = v_t.sum(axis=1).reshape(n_features,1) / n_obs + means = v_t.sum(axis=1).reshape(n_features, 1) / n_obs centered = v_t - means - cov = centered.matmul(centered.transpose(0,1)) / (n_obs - 1) + cov = centered.matmul(centered.transpose(0, 1)) / (n_obs - 1) return cov diff --git a/questions/10_calculate-covariance-matrix/tinygrad/starter_code.py b/questions/10_calculate-covariance-matrix/tinygrad/starter_code.py index ce185fba..66baf0c8 100644 --- a/questions/10_calculate-covariance-matrix/tinygrad/starter_code.py +++ b/questions/10_calculate-covariance-matrix/tinygrad/starter_code.py @@ -1,11 +1,12 @@ from tinygrad.tensor import Tensor + def calculate_covariance_matrix_tg(vectors) -> Tensor: """ Calculate the covariance matrix for given feature vectors using tinygrad. Input: 2D array-like of shape (n_features, n_observations). Returns a Tensor of shape (n_features, n_features). """ - v_t = Tensor(vectors).float() + Tensor(vectors).float() # Your implementation here pass diff --git a/questions/110_evaluate-translation-quality-with-meteor-score/starter_code.py b/questions/110_evaluate-translation-quality-with-meteor-score/starter_code.py index e92f6c7d..e425a96e 100644 --- a/questions/110_evaluate-translation-quality-with-meteor-score/starter_code.py +++ b/questions/110_evaluate-translation-quality-with-meteor-score/starter_code.py @@ -1,6 +1,3 @@ -import numpy as np -from collections import Counter - def meteor_score(reference, candidate, alpha=0.9, beta=3, gamma=0.5): - # Your code here - pass + # Your code here + pass diff --git a/questions/111_compute-pointwise-mutual-information/solution.py b/questions/111_compute-pointwise-mutual-information/solution.py index c8d947fb..4c6f0435 100644 --- a/questions/111_compute-pointwise-mutual-information/solution.py +++ b/questions/111_compute-pointwise-mutual-information/solution.py @@ -1,8 +1,11 @@ import numpy as np -def compute_pmi(joint_counts, total_counts_x, total_counts_y, total_samples): - if not all(isinstance(x, int) and x >= 0 for x in [joint_counts, total_counts_x, total_counts_y, total_samples]): +def compute_pmi(joint_counts, total_counts_x, total_counts_y, total_samples): + if not all( + isinstance(x, int) and x >= 0 + for x in [joint_counts, total_counts_x, total_counts_y, total_samples] + ): raise ValueError("All inputs must be non-negative integers.") if total_samples == 0: @@ -16,7 +19,7 @@ def compute_pmi(joint_counts, total_counts_x, total_counts_y, total_samples): p_xy = joint_counts / total_samples if p_xy == 0: - return float('-inf') + return float("-inf") pmi = np.log2(p_xy / (p_x * p_y)) diff --git a/questions/111_compute-pointwise-mutual-information/starter_code.py b/questions/111_compute-pointwise-mutual-information/starter_code.py index 074a1b49..bbaa58e7 100644 --- a/questions/111_compute-pointwise-mutual-information/starter_code.py +++ b/questions/111_compute-pointwise-mutual-information/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def compute_pmi(joint_counts, total_counts_x, total_counts_y, total_samples): - # Implement PMI calculation here - pass + # Implement PMI calculation here + pass diff --git a/questions/112_min-max-normalization-of-feature-values/starter_code.py b/questions/112_min-max-normalization-of-feature-values/starter_code.py index 8576094f..9616a244 100644 --- a/questions/112_min-max-normalization-of-feature-values/starter_code.py +++ b/questions/112_min-max-normalization-of-feature-values/starter_code.py @@ -1,3 +1,3 @@ def min_max(x: list[int]) -> list[float]: - # Your code here - pass + # Your code here + pass diff --git a/questions/113_implement-a-simple-residual-block-with-shortcut-co/solution.py b/questions/113_implement-a-simple-residual-block-with-shortcut-co/solution.py index 72c43423..bffae114 100644 --- a/questions/113_implement-a-simple-residual-block-with-shortcut-co/solution.py +++ b/questions/113_implement-a-simple-residual-block-with-shortcut-co/solution.py @@ -1,5 +1,6 @@ import numpy as np + def residual_block(x: np.ndarray, w1: np.ndarray, w2: np.ndarray) -> np.ndarray: # First weight layer y = np.dot(w1, x) diff --git a/questions/113_implement-a-simple-residual-block-with-shortcut-co/starter_code.py b/questions/113_implement-a-simple-residual-block-with-shortcut-co/starter_code.py index fa60a0c2..dbad4dbb 100644 --- a/questions/113_implement-a-simple-residual-block-with-shortcut-co/starter_code.py +++ b/questions/113_implement-a-simple-residual-block-with-shortcut-co/starter_code.py @@ -1,5 +1,6 @@ import numpy as np + def residual_block(x: np.ndarray, w1: np.ndarray, w2: np.ndarray) -> np.ndarray: - # Your code here - pass + # Your code here + pass diff --git a/questions/114_implement-global-average-pooling/solution.py b/questions/114_implement-global-average-pooling/solution.py index 392baa3e..c860ac53 100644 --- a/questions/114_implement-global-average-pooling/solution.py +++ b/questions/114_implement-global-average-pooling/solution.py @@ -1,4 +1,5 @@ import numpy as np + def global_avg_pool(x: np.ndarray) -> np.ndarray: return np.mean(x, axis=(0, 1)) diff --git a/questions/114_implement-global-average-pooling/starter_code.py b/questions/114_implement-global-average-pooling/starter_code.py index d2a5b571..ffad9e54 100644 --- a/questions/114_implement-global-average-pooling/starter_code.py +++ b/questions/114_implement-global-average-pooling/starter_code.py @@ -1,5 +1,6 @@ import numpy as np + def global_avg_pool(x: np.ndarray) -> np.ndarray: - # Your code here - pass + # Your code here + pass diff --git a/questions/115_implement-batch-normalization-for-bchw-input/solution.py b/questions/115_implement-batch-normalization-for-bchw-input/solution.py index 9ac70d49..8192edb5 100644 --- a/questions/115_implement-batch-normalization-for-bchw-input/solution.py +++ b/questions/115_implement-batch-normalization-for-bchw-input/solution.py @@ -1,6 +1,9 @@ import numpy as np -def batch_normalization(X: np.ndarray, gamma: np.ndarray, beta: np.ndarray, epsilon: float = 1e-5) -> np.ndarray: + +def batch_normalization( + X: np.ndarray, gamma: np.ndarray, beta: np.ndarray, epsilon: float = 1e-5 +) -> np.ndarray: # Compute mean and variance across the batch and spatial dimensions mean = np.mean(X, axis=(0, 2, 3), keepdims=True) # Mean over (B, H, W) variance = np.var(X, axis=(0, 2, 3), keepdims=True) # Variance over (B, H, W) diff --git a/questions/115_implement-batch-normalization-for-bchw-input/starter_code.py b/questions/115_implement-batch-normalization-for-bchw-input/starter_code.py index 00f654ab..8c770457 100644 --- a/questions/115_implement-batch-normalization-for-bchw-input/starter_code.py +++ b/questions/115_implement-batch-normalization-for-bchw-input/starter_code.py @@ -1,5 +1,8 @@ import numpy as np -def batch_normalization(X: np.ndarray, gamma: np.ndarray, beta: np.ndarray, epsilon: float = 1e-5) -> np.ndarray: - # Your code here - pass + +def batch_normalization( + X: np.ndarray, gamma: np.ndarray, beta: np.ndarray, epsilon: float = 1e-5 +) -> np.ndarray: + # Your code here + pass diff --git a/questions/117_compute-orthonormal-basis-for-2d-vectors/solution.py b/questions/117_compute-orthonormal-basis-for-2d-vectors/solution.py index ec67479b..7bfdd236 100644 --- a/questions/117_compute-orthonormal-basis-for-2d-vectors/solution.py +++ b/questions/117_compute-orthonormal-basis-for-2d-vectors/solution.py @@ -1,6 +1,9 @@ import numpy as np -def orthonormal_basis(vectors: list[list[float]], tol: float = 1e-10) -> list[np.ndarray]: + +def orthonormal_basis( + vectors: list[list[float]], tol: float = 1e-10 +) -> list[np.ndarray]: basis = [] for v in vectors: v = np.array(v, dtype=float) diff --git a/questions/117_compute-orthonormal-basis-for-2d-vectors/starter_code.py b/questions/117_compute-orthonormal-basis-for-2d-vectors/starter_code.py index d48f8721..89b38df9 100644 --- a/questions/117_compute-orthonormal-basis-for-2d-vectors/starter_code.py +++ b/questions/117_compute-orthonormal-basis-for-2d-vectors/starter_code.py @@ -1,5 +1,8 @@ import numpy as np -def orthonormal_basis(vectors: list[list[float]], tol: float = 1e-10) -> list[np.ndarray]: + +def orthonormal_basis( + vectors: list[list[float]], tol: float = 1e-10 +) -> list[np.ndarray]: # Your code here pass diff --git a/questions/118_compute-the-cross-product-of-two-3d-vectors/solution.py b/questions/118_compute-the-cross-product-of-two-3d-vectors/solution.py index 7b794769..fea1845f 100644 --- a/questions/118_compute-the-cross-product-of-two-3d-vectors/solution.py +++ b/questions/118_compute-the-cross-product-of-two-3d-vectors/solution.py @@ -1,5 +1,6 @@ import numpy as np + def cross_product(a, b): """ Compute the cross product of two 3D vectors a and b. @@ -15,9 +16,11 @@ def cross_product(a, b): if a.shape != (3,) or b.shape != (3,): raise ValueError("Both input vectors must be of length 3.") - cross = np.array([ - a[1] * b[2] - a[2] * b[1], - a[2] * b[0] - a[0] * b[2], - a[0] * b[1] - a[1] * b[0] - ]) + cross = np.array( + [ + a[1] * b[2] - a[2] * b[1], + a[2] * b[0] - a[0] * b[2], + a[0] * b[1] - a[1] * b[0], + ] + ) return cross diff --git a/questions/118_compute-the-cross-product-of-two-3d-vectors/starter_code.py b/questions/118_compute-the-cross-product-of-two-3d-vectors/starter_code.py index e035d042..46d47cc2 100644 --- a/questions/118_compute-the-cross-product-of-two-3d-vectors/starter_code.py +++ b/questions/118_compute-the-cross-product-of-two-3d-vectors/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def cross_product(a, b): # Your code here pass diff --git a/questions/119_solve-system-of-linear-equations-using-cramer-s-ru/solution.py b/questions/119_solve-system-of-linear-equations-using-cramer-s-ru/solution.py index 37be8292..bae7faf5 100644 --- a/questions/119_solve-system-of-linear-equations-using-cramer-s-ru/solution.py +++ b/questions/119_solve-system-of-linear-equations-using-cramer-s-ru/solution.py @@ -1,5 +1,6 @@ import numpy as np + def cramers_rule(A, b): A = np.array(A, dtype=float) b = np.array(b, dtype=float) diff --git a/questions/119_solve-system-of-linear-equations-using-cramer-s-ru/starter_code.py b/questions/119_solve-system-of-linear-equations-using-cramer-s-ru/starter_code.py index b99c6a91..aeb0c34f 100644 --- a/questions/119_solve-system-of-linear-equations-using-cramer-s-ru/starter_code.py +++ b/questions/119_solve-system-of-linear-equations-using-cramer-s-ru/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def cramers_rule(A, b): # Your code here pass diff --git a/questions/11_solve-linear-equations-using-jacobi-method/pytorch/solution.py b/questions/11_solve-linear-equations-using-jacobi-method/pytorch/solution.py index c4a81c43..28a79bfa 100644 --- a/questions/11_solve-linear-equations-using-jacobi-method/pytorch/solution.py +++ b/questions/11_solve-linear-equations-using-jacobi-method/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def solve_jacobi(A, b, n) -> torch.Tensor: """ Solve Ax = b using the Jacobi iterative method for n iterations. diff --git a/questions/11_solve-linear-equations-using-jacobi-method/pytorch/starter_code.py b/questions/11_solve-linear-equations-using-jacobi-method/pytorch/starter_code.py index 563e4d7a..af979fa0 100644 --- a/questions/11_solve-linear-equations-using-jacobi-method/pytorch/starter_code.py +++ b/questions/11_solve-linear-equations-using-jacobi-method/pytorch/starter_code.py @@ -1,12 +1,13 @@ import torch + def solve_jacobi(A, b, n) -> torch.Tensor: """ Solve Ax = b using the Jacobi iterative method for n iterations. A: (m,m) tensor; b: (m,) tensor; n: number of iterations. Returns a 1-D tensor of length m, rounded to 4 decimals. """ - A_t = torch.as_tensor(A, dtype=torch.float) - b_t = torch.as_tensor(b, dtype=torch.float) + torch.as_tensor(A, dtype=torch.float) + torch.as_tensor(b, dtype=torch.float) # Your implementation here pass diff --git a/questions/11_solve-linear-equations-using-jacobi-method/solution.py b/questions/11_solve-linear-equations-using-jacobi-method/solution.py index e6c1cded..8ef58cb1 100644 --- a/questions/11_solve-linear-equations-using-jacobi-method/solution.py +++ b/questions/11_solve-linear-equations-using-jacobi-method/solution.py @@ -1,5 +1,6 @@ import numpy as np + def solve_jacobi(A: np.ndarray, b: np.ndarray, n: int) -> list: d_a = np.diag(A) nda = A - np.diag(d_a) @@ -7,6 +8,6 @@ def solve_jacobi(A: np.ndarray, b: np.ndarray, n: int) -> list: x_hold = np.zeros(len(b)) for _ in range(n): for i in range(len(A)): - x_hold[i] = (1/d_a[i]) * (b[i] - sum(nda[i]*x)) + x_hold[i] = (1 / d_a[i]) * (b[i] - sum(nda[i] * x)) x = x_hold.copy() - return np.round(x,4).tolist() + return np.round(x, 4).tolist() diff --git a/questions/11_solve-linear-equations-using-jacobi-method/starter_code.py b/questions/11_solve-linear-equations-using-jacobi-method/starter_code.py index acbd4e67..873474c8 100644 --- a/questions/11_solve-linear-equations-using-jacobi-method/starter_code.py +++ b/questions/11_solve-linear-equations-using-jacobi-method/starter_code.py @@ -1,3 +1,5 @@ import numpy as np + + def solve_jacobi(A: np.ndarray, b: np.ndarray, n: int) -> list: - return x + return x diff --git a/questions/11_solve-linear-equations-using-jacobi-method/tinygrad/solution.py b/questions/11_solve-linear-equations-using-jacobi-method/tinygrad/solution.py index 3bbb2b3c..cdb81de4 100644 --- a/questions/11_solve-linear-equations-using-jacobi-method/tinygrad/solution.py +++ b/questions/11_solve-linear-equations-using-jacobi-method/tinygrad/solution.py @@ -1,6 +1,7 @@ import numpy as np from tinygrad.tensor import Tensor + def solve_jacobi_tg(A, b, n) -> Tensor: """ Solve Ax = b using the Jacobi iterative method for n iterations in tinygrad. @@ -11,12 +12,12 @@ def solve_jacobi_tg(A, b, n) -> Tensor: b_t = Tensor(b).float() m = A_t.shape[0] # extract diagonal - d_list = [A_t[i,i] for i in range(m)] + d_list = [A_t[i, i] for i in range(m)] d = Tensor(d_list) # build remainder matrix - nda_list = [[A_t[i,j] if i != j else 0 for j in range(m)] for i in range(m)] + nda_list = [[A_t[i, j] if i != j else 0 for j in range(m)] for i in range(m)] nda = Tensor(nda_list).float() - x = Tensor([0.0]*m).float() + x = Tensor([0.0] * m).float() for _ in range(n): x = (b_t - nda.matmul(x)) / d res = x.numpy() diff --git a/questions/11_solve-linear-equations-using-jacobi-method/tinygrad/starter_code.py b/questions/11_solve-linear-equations-using-jacobi-method/tinygrad/starter_code.py index 26576d3f..e9411833 100644 --- a/questions/11_solve-linear-equations-using-jacobi-method/tinygrad/starter_code.py +++ b/questions/11_solve-linear-equations-using-jacobi-method/tinygrad/starter_code.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def solve_jacobi_tg(A, b, n) -> Tensor: """ Solve Ax = b using the Jacobi iterative method for n iterations in tinygrad. diff --git a/questions/120_bhattacharyya-distance-between-two-distributions/solution.py b/questions/120_bhattacharyya-distance-between-two-distributions/solution.py index 608e3f15..afffafc6 100644 --- a/questions/120_bhattacharyya-distance-between-two-distributions/solution.py +++ b/questions/120_bhattacharyya-distance-between-two-distributions/solution.py @@ -1,6 +1,7 @@ import numpy as np -def bhattacharyya_distance(p : list[float], q : list[float]) -> float: + +def bhattacharyya_distance(p: list[float], q: list[float]) -> float: if len(p) != len(q): return 0.0 diff --git a/questions/120_bhattacharyya-distance-between-two-distributions/starter_code.py b/questions/120_bhattacharyya-distance-between-two-distributions/starter_code.py index d2fe857f..19cdb443 100644 --- a/questions/120_bhattacharyya-distance-between-two-distributions/starter_code.py +++ b/questions/120_bhattacharyya-distance-between-two-distributions/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def bhattacharyya_distance(p: list[float], q: list[float]) -> float: # Your code here pass diff --git a/questions/121_vector-element-wise-sum/solution.py b/questions/121_vector-element-wise-sum/solution.py index 27adfeec..51c81295 100644 --- a/questions/121_vector-element-wise-sum/solution.py +++ b/questions/121_vector-element-wise-sum/solution.py @@ -1,4 +1,4 @@ -def vector_sum(a: list[int|float], b: list[int|float]) -> list[int|float]: +def vector_sum(a: list[int | float], b: list[int | float]) -> list[int | float]: if len(a) != len(b): return -1 return [a[i] + b[i] for i in range(len(a))] diff --git a/questions/121_vector-element-wise-sum/starter_code.py b/questions/121_vector-element-wise-sum/starter_code.py index 7549d00a..f3b099f8 100644 --- a/questions/121_vector-element-wise-sum/starter_code.py +++ b/questions/121_vector-element-wise-sum/starter_code.py @@ -1,4 +1,4 @@ -def vector_sum(a: list[int|float], b: list[int|float]) -> list[int|float]: - # Return the element-wise sum of vectors 'a' and 'b'. - # If vectors have different lengths, return -1. - pass +def vector_sum(a: list[int | float], b: list[int | float]) -> list[int | float]: + # Return the element-wise sum of vectors 'a' and 'b'. + # If vectors have different lengths, return -1. + pass diff --git a/questions/122_policy-gradient-with-reinforce/solution.py b/questions/122_policy-gradient-with-reinforce/solution.py index 1797b961..4dadd233 100644 --- a/questions/122_policy-gradient-with-reinforce/solution.py +++ b/questions/122_policy-gradient-with-reinforce/solution.py @@ -1,5 +1,6 @@ import numpy as np + def compute_policy_gradient(theta, episodes): def softmax(x): x = x - np.max(x) diff --git a/questions/122_policy-gradient-with-reinforce/starter_code.py b/questions/122_policy-gradient-with-reinforce/starter_code.py index 816d333c..4caaa342 100644 --- a/questions/122_policy-gradient-with-reinforce/starter_code.py +++ b/questions/122_policy-gradient-with-reinforce/starter_code.py @@ -1,6 +1,9 @@ import numpy as np -def compute_policy_gradient(theta: np.ndarray, episodes: list[list[tuple[int, int, float]]]) -> np.ndarray: + +def compute_policy_gradient( + theta: np.ndarray, episodes: list[list[tuple[int, int, float]]] +) -> np.ndarray: """ Estimate the policy gradient using REINFORCE. diff --git a/questions/124_implement-the-noisy-top-k-gating-function/solution.py b/questions/124_implement-the-noisy-top-k-gating-function/solution.py index a079bd58..a953a1d1 100644 --- a/questions/124_implement-the-noisy-top-k-gating-function/solution.py +++ b/questions/124_implement-the-noisy-top-k-gating-function/solution.py @@ -1,11 +1,8 @@ import numpy as np + def noisy_topk_gating( - X: np.ndarray, - W_g: np.ndarray, - W_noise: np.ndarray, - N: np.ndarray, - k: int + X: np.ndarray, W_g: np.ndarray, W_noise: np.ndarray, N: np.ndarray, k: int ) -> np.ndarray: H_base = X @ W_g H_noise = X @ W_noise diff --git a/questions/124_implement-the-noisy-top-k-gating-function/starter_code.py b/questions/124_implement-the-noisy-top-k-gating-function/starter_code.py index 1d02b699..099eb634 100644 --- a/questions/124_implement-the-noisy-top-k-gating-function/starter_code.py +++ b/questions/124_implement-the-noisy-top-k-gating-function/starter_code.py @@ -1,11 +1,8 @@ import numpy as np + def noisy_topk_gating( - X: np.ndarray, - W_g: np.ndarray, - W_noise: np.ndarray, - N: np.ndarray, - k: int + X: np.ndarray, W_g: np.ndarray, W_noise: np.ndarray, N: np.ndarray, k: int ) -> np.ndarray: """ Args: diff --git a/questions/125_implement-a-sparse-mixture-of-experts-layer/solution.py b/questions/125_implement-a-sparse-mixture-of-experts-layer/solution.py index 6071d4c8..632c4bf3 100644 --- a/questions/125_implement-a-sparse-mixture-of-experts-layer/solution.py +++ b/questions/125_implement-a-sparse-mixture-of-experts-layer/solution.py @@ -1,24 +1,29 @@ import numpy as np + def softmax(x: np.ndarray, axis: int = -1) -> np.ndarray: exp_x = np.exp(x - np.max(x, axis=axis, keepdims=True)) return exp_x / np.sum(exp_x, axis=axis, keepdims=True) + def get_top_k(arr: np.ndarray, k: int): idx = np.argpartition(arr, -k)[..., -k:] vals = np.take_along_axis(arr, idx, axis=-1) return idx, vals + def expert(x: np.ndarray, We_i: np.ndarray): # x: [n_tokens, d_model] # We_i: [d_model, d_model] return x @ We_i + def gate(x: np.ndarray, Wg: np.ndarray): # x: [n_batch * l_seq, d_model] # Wg: [n_batch * l_seq, n_experts] return x @ Wg + def moe(x: np.ndarray, We: np.ndarray, Wg: np.ndarray, n_experts: int, top_k: int): # x: [n_batch, l_seq, d_model] # We: [n_experts, d_model, d_model] diff --git a/questions/125_implement-a-sparse-mixture-of-experts-layer/starter_code.py b/questions/125_implement-a-sparse-mixture-of-experts-layer/starter_code.py index 6b7873c7..13d37325 100644 --- a/questions/125_implement-a-sparse-mixture-of-experts-layer/starter_code.py +++ b/questions/125_implement-a-sparse-mixture-of-experts-layer/starter_code.py @@ -1,6 +1,9 @@ import numpy as np -def moe(x: np.ndarray, We: np.ndarray, Wg: np.ndarray, n_experts: int, top_k: int) -> np.ndarray: + +def moe( + x: np.ndarray, We: np.ndarray, Wg: np.ndarray, n_experts: int, top_k: int +) -> np.ndarray: """ Args: x: Input tensor of shape (n_batch, l_seq, d_model) diff --git a/questions/126_implement-group-normalization/solution.py b/questions/126_implement-group-normalization/solution.py index 18cdb7fb..f47db6ec 100644 --- a/questions/126_implement-group-normalization/solution.py +++ b/questions/126_implement-group-normalization/solution.py @@ -1,17 +1,23 @@ -def group_normalization(X: np.ndarray, gamma: np.ndarray, beta: np.ndarray, num_groups: int, epsilon: float = 1e-5) -> np.ndarray: - ''' +def group_normalization( + X: np.ndarray, + gamma: np.ndarray, + beta: np.ndarray, + num_groups: int, + epsilon: float = 1e-5, +) -> np.ndarray: + """ Perform Group Normalization. - + Args: X: numpy array of shape (B, C, H, W), input data gamma: numpy array of shape (C,), scale parameter beta: numpy array of shape (C,), shift parameter num_groups: number of groups for normalization epsilon: small constant to avoid division by zero - + Returns: norm_X: numpy array of shape (B, C, H, W), normalized output - ''' + """ batch_size, num_channels, height, width = X.shape group_size = num_channels // num_groups diff --git a/questions/126_implement-group-normalization/starter_code.py b/questions/126_implement-group-normalization/starter_code.py index a75bfe94..6edb23e3 100644 --- a/questions/126_implement-group-normalization/starter_code.py +++ b/questions/126_implement-group-normalization/starter_code.py @@ -1,5 +1,12 @@ import numpy as np -def group_normalization(X: np.ndarray, gamma: np.ndarray, beta: np.ndarray, num_groups: int, epsilon: float = 1e-5) -> np.ndarray: + +def group_normalization( + X: np.ndarray, + gamma: np.ndarray, + beta: np.ndarray, + num_groups: int, + epsilon: float = 1e-5, +) -> np.ndarray: # Your code here pass diff --git a/questions/127_find-captain-redbeard-s-hidden-treasure/starter_code.py b/questions/127_find-captain-redbeard-s-hidden-treasure/starter_code.py index 2e17590a..f692bf8a 100644 --- a/questions/127_find-captain-redbeard-s-hidden-treasure/starter_code.py +++ b/questions/127_find-captain-redbeard-s-hidden-treasure/starter_code.py @@ -1,9 +1,9 @@ def find_treasure(start_x: float) -> float: """ - Find the x-coordinate where f(x) = x^4 - 3x^3 + 2 is minimized. + Find the x-coordinate where f(x) = x^4 - 3x^3 + 2 is minimized. - Returns: - float: The x-coordinate of the minimum point. + Returns: + float: The x-coordinate of the minimum point. """ # Your code here pass diff --git a/questions/128_dynamic-tanh-normalization-free-transformer-activa/solution.py b/questions/128_dynamic-tanh-normalization-free-transformer-activa/solution.py index 1c9cb05d..2a204bd5 100644 --- a/questions/128_dynamic-tanh-normalization-free-transformer-activa/solution.py +++ b/questions/128_dynamic-tanh-normalization-free-transformer-activa/solution.py @@ -1,5 +1,6 @@ import numpy as np + def dynamic_tanh(x: np.ndarray, alpha: float, gamma: float, beta: float) -> list[float]: def tanh(x: np.ndarray) -> np.ndarray: return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x)) diff --git a/questions/128_dynamic-tanh-normalization-free-transformer-activa/starter_code.py b/questions/128_dynamic-tanh-normalization-free-transformer-activa/starter_code.py index 29bf9f12..9d71217d 100644 --- a/questions/128_dynamic-tanh-normalization-free-transformer-activa/starter_code.py +++ b/questions/128_dynamic-tanh-normalization-free-transformer-activa/starter_code.py @@ -1,5 +1,6 @@ import numpy as np + def dynamic_tanh(x: np.ndarray, alpha: float, gamma: float, beta: float) -> list[float]: # Your code here pass diff --git a/questions/12_singular-value-decomposition-svd/pytorch/solution.py b/questions/12_singular-value-decomposition-svd/pytorch/solution.py index 2ed6e967..95442d16 100644 --- a/questions/12_singular-value-decomposition-svd/pytorch/solution.py +++ b/questions/12_singular-value-decomposition-svd/pytorch/solution.py @@ -1,28 +1,31 @@ import torch -def svd_2x2_singular_values(A: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + +def svd_2x2_singular_values( + A: torch.Tensor, +) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: """ Approximate the SVD of a 2×2 matrix A using one Jacobi rotation. Returns (U, S, Vt) where S is a 1-D tensor of singular values. """ # compute AᵀA - a2 = A.transpose(0,1) @ A + a2 = A.transpose(0, 1) @ A # initialize V V = torch.eye(2, dtype=A.dtype, device=A.device) # Jacobi rotation angle - if torch.isclose(a2[0,0], a2[1,1]): - theta = torch.tensor(torch.pi/4, dtype=A.dtype, device=A.device) + if torch.isclose(a2[0, 0], a2[1, 1]): + theta = torch.tensor(torch.pi / 4, dtype=A.dtype, device=A.device) else: - theta = 0.5 * torch.atan2(2 * a2[0,1], a2[0,0] - a2[1,1]) + theta = 0.5 * torch.atan2(2 * a2[0, 1], a2[0, 0] - a2[1, 1]) c = torch.cos(theta) s = torch.sin(theta) R = torch.stack([torch.stack([c, -s]), torch.stack([s, c])]) # diagonalize - D = R.transpose(0,1) @ a2 @ R + D = R.transpose(0, 1) @ a2 @ R V = V @ R # singular values - S = torch.sqrt(torch.tensor([D[0,0], D[1,1]], dtype=A.dtype, device=A.device)) + S = torch.sqrt(torch.tensor([D[0, 0], D[1, 1]], dtype=A.dtype, device=A.device)) # compute U S_inv = torch.diag(1.0 / S) U = A @ V @ S_inv - return U, S, V.transpose(0,1) + return U, S, V.transpose(0, 1) diff --git a/questions/12_singular-value-decomposition-svd/pytorch/starter_code.py b/questions/12_singular-value-decomposition-svd/pytorch/starter_code.py index 3dc609a5..bc03f473 100644 --- a/questions/12_singular-value-decomposition-svd/pytorch/starter_code.py +++ b/questions/12_singular-value-decomposition-svd/pytorch/starter_code.py @@ -1,6 +1,9 @@ import torch -def svd_2x2_singular_values(A: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + +def svd_2x2_singular_values( + A: torch.Tensor, +) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: """ Approximate the SVD of a 2×2 matrix A using one Jacobi rotation. Returns (U, S, Vt) where S is a 1-D tensor of singular values. diff --git a/questions/12_singular-value-decomposition-svd/solution.py b/questions/12_singular-value-decomposition-svd/solution.py index f6a8fbb3..9e48e7e1 100644 --- a/questions/12_singular-value-decomposition-svd/solution.py +++ b/questions/12_singular-value-decomposition-svd/solution.py @@ -1,44 +1,38 @@ -import numpy as np +import numpy as np def svd_2x2_singular_values(A: np.ndarray) -> tuple: - # stick to lowercase - a = A - - a_t = np.transpose(a) - a_2 = a_t @ a - - v = np.eye(2) - - for _ in range(1): - # Compute rotation angle for a 2x2 matrix - if a_2[0,0] == a_2[1,1]: - theta = np.pi/4 - else: - theta = 0.5 * np.arctan2(2 * a_2[0,1], a_2[0,0] - a_2[1,1]) - - # Create rotation matrix - r = np.array( - [ - [np.cos(theta), -np.sin(theta)], - [np.sin(theta), np.cos(theta)] - ] - ) - - # apply rotation - d = np.transpose(r) @ a_2 @ r - - # update a_2 - a_2 = d - - # accumulate v - v = v @ r - - # sigma is the diagonal elements squared - s = np.sqrt([d[0,0], d[1,1]]) - s_inv = np.array([[1/s[0], 0], [0, 1/s[1]]]) - - u = a @ v @ s_inv - - return (u, s, v.T) - + # stick to lowercase + a = A + + a_t = np.transpose(a) + a_2 = a_t @ a + + v = np.eye(2) + + for _ in range(1): + # Compute rotation angle for a 2x2 matrix + if a_2[0, 0] == a_2[1, 1]: + theta = np.pi / 4 + else: + theta = 0.5 * np.arctan2(2 * a_2[0, 1], a_2[0, 0] - a_2[1, 1]) + + # Create rotation matrix + r = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) + + # apply rotation + d = np.transpose(r) @ a_2 @ r + + # update a_2 + a_2 = d + + # accumulate v + v = v @ r + + # sigma is the diagonal elements squared + s = np.sqrt([d[0, 0], d[1, 1]]) + s_inv = np.array([[1 / s[0], 0], [0, 1 / s[1]]]) + + u = a @ v @ s_inv + + return (u, s, v.T) diff --git a/questions/12_singular-value-decomposition-svd/starter_code.py b/questions/12_singular-value-decomposition-svd/starter_code.py index 04722225..1847529f 100644 --- a/questions/12_singular-value-decomposition-svd/starter_code.py +++ b/questions/12_singular-value-decomposition-svd/starter_code.py @@ -1,3 +1,3 @@ import numpy as np - def svd_2x2_singular_values(A: np.ndarray) -> tuple: +def svd_2x2_singular_values(A: np.ndarray) -> tuple: return SVD diff --git a/questions/12_singular-value-decomposition-svd/tinygrad/solution.py b/questions/12_singular-value-decomposition-svd/tinygrad/solution.py index 42c9e31c..02758b3a 100644 --- a/questions/12_singular-value-decomposition-svd/tinygrad/solution.py +++ b/questions/12_singular-value-decomposition-svd/tinygrad/solution.py @@ -1,6 +1,7 @@ import numpy as np from tinygrad.tensor import Tensor + def svd_2x2_singular_values_tg(A) -> tuple[Tensor, Tensor, Tensor]: """ Approximate the SVD of a 2×2 matrix A using one Jacobi rotation in tinygrad. @@ -11,10 +12,12 @@ def svd_2x2_singular_values_tg(A) -> tuple[Tensor, Tensor, Tensor]: a2 = A_t.T.matmul(A_t) V = Tensor([[1.0, 0.0], [0.0, 1.0]]) # extract entries - a_val = a2[0,0].numpy(); d_val = a2[1,1].numpy(); b_val = a2[0,1].numpy() + a_val = a2[0, 0].numpy() + d_val = a2[1, 1].numpy() + b_val = a2[0, 1].numpy() # compute rotation angle if np.isclose(a_val, d_val): - theta = np.pi/4 + theta = np.pi / 4 else: theta = 0.5 * np.arctan2(2 * b_val, a_val - d_val) c, s = np.cos(theta), np.sin(theta) @@ -22,8 +25,8 @@ def svd_2x2_singular_values_tg(A) -> tuple[Tensor, Tensor, Tensor]: D = R.T.matmul(a2).matmul(R) V = V.matmul(R) # singular values - S = Tensor(np.sqrt([D[0,0].numpy(), D[1,1].numpy()])) + S = Tensor(np.sqrt([D[0, 0].numpy(), D[1, 1].numpy()])) # compute U - S_inv = Tensor([[1.0/S[0].numpy(), 0.0], [0.0, 1.0/S[1].numpy()]]) + S_inv = Tensor([[1.0 / S[0].numpy(), 0.0], [0.0, 1.0 / S[1].numpy()]]) U = A_t.matmul(V).matmul(S_inv) return U, S, V.T diff --git a/questions/12_singular-value-decomposition-svd/tinygrad/starter_code.py b/questions/12_singular-value-decomposition-svd/tinygrad/starter_code.py index 086402fa..07e1b6d7 100644 --- a/questions/12_singular-value-decomposition-svd/tinygrad/starter_code.py +++ b/questions/12_singular-value-decomposition-svd/tinygrad/starter_code.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def svd_2x2_singular_values_tg(A) -> tuple[Tensor, Tensor, Tensor]: """ Approximate the SVD of a 2×2 matrix A using one Jacobi rotation in tinygrad. diff --git a/questions/130_implement-a-simple-cnn-training-function-with-back/solution.py b/questions/130_implement-a-simple-cnn-training-function-with-back/solution.py index da6929c5..43875dd9 100644 --- a/questions/130_implement-a-simple-cnn-training-function-with-back/solution.py +++ b/questions/130_implement-a-simple-cnn-training-function-with-back/solution.py @@ -1,7 +1,10 @@ import numpy as np -def train_simple_cnn_with_backprop(X, y, epochs, learning_rate, kernel_size=3, num_filters=1): - ''' + +def train_simple_cnn_with_backprop( + X, y, epochs, learning_rate, kernel_size=3, num_filters=1 +): + """ Trains a simple CNN with one convolutional layer, ReLU activation, flattening, and a dense layer with softmax output using backpropagation. Assumes X has shape (n_samples, height, width) for grayscale images and y is one-hot encoded with shape (n_samples, num_classes). @@ -16,7 +19,7 @@ def train_simple_cnn_with_backprop(X, y, epochs, learning_rate, kernel_size=3, n Returns: W_conv, b_conv, W_dense, b_dense : Trained weights and biases for the convolutional and dense layers - ''' + """ n_samples, height, width = X.shape num_classes = y.shape[1] @@ -37,13 +40,21 @@ def train_simple_cnn_with_backprop(X, y, epochs, learning_rate, kernel_size=3, n for k in range(num_filters): for p in range(output_height): for q in range(output_width): - Z_conv[p, q, k] = np.sum(X[i, p:p+kernel_size, q:q+kernel_size] * W_conv[:, :, k]) + b_conv[k] + Z_conv[p, q, k] = ( + np.sum( + X[i, p : p + kernel_size, q : q + kernel_size] + * W_conv[:, :, k] + ) + + b_conv[k] + ) A_conv = np.maximum(Z_conv, 0) # ReLU activation A_flat = A_conv.flatten() # Flatten the output # Dense layer Z_dense = np.dot(A_flat, W_dense) + b_dense - exp_Z_dense = np.exp(Z_dense - np.max(Z_dense)) # Numerical stability for softmax + exp_Z_dense = np.exp( + Z_dense - np.max(Z_dense) + ) # Numerical stability for softmax A_dense = exp_Z_dense / np.sum(exp_Z_dense) # Backpropagation @@ -66,11 +77,12 @@ def train_simple_cnn_with_backprop(X, y, epochs, learning_rate, kernel_size=3, n db_conv[k] = np.sum(dZ_conv[:, :, k]) for ii in range(kernel_size): for jj in range(kernel_size): - - dW_conv[ii, jj, k] = np.sum(dZ_conv[:, :, k] * X[i, ii:ii+output_height, jj:jj+output_width]) + dW_conv[ii, jj, k] = np.sum( + dZ_conv[:, :, k] + * X[i, ii : ii + output_height, jj : jj + output_width] + ) - -# Update weights and biases + # Update weights and biases W_conv -= learning_rate * dW_conv b_conv -= learning_rate * db_conv W_dense -= learning_rate * dW_dense diff --git a/questions/130_implement-a-simple-cnn-training-function-with-back/starter_code.py b/questions/130_implement-a-simple-cnn-training-function-with-back/starter_code.py index cc6a5dc4..d5f90fc5 100644 --- a/questions/130_implement-a-simple-cnn-training-function-with-back/starter_code.py +++ b/questions/130_implement-a-simple-cnn-training-function-with-back/starter_code.py @@ -1,3 +1,5 @@ -def train_simple_cnn_with_backprop(X, y, epochs, learning_rate, kernel_size=3, num_filters=1): +def train_simple_cnn_with_backprop( + X, y, epochs, learning_rate, kernel_size=3, num_filters=1 +): # Your code here pass diff --git a/questions/131_implement-efficient-sparse-window-attention/solution.py b/questions/131_implement-efficient-sparse-window-attention/solution.py index 1425246c..bc437b17 100644 --- a/questions/131_implement-efficient-sparse-window-attention/solution.py +++ b/questions/131_implement-efficient-sparse-window-attention/solution.py @@ -1,5 +1,6 @@ import numpy as np + def sparse_window_attention(Q, K, V, window_size, scale_factor=None): """ Computes sparse attention with a sliding window mask to efficiently handle longer context lengths. @@ -24,7 +25,7 @@ def sparse_window_attention(Q, K, V, window_size, scale_factor=None): for i in range(seq_len): start = max(0, i - window_size) end = min(seq_len, i + window_size + 1) - local_Q = Q[i:i+1] + local_Q = Q[i : i + 1] local_K = K[start:end] local_V = V[start:end] scores = np.dot(local_Q, local_K.T) / scale_factor diff --git a/questions/131_implement-efficient-sparse-window-attention/starter_code.py b/questions/131_implement-efficient-sparse-window-attention/starter_code.py index e0ef4ce4..8417bb75 100644 --- a/questions/131_implement-efficient-sparse-window-attention/starter_code.py +++ b/questions/131_implement-efficient-sparse-window-attention/starter_code.py @@ -1,4 +1,3 @@ -import numpy as np def sparse_window_attention(Q, K, V, window_size, scale_factor=None): # Your code here pass diff --git a/questions/132_simulate-markov-chain-transitions/solution.py b/questions/132_simulate-markov-chain-transitions/solution.py index 38090142..1176c2b9 100644 --- a/questions/132_simulate-markov-chain-transitions/solution.py +++ b/questions/132_simulate-markov-chain-transitions/solution.py @@ -1,5 +1,6 @@ import numpy as np + def simulate_markov_chain(transition_matrix, initial_state, num_steps): """ Simulates a Markov Chain given a transition matrix, initial state, and number of steps. diff --git a/questions/132_simulate-markov-chain-transitions/starter_code.py b/questions/132_simulate-markov-chain-transitions/starter_code.py index e3f0e7b0..cf6e528d 100644 --- a/questions/132_simulate-markov-chain-transitions/starter_code.py +++ b/questions/132_simulate-markov-chain-transitions/starter_code.py @@ -1,4 +1,3 @@ -import numpy as np def simulate_markov_chain(transition_matrix, initial_state, num_steps): # Your code here pass diff --git a/questions/133_implement-q-learning-algorithm-for-mdps/solution.py b/questions/133_implement-q-learning-algorithm-for-mdps/solution.py index 553155d0..b0150812 100644 --- a/questions/133_implement-q-learning-algorithm-for-mdps/solution.py +++ b/questions/133_implement-q-learning-algorithm-for-mdps/solution.py @@ -1,6 +1,9 @@ import numpy as np -def q_learning(num_states, num_actions, P, R, terminal_states, alpha, gamma, epsilon, num_episodes): + +def q_learning( + num_states, num_actions, P, R, terminal_states, alpha, gamma, epsilon, num_episodes +): """ Implements Q-Learning algorithm to learn the optimal Q-table for a given MDP. @@ -19,34 +22,36 @@ def q_learning(num_states, num_actions, P, R, terminal_states, alpha, gamma, eps - Q: NumPy array of shape (num_states, num_actions), the learned Q-table """ Q = np.zeros((num_states, num_actions)) - + for episode in range(num_episodes): # Start from a random non-terminal state - state = np.random.choice([s for s in range(num_states) if s not in set(terminal_states)]) - + state = np.random.choice( + [s for s in range(num_states) if s not in set(terminal_states)] + ) + while state not in terminal_states: # Epsilon-greedy action selection if np.random.rand() < epsilon: action = np.random.randint(num_actions) else: action = np.argmax(Q[state]) - + # Sample next state based on transition probabilities next_state = np.random.choice(num_states, p=P[state, action]) - + # Get reward reward = R[state, action] - + # Compute target Q-value if next_state in terminal_states: target = reward else: target = reward + gamma * np.max(Q[next_state]) - + # Update Q-table Q[state, action] += alpha * (target - Q[state, action]) - + # Transition to next state state = next_state - + return Q diff --git a/questions/133_implement-q-learning-algorithm-for-mdps/starter_code.py b/questions/133_implement-q-learning-algorithm-for-mdps/starter_code.py index c4b26350..b4bcdf89 100644 --- a/questions/133_implement-q-learning-algorithm-for-mdps/starter_code.py +++ b/questions/133_implement-q-learning-algorithm-for-mdps/starter_code.py @@ -1,4 +1,5 @@ -import numpy as np -def q_learning(num_states, num_actions, P, R, terminal_states, alpha, gamma, epsilon, num_episodes): +def q_learning( + num_states, num_actions, P, R, terminal_states, alpha, gamma, epsilon, num_episodes +): # Your code here pass diff --git a/questions/134_compute-multi-class-cross-entropy-loss/solution.py b/questions/134_compute-multi-class-cross-entropy-loss/solution.py index 2ed25690..1575d696 100644 --- a/questions/134_compute-multi-class-cross-entropy-loss/solution.py +++ b/questions/134_compute-multi-class-cross-entropy-loss/solution.py @@ -1,10 +1,12 @@ import numpy as np -def compute_cross_entropy_loss(predicted_probs: np.ndarray, true_labels: np.ndarray,epsilon = 1e-15) -> float: +def compute_cross_entropy_loss( + predicted_probs: np.ndarray, true_labels: np.ndarray, epsilon=1e-15 +) -> float: predicted_probs = np.clip(predicted_probs, epsilon, 1 - epsilon) - #Write your code here + # Write your code here log_probs = np.log(predicted_probs) loss = -np.sum(true_labels * log_probs, axis=1) return float(np.mean(loss)) diff --git a/questions/134_compute-multi-class-cross-entropy-loss/starter_code.py b/questions/134_compute-multi-class-cross-entropy-loss/starter_code.py index c182289b..ece27566 100644 --- a/questions/134_compute-multi-class-cross-entropy-loss/starter_code.py +++ b/questions/134_compute-multi-class-cross-entropy-loss/starter_code.py @@ -1,5 +1,8 @@ import numpy as np -def compute_cross_entropy_loss(predicted_probs: np.ndarray, true_labels: np.ndarray, epsilon = 1e-15) -> float: + +def compute_cross_entropy_loss( + predicted_probs: np.ndarray, true_labels: np.ndarray, epsilon=1e-15 +) -> float: # Your code here pass diff --git a/questions/135_implement-early-stopping-based-on-validation-loss/solution.py b/questions/135_implement-early-stopping-based-on-validation-loss/solution.py index 689d05ee..427f9569 100644 --- a/questions/135_implement-early-stopping-based-on-validation-loss/solution.py +++ b/questions/135_implement-early-stopping-based-on-validation-loss/solution.py @@ -1,7 +1,10 @@ from typing import Tuple -def early_stopping(val_losses: list[float], patience: int, min_delta: float) -> Tuple[int, int]: - best_loss = float('inf') + +def early_stopping( + val_losses: list[float], patience: int, min_delta: float +) -> Tuple[int, int]: + best_loss = float("inf") best_epoch = 0 epochs_without_improvement = 0 diff --git a/questions/135_implement-early-stopping-based-on-validation-loss/starter_code.py b/questions/135_implement-early-stopping-based-on-validation-loss/starter_code.py index 9576b639..0560f4c7 100644 --- a/questions/135_implement-early-stopping-based-on-validation-loss/starter_code.py +++ b/questions/135_implement-early-stopping-based-on-validation-loss/starter_code.py @@ -1,5 +1,8 @@ from typing import Tuple -def early_stopping(val_losses: list[float], patience: int, min_delta: float) -> Tuple[int, int]: + +def early_stopping( + val_losses: list[float], patience: int, min_delta: float +) -> Tuple[int, int]: # Your code here pass diff --git a/questions/136_calculate-kl-divergence-between-two-multivariate-g/solution.py b/questions/136_calculate-kl-divergence-between-two-multivariate-g/solution.py index f899a960..e4b14313 100644 --- a/questions/136_calculate-kl-divergence-between-two-multivariate-g/solution.py +++ b/questions/136_calculate-kl-divergence-between-two-multivariate-g/solution.py @@ -1,12 +1,20 @@ import numpy as np -def multivariate_kl_divergence(mu_p:np.ndarray, Cov_p:np.ndarray, - mu_q:np.ndarray, Cov_q:np.ndarray) -> float: +def multivariate_kl_divergence( + mu_p: np.ndarray, Cov_p: np.ndarray, mu_q: np.ndarray, Cov_q: np.ndarray +) -> float: def trace(x: np.ndarray) -> float: return np.diag(x).sum() p = Cov_p.shape[0] - return float(1/2 * ( - np.log(np.linalg.det(Cov_q)/np.linalg.det(Cov_p)) - p + (mu_p-mu_q).T @ np.linalg.inv(Cov_q) @ (mu_p-mu_q) + trace(np.linalg.inv(Cov_q) @ Cov_p) - )) + return float( + 1 + / 2 + * ( + np.log(np.linalg.det(Cov_q) / np.linalg.det(Cov_p)) + - p + + (mu_p - mu_q).T @ np.linalg.inv(Cov_q) @ (mu_p - mu_q) + + trace(np.linalg.inv(Cov_q) @ Cov_p) + ) + ) diff --git a/questions/136_calculate-kl-divergence-between-two-multivariate-g/starter_code.py b/questions/136_calculate-kl-divergence-between-two-multivariate-g/starter_code.py index 91200797..7e4ceee8 100644 --- a/questions/136_calculate-kl-divergence-between-two-multivariate-g/starter_code.py +++ b/questions/136_calculate-kl-divergence-between-two-multivariate-g/starter_code.py @@ -1,9 +1,12 @@ import numpy as np -def multivariate_kl_divergence(mu_p: np.ndarray, Cov_p: np.ndarray, mu_q: np.ndarray, Cov_q: np.ndarray) -> float: + +def multivariate_kl_divergence( + mu_p: np.ndarray, Cov_p: np.ndarray, mu_q: np.ndarray, Cov_q: np.ndarray +) -> float: """ Computes the KL divergence between two multivariate Gaussian distributions. - + Parameters: mu_p: mean vector of the first distribution Cov_p: covariance matrix of the first distribution diff --git a/questions/137_implement-a-dense-block-with-2d-convolutions/solution.py b/questions/137_implement-a-dense-block-with-2d-convolutions/solution.py index bc273341..172df837 100644 --- a/questions/137_implement-a-dense-block-with-2d-convolutions/solution.py +++ b/questions/137_implement-a-dense-block-with-2d-convolutions/solution.py @@ -1,8 +1,11 @@ import numpy as np + def conv2d(x, kernel, padding=0): if padding > 0: - x_padded = np.pad(x, ((0, 0), (padding, padding), (padding, padding), (0, 0)), mode='constant') + x_padded = np.pad( + x, ((0, 0), (padding, padding), (padding, padding), (0, 0)), mode="constant" + ) else: x_padded = x batch_size, in_height, in_width, in_channels = x_padded.shape @@ -16,10 +19,14 @@ def conv2d(x, kernel, padding=0): for c_out in range(out_channels): sum_val = 0.0 for c_in in range(in_channels): - sum_val += np.sum(x_padded[b, i:i+kh, j:j+kw, c_in] * kernel[:, :, c_in, c_out]) + sum_val += np.sum( + x_padded[b, i : i + kh, j : j + kw, c_in] + * kernel[:, :, c_in, c_out] + ) output[b, i, j, c_out] = sum_val return output + def dense_net_block(input_data, num_layers, growth_rate, kernels, kernel_size=(3, 3)): kh, kw = kernel_size padding = (kh - 1) // 2 @@ -27,5 +34,7 @@ def dense_net_block(input_data, num_layers, growth_rate, kernels, kernel_size=(3 for l in range(num_layers): activated = np.maximum(concatenated_features, 0.0) conv_output = conv2d(activated, kernels[l], padding=padding) - concatenated_features = np.concatenate([concatenated_features, conv_output], axis=3) + concatenated_features = np.concatenate( + [concatenated_features, conv_output], axis=3 + ) return concatenated_features diff --git a/questions/137_implement-a-dense-block-with-2d-convolutions/starter_code.py b/questions/137_implement-a-dense-block-with-2d-convolutions/starter_code.py index 90abdcee..ac79804b 100644 --- a/questions/137_implement-a-dense-block-with-2d-convolutions/starter_code.py +++ b/questions/137_implement-a-dense-block-with-2d-convolutions/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def dense_net_block(input_data, num_layers, growth_rate, kernels, kernel_size=(3, 3)): # Your code here pass diff --git a/questions/138_find-the-best-gini-based-split-for-a-binary-decisi/solution.py b/questions/138_find-the-best-gini-based-split-for-a-binary-decisi/solution.py index 806300f5..578297e2 100644 --- a/questions/138_find-the-best-gini-based-split-for-a-binary-decisi/solution.py +++ b/questions/138_find-the-best-gini-based-split-for-a-binary-decisi/solution.py @@ -1,16 +1,17 @@ import numpy as np from typing import Tuple + def find_best_split(X: np.ndarray, y: np.ndarray) -> Tuple[int, float]: def gini(y_subset: np.ndarray) -> float: if y_subset.size == 0: return 0.0 p = y_subset.mean() - return 1.0 - (p**2 + (1 - p)**2) + return 1.0 - (p**2 + (1 - p) ** 2) n_samples, n_features = X.shape - best_feature, best_threshold = -1, float('inf') - best_gini = float('inf') + best_feature, best_threshold = -1, float("inf") + best_gini = float("inf") for f in range(n_features): for threshold in np.unique(X[:, f]): diff --git a/questions/138_find-the-best-gini-based-split-for-a-binary-decisi/starter_code.py b/questions/138_find-the-best-gini-based-split-for-a-binary-decisi/starter_code.py index 15d4c06d..7a5cbe84 100644 --- a/questions/138_find-the-best-gini-based-split-for-a-binary-decisi/starter_code.py +++ b/questions/138_find-the-best-gini-based-split-for-a-binary-decisi/starter_code.py @@ -1,6 +1,7 @@ import numpy as np from typing import Tuple + def find_best_split(X: np.ndarray, y: np.ndarray) -> Tuple[int, float]: """Return the (feature_index, threshold) that minimises weighted Gini impurity.""" # ✏️ TODO: implement diff --git a/questions/139_elastic-net-regression-via-gradient-descent/solution.py b/questions/139_elastic-net-regression-via-gradient-descent/solution.py index 90f8e267..022dde2e 100644 --- a/questions/139_elastic-net-regression-via-gradient-descent/solution.py +++ b/questions/139_elastic-net-regression-via-gradient-descent/solution.py @@ -1,5 +1,6 @@ import numpy as np + def elastic_net_gradient_descent( X: np.ndarray, y: np.ndarray, @@ -16,7 +17,11 @@ def elastic_net_gradient_descent( for _ in range(max_iter): y_pred = np.dot(X, weights) + bias error = y_pred - y - grad_w = (1 / n_samples) * np.dot(X.T, error) + alpha1 * np.sign(weights) + 2 * alpha2 * weights + grad_w = ( + (1 / n_samples) * np.dot(X.T, error) + + alpha1 * np.sign(weights) + + 2 * alpha2 * weights + ) grad_b = (1 / n_samples) * np.sum(error) weights -= learning_rate * grad_w bias -= learning_rate * grad_b diff --git a/questions/139_elastic-net-regression-via-gradient-descent/starter_code.py b/questions/139_elastic-net-regression-via-gradient-descent/starter_code.py index f383c038..f0efa364 100644 --- a/questions/139_elastic-net-regression-via-gradient-descent/starter_code.py +++ b/questions/139_elastic-net-regression-via-gradient-descent/starter_code.py @@ -1,5 +1,6 @@ import numpy as np + def elastic_net_gradient_descent( X: np.ndarray, y: np.ndarray, diff --git a/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/pytorch/solution.py b/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/pytorch/solution.py index 54f64913..5785e894 100644 --- a/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/pytorch/solution.py +++ b/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def determinant_4x4(matrix) -> float: """ Compute the determinant of a 4×4 matrix using PyTorch. diff --git a/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/pytorch/starter_code.py b/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/pytorch/starter_code.py index acf9ccb6..0380e1ca 100644 --- a/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/pytorch/starter_code.py +++ b/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/pytorch/starter_code.py @@ -1,5 +1,6 @@ import torch + def determinant_4x4(matrix) -> float: """ Compute the determinant of a 4×4 matrix using PyTorch. @@ -7,6 +8,6 @@ def determinant_4x4(matrix) -> float: Returns a Python float. """ # Convert to tensor - m = torch.as_tensor(matrix, dtype=torch.float) + torch.as_tensor(matrix, dtype=torch.float) # Your implementation here pass diff --git a/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/solution.py b/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/solution.py index 17825b2a..35caeb91 100644 --- a/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/solution.py +++ b/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/solution.py @@ -1,11 +1,11 @@ -def determinant_4x4(matrix: list[list[int|float]]) -> float: +def determinant_4x4(matrix: list[list[int | float]]) -> float: # Base case: If the matrix is 1x1, return its single element if len(matrix) == 1: return matrix[0][0] # Recursive case: Calculate determinant using Laplace's Expansion det = 0 for c in range(len(matrix)): - minor = [row[:c] + row[c+1:] for row in matrix[1:]] # Remove column c - cofactor = ((-1)**c) * determinant_4x4(minor) # Compute cofactor + minor = [row[:c] + row[c + 1 :] for row in matrix[1:]] # Remove column c + cofactor = ((-1) ** c) * determinant_4x4(minor) # Compute cofactor det += matrix[0][c] * cofactor # Add to running total return det diff --git a/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/starter_code.py b/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/starter_code.py index 32d67a49..49527285 100644 --- a/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/starter_code.py +++ b/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/starter_code.py @@ -1,3 +1,3 @@ -def determinant_4x4(matrix: list[list[int|float]]) -> float: - # Your recursive implementation here - pass +def determinant_4x4(matrix: list[list[int | float]]) -> float: + # Your recursive implementation here + pass diff --git a/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/tinygrad/solution.py b/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/tinygrad/solution.py index ea44aba5..944ad1e1 100644 --- a/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/tinygrad/solution.py +++ b/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/tinygrad/solution.py @@ -1,6 +1,7 @@ import numpy as np from tinygrad.tensor import Tensor + def determinant_4x4_tg(matrix) -> Tensor: """ Compute the determinant of a 4×4 matrix using tinygrad. diff --git a/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/tinygrad/starter_code.py b/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/tinygrad/starter_code.py index cdcef93e..b33dfc40 100644 --- a/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/tinygrad/starter_code.py +++ b/questions/13_determinant-of-a-4x4-matrix-using-laplace-s-expans/tinygrad/starter_code.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def determinant_4x4_tg(matrix) -> Tensor: """ Compute the determinant of a 4×4 matrix using tinygrad. diff --git a/questions/14_linear-regression-using-normal-equation/pytorch/solution.py b/questions/14_linear-regression-using-normal-equation/pytorch/solution.py index 2469e162..cdb533dc 100644 --- a/questions/14_linear-regression-using-normal-equation/pytorch/solution.py +++ b/questions/14_linear-regression-using-normal-equation/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def linear_regression_normal_equation(X, y) -> torch.Tensor: """ Solve linear regression via the normal equation using PyTorch. @@ -7,9 +8,9 @@ def linear_regression_normal_equation(X, y) -> torch.Tensor: Returns a 1-D tensor of length n, rounded to 4 decimals. """ X_t = torch.as_tensor(X, dtype=torch.float) - y_t = torch.as_tensor(y, dtype=torch.float).reshape(-1,1) + y_t = torch.as_tensor(y, dtype=torch.float).reshape(-1, 1) # normal equation: theta = (XᵀX)⁻¹ Xᵀ y - XtX = X_t.transpose(0,1) @ X_t - theta = torch.linalg.inv(XtX) @ (X_t.transpose(0,1) @ y_t) + XtX = X_t.transpose(0, 1) @ X_t + theta = torch.linalg.inv(XtX) @ (X_t.transpose(0, 1) @ y_t) theta = theta.flatten() return torch.round(theta * 10000) / 10000 diff --git a/questions/14_linear-regression-using-normal-equation/pytorch/starter_code.py b/questions/14_linear-regression-using-normal-equation/pytorch/starter_code.py index c9c5c8ce..9e1ce35a 100644 --- a/questions/14_linear-regression-using-normal-equation/pytorch/starter_code.py +++ b/questions/14_linear-regression-using-normal-equation/pytorch/starter_code.py @@ -1,12 +1,13 @@ import torch + def linear_regression_normal_equation(X, y) -> torch.Tensor: """ Solve linear regression via the normal equation using PyTorch. X: Tensor or convertible of shape (m,n); y: shape (m,) or (m,1). Returns a 1-D tensor of length n, rounded to 4 decimals. """ - X_t = torch.as_tensor(X, dtype=torch.float) - y_t = torch.as_tensor(y, dtype=torch.float).reshape(-1,1) + torch.as_tensor(X, dtype=torch.float) + torch.as_tensor(y, dtype=torch.float).reshape(-1, 1) # Your implementation here pass diff --git a/questions/14_linear-regression-using-normal-equation/solution.py b/questions/14_linear-regression-using-normal-equation/solution.py index 0c60e015..30e2717e 100644 --- a/questions/14_linear-regression-using-normal-equation/solution.py +++ b/questions/14_linear-regression-using-normal-equation/solution.py @@ -1,6 +1,9 @@ - import numpy as np -def linear_regression_normal_equation(X: list[list[float]], y: list[float]) -> list[float]: + + +def linear_regression_normal_equation( + X: list[list[float]], y: list[float] +) -> list[float]: X = np.array(X) y = np.array(y).reshape(-1, 1) X_transpose = X.T diff --git a/questions/14_linear-regression-using-normal-equation/starter_code.py b/questions/14_linear-regression-using-normal-equation/starter_code.py index 38642e7e..cb981cc4 100644 --- a/questions/14_linear-regression-using-normal-equation/starter_code.py +++ b/questions/14_linear-regression-using-normal-equation/starter_code.py @@ -1,4 +1,5 @@ -import numpy as np -def linear_regression_normal_equation(X: list[list[float]], y: list[float]) -> list[float]: - # Your code here, make sure to round - return theta +def linear_regression_normal_equation( + X: list[list[float]], y: list[float] +) -> list[float]: + # Your code here, make sure to round + return theta diff --git a/questions/14_linear-regression-using-normal-equation/tinygrad/solution.py b/questions/14_linear-regression-using-normal-equation/tinygrad/solution.py index 832f53ff..dc107027 100644 --- a/questions/14_linear-regression-using-normal-equation/tinygrad/solution.py +++ b/questions/14_linear-regression-using-normal-equation/tinygrad/solution.py @@ -1,6 +1,7 @@ import numpy as np from tinygrad.tensor import Tensor + def linear_regression_normal_equation_tg(X, y) -> Tensor: """ Solve linear regression via the normal equation using tinygrad. @@ -8,7 +9,7 @@ def linear_regression_normal_equation_tg(X, y) -> Tensor: Returns a 1-D Tensor of length n, rounded to 4 decimals. """ X_np = np.array(X, dtype=float) - y_np = np.array(y, dtype=float).reshape(-1,1) + y_np = np.array(y, dtype=float).reshape(-1, 1) theta = np.linalg.inv(X_np.T.dot(X_np)).dot(X_np.T).dot(y_np) theta = np.round(theta.flatten(), 4) return Tensor(theta) diff --git a/questions/14_linear-regression-using-normal-equation/tinygrad/starter_code.py b/questions/14_linear-regression-using-normal-equation/tinygrad/starter_code.py index eead5dfc..36b81d7d 100644 --- a/questions/14_linear-regression-using-normal-equation/tinygrad/starter_code.py +++ b/questions/14_linear-regression-using-normal-equation/tinygrad/starter_code.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def linear_regression_normal_equation_tg(X, y) -> Tensor: """ Solve linear regression via the normal equation using tinygrad. diff --git a/questions/15_linear-regression-using-gradient-descent/pytorch/solution.py b/questions/15_linear-regression-using-gradient-descent/pytorch/solution.py index 657c914a..55d984a7 100644 --- a/questions/15_linear-regression-using-gradient-descent/pytorch/solution.py +++ b/questions/15_linear-regression-using-gradient-descent/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def linear_regression_gradient_descent(X, y, alpha, iterations) -> torch.Tensor: """ Solve linear regression via gradient descent using PyTorch autograd. @@ -8,9 +9,9 @@ def linear_regression_gradient_descent(X, y, alpha, iterations) -> torch.Tensor: Returns a 1-D tensor of length n, rounded to 4 decimals. """ X_t = torch.as_tensor(X, dtype=torch.float) - y_t = torch.as_tensor(y, dtype=torch.float).reshape(-1,1) + y_t = torch.as_tensor(y, dtype=torch.float).reshape(-1, 1) m, n = X_t.shape - theta = torch.zeros((n,1), requires_grad=True) + theta = torch.zeros((n, 1), requires_grad=True) for _ in range(iterations): preds = X_t @ theta loss = ((preds - y_t) ** 2).mean() diff --git a/questions/15_linear-regression-using-gradient-descent/pytorch/starter_code.py b/questions/15_linear-regression-using-gradient-descent/pytorch/starter_code.py index 3dce5f52..1aeff4c2 100644 --- a/questions/15_linear-regression-using-gradient-descent/pytorch/starter_code.py +++ b/questions/15_linear-regression-using-gradient-descent/pytorch/starter_code.py @@ -1,5 +1,6 @@ import torch + def linear_regression_gradient_descent(X, y, alpha, iterations) -> torch.Tensor: """ Solve linear regression via gradient descent using PyTorch autograd. @@ -8,8 +9,8 @@ def linear_regression_gradient_descent(X, y, alpha, iterations) -> torch.Tensor: Returns a 1-D tensor of length n, rounded to 4 decimals. """ X_t = torch.as_tensor(X, dtype=torch.float) - y_t = torch.as_tensor(y, dtype=torch.float).reshape(-1,1) + torch.as_tensor(y, dtype=torch.float).reshape(-1, 1) m, n = X_t.shape - theta = torch.zeros((n,1), requires_grad=True) + torch.zeros((n, 1), requires_grad=True) # Your implementation here pass diff --git a/questions/15_linear-regression-using-gradient-descent/solution.py b/questions/15_linear-regression-using-gradient-descent/solution.py index ff331bd6..92b82451 100644 --- a/questions/15_linear-regression-using-gradient-descent/solution.py +++ b/questions/15_linear-regression-using-gradient-descent/solution.py @@ -1,4 +1,3 @@ - import numpy as np def linear_regression_gradient_descent(X: np.ndarray, y: np.ndarray, alpha: float, iterations: int) -> np.ndarray: """ diff --git a/questions/15_linear-regression-using-gradient-descent/tinygrad/solution.py b/questions/15_linear-regression-using-gradient-descent/tinygrad/solution.py index 2dc4ad60..dba53deb 100644 --- a/questions/15_linear-regression-using-gradient-descent/tinygrad/solution.py +++ b/questions/15_linear-regression-using-gradient-descent/tinygrad/solution.py @@ -1,6 +1,7 @@ import numpy as np from tinygrad.tensor import Tensor + def linear_regression_gradient_descent_tg(X, y, alpha, iterations) -> Tensor: """ Solve linear regression via gradient descent using tinygrad autograd. @@ -9,7 +10,7 @@ def linear_regression_gradient_descent_tg(X, y, alpha, iterations) -> Tensor: Returns a 1-D Tensor of length n, rounded to 4 decimals. """ X_t = Tensor(X).float() - y_t = Tensor(y).float().reshape(-1,1) + y_t = Tensor(y).float().reshape(-1, 1) m, n = X_t.shape theta = Tensor([[0.0] for _ in range(n)]) for _ in range(iterations): diff --git a/questions/15_linear-regression-using-gradient-descent/tinygrad/starter_code.py b/questions/15_linear-regression-using-gradient-descent/tinygrad/starter_code.py index 9e98b0a3..bdc0dde7 100644 --- a/questions/15_linear-regression-using-gradient-descent/tinygrad/starter_code.py +++ b/questions/15_linear-regression-using-gradient-descent/tinygrad/starter_code.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def linear_regression_gradient_descent_tg(X, y, alpha, iterations) -> Tensor: """ Solve linear regression via gradient descent using tinygrad autograd. @@ -8,8 +9,8 @@ def linear_regression_gradient_descent_tg(X, y, alpha, iterations) -> Tensor: Returns a 1-D Tensor of length n, rounded to 4 decimals. """ X_t = Tensor(X).float() - y_t = Tensor(y).float().reshape(-1,1) + Tensor(y).float().reshape(-1, 1) m, n = X_t.shape - theta = Tensor([[0.0] for _ in range(n)]) + Tensor([[0.0] for _ in range(n)]) # Your implementation here pass diff --git a/questions/16_feature-scaling-implementation/pytorch/solution.py b/questions/16_feature-scaling-implementation/pytorch/solution.py index 4d0508bc..b1bb2f89 100644 --- a/questions/16_feature-scaling-implementation/pytorch/solution.py +++ b/questions/16_feature-scaling-implementation/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def feature_scaling(data) -> tuple[torch.Tensor, torch.Tensor]: """ Standardize and Min-Max normalize input data using PyTorch. diff --git a/questions/16_feature-scaling-implementation/pytorch/starter_code.py b/questions/16_feature-scaling-implementation/pytorch/starter_code.py index 827f55c3..a51ae44e 100644 --- a/questions/16_feature-scaling-implementation/pytorch/starter_code.py +++ b/questions/16_feature-scaling-implementation/pytorch/starter_code.py @@ -1,11 +1,12 @@ import torch + def feature_scaling(data) -> tuple[torch.Tensor, torch.Tensor]: """ Standardize and Min-Max normalize input data using PyTorch. Input: Tensor or convertible of shape (m,n). Returns (standardized_data, normalized_data), both rounded to 4 decimals. """ - data_t = torch.as_tensor(data, dtype=torch.float) + torch.as_tensor(data, dtype=torch.float) # Your implementation here pass diff --git a/questions/16_feature-scaling-implementation/solution.py b/questions/16_feature-scaling-implementation/solution.py index 6b6a0fd7..f39a8429 100644 --- a/questions/16_feature-scaling-implementation/solution.py +++ b/questions/16_feature-scaling-implementation/solution.py @@ -1,15 +1,17 @@ - import numpy as np + def feature_scaling(data): # Standardization mean = np.mean(data, axis=0) std = np.std(data, axis=0) standardized_data = (data - mean) / std - + # Min-Max Normalization min_val = np.min(data, axis=0) max_val = np.max(data, axis=0) normalized_data = (data - min_val) / (max_val - min_val) - - return np.round(standardized_data,4).tolist(), np.round(normalized_data,4).tolist() + + return np.round(standardized_data, 4).tolist(), np.round( + normalized_data, 4 + ).tolist() diff --git a/questions/16_feature-scaling-implementation/starter_code.py b/questions/16_feature-scaling-implementation/starter_code.py index 42618d0a..19260847 100644 --- a/questions/16_feature-scaling-implementation/starter_code.py +++ b/questions/16_feature-scaling-implementation/starter_code.py @@ -1,3 +1,3 @@ def feature_scaling(data: np.ndarray) -> (np.ndarray, np.ndarray): - # Your code here - return standardized_data, normalized_data + # Your code here + return standardized_data, normalized_data diff --git a/questions/16_feature-scaling-implementation/tinygrad/solution.py b/questions/16_feature-scaling-implementation/tinygrad/solution.py index aee85f1b..78bd0bc4 100644 --- a/questions/16_feature-scaling-implementation/tinygrad/solution.py +++ b/questions/16_feature-scaling-implementation/tinygrad/solution.py @@ -1,6 +1,7 @@ import numpy as np from tinygrad.tensor import Tensor + def feature_scaling_tg(data) -> tuple[Tensor, Tensor]: """ Standardize and Min-Max normalize input data using tinygrad. diff --git a/questions/16_feature-scaling-implementation/tinygrad/starter_code.py b/questions/16_feature-scaling-implementation/tinygrad/starter_code.py index 0e367e7d..17cceb8f 100644 --- a/questions/16_feature-scaling-implementation/tinygrad/starter_code.py +++ b/questions/16_feature-scaling-implementation/tinygrad/starter_code.py @@ -1,11 +1,12 @@ from tinygrad.tensor import Tensor + def feature_scaling_tg(data) -> tuple[Tensor, Tensor]: """ Standardize and Min-Max normalize input data using tinygrad. Input: Tensor or convertible of shape (m,n). Returns (standardized_data, normalized_data), both rounded to 4 decimals. """ - data_t = Tensor(data).float() + Tensor(data).float() # Your implementation here pass diff --git a/questions/17_k-means-clustering/pytorch/solution.py b/questions/17_k-means-clustering/pytorch/solution.py index ed0f38d0..46f40c22 100644 --- a/questions/17_k-means-clustering/pytorch/solution.py +++ b/questions/17_k-means-clustering/pytorch/solution.py @@ -1,6 +1,9 @@ import torch -def k_means_clustering(points, k, initial_centroids, max_iterations) -> list[tuple[float, ...]]: + +def k_means_clustering( + points, k, initial_centroids, max_iterations +) -> list[tuple[float, ...]]: """ Perform k-means clustering on `points` into `k` clusters. points: tensor of shape (n_points, n_features) @@ -13,7 +16,7 @@ def k_means_clustering(points, k, initial_centroids, max_iterations) -> list[tup for _ in range(max_iterations): # compute distances (k, n_points) diffs = points_t.unsqueeze(0) - centroids.unsqueeze(1) - distances = torch.sqrt((diffs ** 2).sum(dim=2)) + distances = torch.sqrt((diffs**2).sum(dim=2)) # assign each point to nearest centroid assignments = distances.argmin(dim=0) new_centroids = [] diff --git a/questions/17_k-means-clustering/pytorch/starter_code.py b/questions/17_k-means-clustering/pytorch/starter_code.py index 7101417a..9acc490e 100644 --- a/questions/17_k-means-clustering/pytorch/starter_code.py +++ b/questions/17_k-means-clustering/pytorch/starter_code.py @@ -1,6 +1,9 @@ import torch -def k_means_clustering(points, k, initial_centroids, max_iterations) -> list[tuple[float, ...]]: + +def k_means_clustering( + points, k, initial_centroids, max_iterations +) -> list[tuple[float, ...]]: """ Perform k-means clustering on `points` into `k` clusters. points: tensor of shape (n_points, n_features) @@ -9,7 +12,7 @@ def k_means_clustering(points, k, initial_centroids, max_iterations) -> list[tup Returns a list of k centroids as tuples, rounded to 4 decimals. """ # Convert to tensors - points_t = torch.as_tensor(points, dtype=torch.float) - centroids = torch.as_tensor(initial_centroids, dtype=torch.float) + torch.as_tensor(points, dtype=torch.float) + torch.as_tensor(initial_centroids, dtype=torch.float) # Your implementation here pass diff --git a/questions/17_k-means-clustering/solution.py b/questions/17_k-means-clustering/solution.py index 97d79341..0f65d1d5 100644 --- a/questions/17_k-means-clustering/solution.py +++ b/questions/17_k-means-clustering/solution.py @@ -1,23 +1,33 @@ - import numpy as np + def euclidean_distance(a, b): return np.sqrt(((a - b) ** 2).sum(axis=1)) + def k_means_clustering(points, k, initial_centroids, max_iterations): points = np.array(points) centroids = np.array(initial_centroids) - + for iteration in range(max_iterations): # Assign points to the nearest centroid - distances = np.array([euclidean_distance(points, centroid) for centroid in centroids]) + distances = np.array( + [euclidean_distance(points, centroid) for centroid in centroids] + ) assignments = np.argmin(distances, axis=0) - new_centroids = np.array([points[assignments == i].mean(axis=0) if len(points[assignments == i]) > 0 else centroids[i] for i in range(k)]) - + new_centroids = np.array( + [ + points[assignments == i].mean(axis=0) + if len(points[assignments == i]) > 0 + else centroids[i] + for i in range(k) + ] + ) + # Check for convergence if np.all(centroids == new_centroids): break centroids = new_centroids - centroids = np.round(centroids,4) + centroids = np.round(centroids, 4) return [tuple(centroid) for centroid in centroids] diff --git a/questions/17_k-means-clustering/starter_code.py b/questions/17_k-means-clustering/starter_code.py index 8a792434..9807adfa 100644 --- a/questions/17_k-means-clustering/starter_code.py +++ b/questions/17_k-means-clustering/starter_code.py @@ -1,3 +1,8 @@ -def k_means_clustering(points: list[tuple[float, float]], k: int, initial_centroids: list[tuple[float, float]], max_iterations: int) -> list[tuple[float, float]]: - # Your code here - return final_centroids +def k_means_clustering( + points: list[tuple[float, float]], + k: int, + initial_centroids: list[tuple[float, float]], + max_iterations: int, +) -> list[tuple[float, float]]: + # Your code here + return final_centroids diff --git a/questions/17_k-means-clustering/tinygrad/solution.py b/questions/17_k-means-clustering/tinygrad/solution.py index 53a3370c..3458de98 100644 --- a/questions/17_k-means-clustering/tinygrad/solution.py +++ b/questions/17_k-means-clustering/tinygrad/solution.py @@ -1,7 +1,9 @@ import numpy as np -from tinygrad.tensor import Tensor -def k_means_clustering_tg(points, k, initial_centroids, max_iterations) -> list[tuple[float, ...]]: + +def k_means_clustering_tg( + points, k, initial_centroids, max_iterations +) -> list[tuple[float, ...]]: """ Perform k-means clustering on `points` into `k` clusters using tinygrad. points: list of lists or Tensor, shape (n_points, n_features) @@ -16,10 +18,14 @@ def k_means_clustering_tg(points, k, initial_centroids, max_iterations) -> list[ dists = np.array([np.linalg.norm(pts - c, axis=1) for c in centroids]) # assign points assignments = dists.argmin(axis=0) - new_centroids = np.array([ - pts[assignments == i].mean(axis=0) if np.any(assignments == i) else centroids[i] - for i in range(k) - ]) + new_centroids = np.array( + [ + pts[assignments == i].mean(axis=0) + if np.any(assignments == i) + else centroids[i] + for i in range(k) + ] + ) new_centroids = np.round(new_centroids, 4) if np.array_equal(new_centroids, centroids): break diff --git a/questions/17_k-means-clustering/tinygrad/starter_code.py b/questions/17_k-means-clustering/tinygrad/starter_code.py index 2ae44a09..0f3f73ac 100644 --- a/questions/17_k-means-clustering/tinygrad/starter_code.py +++ b/questions/17_k-means-clustering/tinygrad/starter_code.py @@ -1,6 +1,6 @@ -from tinygrad.tensor import Tensor - -def k_means_clustering_tg(points, k, initial_centroids, max_iterations) -> list[tuple[float, ...]]: +def k_means_clustering_tg( + points, k, initial_centroids, max_iterations +) -> list[tuple[float, ...]]: """ Perform k-means clustering on `points` into `k` clusters using tinygrad. points: list of lists or Tensor, shape (n_points, n_features) diff --git a/questions/18_implement-k-fold-cross-validation/pytorch/solution.py b/questions/18_implement-k-fold-cross-validation/pytorch/solution.py index b9ca822a..6d0ef5a4 100644 --- a/questions/18_implement-k-fold-cross-validation/pytorch/solution.py +++ b/questions/18_implement-k-fold-cross-validation/pytorch/solution.py @@ -1,6 +1,9 @@ import torch -def k_fold_cross_validation(X, y, k=5, shuffle=True) -> list[tuple[list[int], list[int]]]: + +def k_fold_cross_validation( + X, y, k=5, shuffle=True +) -> list[tuple[list[int], list[int]]]: """ Return train/test index splits for k-fold cross-validation using PyTorch. X: Tensor or convertible of shape (n_samples, ...) @@ -20,7 +23,7 @@ def k_fold_cross_validation(X, y, k=5, shuffle=True) -> list[tuple[list[int], li folds = [] start = 0 for fs in fold_sizes: - folds.append(indices[start:start+fs].tolist()) + folds.append(indices[start : start + fs].tolist()) start += fs result = [] for i in range(k): diff --git a/questions/18_implement-k-fold-cross-validation/pytorch/starter_code.py b/questions/18_implement-k-fold-cross-validation/pytorch/starter_code.py index c881f619..16d78e89 100644 --- a/questions/18_implement-k-fold-cross-validation/pytorch/starter_code.py +++ b/questions/18_implement-k-fold-cross-validation/pytorch/starter_code.py @@ -1,6 +1,9 @@ import torch -def k_fold_cross_validation(X, y, k=5, shuffle=True) -> list[tuple[list[int], list[int]]]: + +def k_fold_cross_validation( + X, y, k=5, shuffle=True +) -> list[tuple[list[int], list[int]]]: """ Return train/test index splits for k-fold cross-validation using PyTorch. X: Tensor or convertible of shape (n_samples, ...) @@ -22,7 +25,7 @@ def k_fold_cross_validation(X, y, k=5, shuffle=True) -> list[tuple[list[int], li folds = [] start = 0 for fs in fold_sizes: - folds.append(indices[start:start+fs].tolist()) + folds.append(indices[start : start + fs].tolist()) start += fs # build train/test pairs result = [] diff --git a/questions/18_implement-k-fold-cross-validation/starter_code.py b/questions/18_implement-k-fold-cross-validation/starter_code.py index 8a3ebdbc..2adb7db9 100644 --- a/questions/18_implement-k-fold-cross-validation/starter_code.py +++ b/questions/18_implement-k-fold-cross-validation/starter_code.py @@ -1,5 +1,6 @@ import numpy as np + def k_fold_cross_validation(X: np.ndarray, y: np.ndarray, k=5, shuffle=True): """ Implement k-fold cross-validation by returning train-test indices. diff --git a/questions/18_implement-k-fold-cross-validation/tinygrad/solution.py b/questions/18_implement-k-fold-cross-validation/tinygrad/solution.py index d564f51b..5dfc4603 100644 --- a/questions/18_implement-k-fold-cross-validation/tinygrad/solution.py +++ b/questions/18_implement-k-fold-cross-validation/tinygrad/solution.py @@ -1,6 +1,9 @@ import numpy as np -def k_fold_cross_validation_tg(X, y, k=5, shuffle=True) -> list[tuple[list[int], list[int]]]: + +def k_fold_cross_validation_tg( + X, y, k=5, shuffle=True +) -> list[tuple[list[int], list[int]]]: """ Return train/test index splits for k-fold cross-validation using NumPy backend. X: list or NumPy array or Tensor of shape (n_samples, ...) @@ -20,7 +23,7 @@ def k_fold_cross_validation_tg(X, y, k=5, shuffle=True) -> list[tuple[list[int], folds = [] start = 0 for fs in fold_sizes: - folds.append(indices[start:start+fs].tolist()) + folds.append(indices[start : start + fs].tolist()) start += fs result = [] for i in range(k): diff --git a/questions/18_implement-k-fold-cross-validation/tinygrad/starter_code.py b/questions/18_implement-k-fold-cross-validation/tinygrad/starter_code.py index 2d0c8230..a440c8ab 100644 --- a/questions/18_implement-k-fold-cross-validation/tinygrad/starter_code.py +++ b/questions/18_implement-k-fold-cross-validation/tinygrad/starter_code.py @@ -1,4 +1,6 @@ -def k_fold_cross_validation_tg(X, y, k=5, shuffle=True) -> list[tuple[list[int], list[int]]]: +def k_fold_cross_validation_tg( + X, y, k=5, shuffle=True +) -> list[tuple[list[int], list[int]]]: """ Return train/test index splits for k-fold cross-validation using pure Python or tinygrad. X: list or Tensor of shape (n_samples, ...) diff --git a/questions/19_principal-component-analysis-pca-implementation/pytorch/solution.py b/questions/19_principal-component-analysis-pca-implementation/pytorch/solution.py index 7a8263fc..dccbee4e 100644 --- a/questions/19_principal-component-analysis-pca-implementation/pytorch/solution.py +++ b/questions/19_principal-component-analysis-pca-implementation/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def pca(data, k) -> torch.Tensor: """ Perform PCA on `data`, returning the top `k` principal components as a tensor. @@ -9,7 +10,7 @@ def pca(data, k) -> torch.Tensor: data_t = torch.as_tensor(data, dtype=torch.float) # Standardize mean = data_t.mean(dim=0, keepdim=True) - std = data_t.std(dim=0, unbiased=False, keepdim=True) + std = data_t.std(dim=0, unbiased=False, keepdim=True) data_std = (data_t - mean) / std # Covariance cov = torch.cov(data_std.T) diff --git a/questions/19_principal-component-analysis-pca-implementation/pytorch/starter_code.py b/questions/19_principal-component-analysis-pca-implementation/pytorch/starter_code.py index 3df21fa1..ddcbfea8 100644 --- a/questions/19_principal-component-analysis-pca-implementation/pytorch/starter_code.py +++ b/questions/19_principal-component-analysis-pca-implementation/pytorch/starter_code.py @@ -1,11 +1,12 @@ import torch + def pca(data, k) -> torch.Tensor: """ Perform PCA on `data`, returning the top `k` principal components as a tensor. Input: Tensor or convertible of shape (n_samples, n_features). Returns: a torch.Tensor of shape (n_features, k), with floats rounded to 4 decimals. """ - data_t = torch.as_tensor(data, dtype=torch.float) + torch.as_tensor(data, dtype=torch.float) # Your implementation here pass diff --git a/questions/19_principal-component-analysis-pca-implementation/solution.py b/questions/19_principal-component-analysis-pca-implementation/solution.py index 75b349e5..02222015 100644 --- a/questions/19_principal-component-analysis-pca-implementation/solution.py +++ b/questions/19_principal-component-analysis-pca-implementation/solution.py @@ -1,22 +1,22 @@ - import numpy as np + def pca(data, k): # Standardize the data data_standardized = (data - np.mean(data, axis=0)) / np.std(data, axis=0) - + # Compute the covariance matrix covariance_matrix = np.cov(data_standardized, rowvar=False) - + # Eigen decomposition eigenvalues, eigenvectors = np.linalg.eig(covariance_matrix) - + # Sort the eigenvectors by decreasing eigenvalues idx = np.argsort(eigenvalues)[::-1] - eigenvalues_sorted = eigenvalues[idx] - eigenvectors_sorted = eigenvectors[:,idx] - + eigenvalues[idx] + eigenvectors_sorted = eigenvectors[:, idx] + # Select the top k eigenvectors (principal components) principal_components = eigenvectors_sorted[:, :k] - + return np.round(principal_components, 4) diff --git a/questions/19_principal-component-analysis-pca-implementation/starter_code.py b/questions/19_principal-component-analysis-pca-implementation/starter_code.py index 3cb75f74..5799f625 100644 --- a/questions/19_principal-component-analysis-pca-implementation/starter_code.py +++ b/questions/19_principal-component-analysis-pca-implementation/starter_code.py @@ -1,4 +1,6 @@ -import numpy as np +import numpy as np + + def pca(data: np.ndarray, k: int) -> np.ndarray: - # Your code here - return np.round(principal_components, 4) + # Your code here + return np.round(principal_components, 4) diff --git a/questions/19_principal-component-analysis-pca-implementation/tinygrad/solution.py b/questions/19_principal-component-analysis-pca-implementation/tinygrad/solution.py index 61724c54..4ea761da 100644 --- a/questions/19_principal-component-analysis-pca-implementation/tinygrad/solution.py +++ b/questions/19_principal-component-analysis-pca-implementation/tinygrad/solution.py @@ -1,6 +1,7 @@ import numpy as np from tinygrad.tensor import Tensor + def pca_tg(data, k) -> Tensor: """ Perform PCA on `data`, returning the top `k` principal components as a tinygrad Tensor. diff --git a/questions/19_principal-component-analysis-pca-implementation/tinygrad/starter_code.py b/questions/19_principal-component-analysis-pca-implementation/tinygrad/starter_code.py index d46a32e7..9d2b4029 100644 --- a/questions/19_principal-component-analysis-pca-implementation/tinygrad/starter_code.py +++ b/questions/19_principal-component-analysis-pca-implementation/tinygrad/starter_code.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def pca_tg(data, k) -> Tensor: """ Perform PCA on `data`, returning the top `k` principal components as a tinygrad Tensor. diff --git a/questions/1_matrix-vector-dot-product/pytorch/solution.py b/questions/1_matrix-vector-dot-product/pytorch/solution.py index 17a3f582..e43a2e3d 100644 --- a/questions/1_matrix-vector-dot-product/pytorch/solution.py +++ b/questions/1_matrix-vector-dot-product/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def matrix_dot_vector(a, b) -> torch.Tensor: """ Compute the product of matrix `a` and vector `b` using PyTorch. diff --git a/questions/1_matrix-vector-dot-product/pytorch/starter_code.py b/questions/1_matrix-vector-dot-product/pytorch/starter_code.py index 776632b8..0139dc98 100644 --- a/questions/1_matrix-vector-dot-product/pytorch/starter_code.py +++ b/questions/1_matrix-vector-dot-product/pytorch/starter_code.py @@ -1,5 +1,6 @@ import torch + def matrix_dot_vector(a, b) -> torch.Tensor: """ Compute the product of matrix `a` and vector `b` using PyTorch. diff --git a/questions/1_matrix-vector-dot-product/solution.py b/questions/1_matrix-vector-dot-product/solution.py index db795872..2356e2a7 100644 --- a/questions/1_matrix-vector-dot-product/solution.py +++ b/questions/1_matrix-vector-dot-product/solution.py @@ -1,4 +1,6 @@ -def matrix_dot_vector(a: list[list[int|float]], b: list[int|float]) -> list[int|float]: +def matrix_dot_vector( + a: list[list[int | float]], b: list[int | float] +) -> list[int | float]: if len(a[0]) != len(b): return -1 result = [] diff --git a/questions/1_matrix-vector-dot-product/starter_code.py b/questions/1_matrix-vector-dot-product/starter_code.py index 9d681c5b..eafcef69 100644 --- a/questions/1_matrix-vector-dot-product/starter_code.py +++ b/questions/1_matrix-vector-dot-product/starter_code.py @@ -1,4 +1,6 @@ -def matrix_dot_vector(a: list[list[int|float]], b: list[int|float]) -> list[int|float]: - # Return a list where each element is the dot product of a row of 'a' with 'b'. - # If the number of columns in 'a' does not match the length of 'b', return -1. - pass +def matrix_dot_vector( + a: list[list[int | float]], b: list[int | float] +) -> list[int | float]: + # Return a list where each element is the dot product of a row of 'a' with 'b'. + # If the number of columns in 'a' does not match the length of 'b', return -1. + pass diff --git a/questions/20_decision-tree-learning/pytorch/solution.py b/questions/20_decision-tree-learning/pytorch/solution.py index 52e72cc7..20eaeb77 100644 --- a/questions/20_decision-tree-learning/pytorch/solution.py +++ b/questions/20_decision-tree-learning/pytorch/solution.py @@ -1,4 +1,3 @@ -import torch import math from collections import Counter from typing import List, Dict, Any, Union @@ -15,9 +14,7 @@ def calculate_entropy(labels: List[Any]) -> float: def calculate_information_gain( - examples: List[Dict[str, Any]], - attr: str, - target_attr: str + examples: List[Dict[str, Any]], attr: str, target_attr: str ) -> float: total_labels = [ex[target_attr] for ex in examples] total_ent = calculate_entropy(total_labels) @@ -25,30 +22,27 @@ def calculate_information_gain( rem = 0.0 for v in set(ex[attr] for ex in examples): subset_labels = [ex[target_attr] for ex in examples if ex[attr] == v] - rem += (len(subset_labels)/n) * calculate_entropy(subset_labels) + rem += (len(subset_labels) / n) * calculate_entropy(subset_labels) return total_ent - rem -def majority_class( - examples: List[Dict[str, Any]], - target_attr: str -) -> Any: +def majority_class(examples: List[Dict[str, Any]], target_attr: str) -> Any: return Counter(ex[target_attr] for ex in examples).most_common(1)[0][0] def learn_decision_tree( - examples: List[Dict[str, Any]], - attributes: List[str], - target_attr: str + examples: List[Dict[str, Any]], attributes: List[str], target_attr: str ) -> Union[Dict[str, Any], Any]: if not examples: - return 'No examples' + return "No examples" first_label = examples[0][target_attr] if all(ex[target_attr] == first_label for ex in examples): return first_label if not attributes: return majority_class(examples, target_attr) - gains = {a: calculate_information_gain(examples, a, target_attr) for a in attributes} + gains = { + a: calculate_information_gain(examples, a, target_attr) for a in attributes + } best = max(gains, key=gains.get) tree: Dict[str, Any] = {best: {}} for v in set(ex[best] for ex in examples): diff --git a/questions/20_decision-tree-learning/pytorch/starter_code.py b/questions/20_decision-tree-learning/pytorch/starter_code.py index 4531de26..fdff605f 100644 --- a/questions/20_decision-tree-learning/pytorch/starter_code.py +++ b/questions/20_decision-tree-learning/pytorch/starter_code.py @@ -1,6 +1,3 @@ -import torch -import math -from collections import Counter from typing import List, Dict, Any, Union @@ -15,9 +12,7 @@ def calculate_entropy(labels: List[Any]) -> float: def calculate_information_gain( - examples: List[Dict[str, Any]], - attr: str, - target_attr: str + examples: List[Dict[str, Any]], attr: str, target_attr: str ) -> float: """ Compute information gain for splitting `examples` on `attr` w.r.t. `target_attr`. @@ -27,10 +22,7 @@ def calculate_information_gain( pass -def majority_class( - examples: List[Dict[str, Any]], - target_attr: str -) -> Any: +def majority_class(examples: List[Dict[str, Any]], target_attr: str) -> Any: """ Return the most common value of `target_attr` in `examples`. """ @@ -39,9 +31,7 @@ def majority_class( def learn_decision_tree( - examples: List[Dict[str, Any]], - attributes: List[str], - target_attr: str + examples: List[Dict[str, Any]], attributes: List[str], target_attr: str ) -> Union[Dict[str, Any], Any]: """ Learn a decision tree using the ID3 algorithm. diff --git a/questions/20_decision-tree-learning/solution.py b/questions/20_decision-tree-learning/solution.py index 3a66870e..78cfc6bd 100644 --- a/questions/20_decision-tree-learning/solution.py +++ b/questions/20_decision-tree-learning/solution.py @@ -1,43 +1,54 @@ - import math from collections import Counter + def calculate_entropy(labels): label_counts = Counter(labels) total_count = len(labels) - entropy = -sum((count / total_count) * math.log2(count / total_count) for count in label_counts.values()) + entropy = -sum( + (count / total_count) * math.log2(count / total_count) + for count in label_counts.values() + ) return entropy + def calculate_information_gain(examples, attr, target_attr): total_entropy = calculate_entropy([example[target_attr] for example in examples]) values = set(example[attr] for example in examples) attr_entropy = 0 for value in values: - value_subset = [example[target_attr] for example in examples if example[attr] == value] + value_subset = [ + example[target_attr] for example in examples if example[attr] == value + ] value_entropy = calculate_entropy(value_subset) attr_entropy += (len(value_subset) / len(examples)) * value_entropy return total_entropy - attr_entropy + def majority_class(examples, target_attr): return Counter([example[target_attr] for example in examples]).most_common(1)[0][0] + def learn_decision_tree(examples, attributes, target_attr): if not examples: - return 'No examples' + return "No examples" if all(example[target_attr] == examples[0][target_attr] for example in examples): return examples[0][target_attr] if not attributes: return majority_class(examples, target_attr) - - gains = {attr: calculate_information_gain(examples, attr, target_attr) for attr in attributes} + + gains = { + attr: calculate_information_gain(examples, attr, target_attr) + for attr in attributes + } best_attr = max(gains, key=gains.get) tree = {best_attr: {}} - + for value in set(example[best_attr] for example in examples): subset = [example for example in examples if example[best_attr] == value] new_attributes = attributes.copy() new_attributes.remove(best_attr) subtree = learn_decision_tree(subset, new_attributes, target_attr) tree[best_attr][value] = subtree - + return tree diff --git a/questions/20_decision-tree-learning/starter_code.py b/questions/20_decision-tree-learning/starter_code.py index fd8e7112..943552ef 100644 --- a/questions/20_decision-tree-learning/starter_code.py +++ b/questions/20_decision-tree-learning/starter_code.py @@ -1,3 +1,5 @@ -def learn_decision_tree(examples: list[dict], attributes: list[str], target_attr: str) -> dict: - # Your code here - return decision_tree +def learn_decision_tree( + examples: list[dict], attributes: list[str], target_attr: str +) -> dict: + # Your code here + return decision_tree diff --git a/questions/20_decision-tree-learning/tinygrad/solution.py b/questions/20_decision-tree-learning/tinygrad/solution.py index 808c6f85..95f46466 100644 --- a/questions/20_decision-tree-learning/tinygrad/solution.py +++ b/questions/20_decision-tree-learning/tinygrad/solution.py @@ -8,13 +8,11 @@ def calculate_entropy_tg(labels) -> float: arr = labels.tolist() if isinstance(labels, Tensor) else labels total = len(arr) cnt = Counter(arr) - return -sum((c/total)*math.log2(c/total) for c in cnt.values()) + return -sum((c / total) * math.log2(c / total) for c in cnt.values()) def calculate_information_gain_tg( - examples: List[Dict[str, Any]], - attr: str, - target_attr: str + examples: List[Dict[str, Any]], attr: str, target_attr: str ) -> float: total = [ex[target_attr] for ex in examples] total_ent = calculate_entropy_tg(total) @@ -22,30 +20,27 @@ def calculate_information_gain_tg( rem = 0.0 for v in set(ex[attr] for ex in examples): subset = [ex[target_attr] for ex in examples if ex[attr] == v] - rem += (len(subset)/n) * calculate_entropy_tg(subset) + rem += (len(subset) / n) * calculate_entropy_tg(subset) return total_ent - rem -def majority_class_tg( - examples: List[Dict[str, Any]], - target_attr: str -) -> Any: +def majority_class_tg(examples: List[Dict[str, Any]], target_attr: str) -> Any: return Counter(ex[target_attr] for ex in examples).most_common(1)[0][0] def learn_decision_tree_tg( - examples: List[Dict[str, Any]], - attributes: List[str], - target_attr: str + examples: List[Dict[str, Any]], attributes: List[str], target_attr: str ) -> Union[Dict[str, Any], Any]: if not examples: - return 'No examples' + return "No examples" first_label = examples[0][target_attr] if all(ex[target_attr] == first_label for ex in examples): return first_label if not attributes: return majority_class_tg(examples, target_attr) - gains = {a: calculate_information_gain_tg(examples, a, target_attr) for a in attributes} + gains = { + a: calculate_information_gain_tg(examples, a, target_attr) for a in attributes + } best = max(gains, key=gains.get) tree: Dict[str, Any] = {best: {}} for v in set(ex[best] for ex in examples): diff --git a/questions/20_decision-tree-learning/tinygrad/starter_code.py b/questions/20_decision-tree-learning/tinygrad/starter_code.py index 510b469b..e3cafa7f 100644 --- a/questions/20_decision-tree-learning/tinygrad/starter_code.py +++ b/questions/20_decision-tree-learning/tinygrad/starter_code.py @@ -1,12 +1,8 @@ -import math -from collections import Counter from typing import List, Dict, Any, Union def learn_decision_tree_tg( - examples: List[Dict[str, Any]], - attributes: List[str], - target_attr: str + examples: List[Dict[str, Any]], attributes: List[str], target_attr: str ) -> Union[Dict[str, Any], Any]: """ Learn a decision tree using ID3 with tinygrad for entropy/gain. diff --git a/questions/21_pegasos-kernel-svm-implementation/solution.py b/questions/21_pegasos-kernel-svm-implementation/solution.py index bee077e2..1f07bcc5 100644 --- a/questions/21_pegasos-kernel-svm-implementation/solution.py +++ b/questions/21_pegasos-kernel-svm-implementation/solution.py @@ -1,13 +1,17 @@ - import numpy as np + def linear_kernel(x, y): return np.dot(x, y) + def rbf_kernel(x, y, sigma=1.0): - return np.exp(-np.linalg.norm(x-y)**2 / (2 * (sigma ** 2))) + return np.exp(-(np.linalg.norm(x - y) ** 2) / (2 * (sigma**2))) -def pegasos_kernel_svm(data, labels, kernel='linear', lambda_val=0.01, iterations=100, sigma=1.0): + +def pegasos_kernel_svm( + data, labels, kernel="linear", lambda_val=0.01, iterations=100, sigma=1.0 +): n_samples = len(data) alphas = np.zeros(n_samples) b = 0 @@ -15,14 +19,21 @@ def pegasos_kernel_svm(data, labels, kernel='linear', lambda_val=0.01, iteration for t in range(1, iterations + 1): for i in range(n_samples): eta = 1.0 / (lambda_val * t) - if kernel == 'linear': + if kernel == "linear": kernel_func = linear_kernel - elif kernel == 'rbf': - kernel_func = lambda x, y: rbf_kernel(x, y, sigma) - - decision = sum(alphas[j] * labels[j] * kernel_func(data[j], data[i]) for j in range(n_samples)) + b + elif kernel == "rbf": + def kernel_func(x, y): + return rbf_kernel(x, y, sigma) + + decision = ( + sum( + alphas[j] * labels[j] * kernel_func(data[j], data[i]) + for j in range(n_samples) + ) + + b + ) if labels[i] * decision < 1: alphas[i] += eta * (labels[i] - lambda_val * alphas[i]) b += eta * labels[i] - return np.round(alphas,4).tolist(), np.round(b,4) + return np.round(alphas, 4).tolist(), np.round(b, 4) diff --git a/questions/21_pegasos-kernel-svm-implementation/starter_code.py b/questions/21_pegasos-kernel-svm-implementation/starter_code.py index 06fbcc08..b6069bda 100644 --- a/questions/21_pegasos-kernel-svm-implementation/starter_code.py +++ b/questions/21_pegasos-kernel-svm-implementation/starter_code.py @@ -1,3 +1,10 @@ -def pegasos_kernel_svm(data: np.ndarray, labels: np.ndarray, kernel='linear', lambda_val=0.01, iterations=100,sigma=1.0) -> (list, float): - # Your code here - return alphas, b +def pegasos_kernel_svm( + data: np.ndarray, + labels: np.ndarray, + kernel="linear", + lambda_val=0.01, + iterations=100, + sigma=1.0, +) -> (list, float): + # Your code here + return alphas, b diff --git a/questions/22_sigmoid-activation-function-understanding/pytorch/solution.py b/questions/22_sigmoid-activation-function-understanding/pytorch/solution.py index 8ec1343d..4604b9c0 100644 --- a/questions/22_sigmoid-activation-function-understanding/pytorch/solution.py +++ b/questions/22_sigmoid-activation-function-understanding/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def sigmoid(z: float) -> float: """ Compute the sigmoid activation function. diff --git a/questions/22_sigmoid-activation-function-understanding/pytorch/starter_code.py b/questions/22_sigmoid-activation-function-understanding/pytorch/starter_code.py index c1503f83..28ac05aa 100644 --- a/questions/22_sigmoid-activation-function-understanding/pytorch/starter_code.py +++ b/questions/22_sigmoid-activation-function-understanding/pytorch/starter_code.py @@ -1,5 +1,3 @@ -import torch - def sigmoid(z: float) -> float: """ Compute the sigmoid activation function. diff --git a/questions/22_sigmoid-activation-function-understanding/solution.py b/questions/22_sigmoid-activation-function-understanding/solution.py index c3a97bb9..f6ef453c 100644 --- a/questions/22_sigmoid-activation-function-understanding/solution.py +++ b/questions/22_sigmoid-activation-function-understanding/solution.py @@ -1,5 +1,6 @@ - import math + + def sigmoid(z: float) -> float: - result = 1 / (1 + math.exp(-z)) - return round(result, 4) + result = 1 / (1 + math.exp(-z)) + return round(result, 4) diff --git a/questions/22_sigmoid-activation-function-understanding/starter_code.py b/questions/22_sigmoid-activation-function-understanding/starter_code.py index 256d2e53..7b5ab6a1 100644 --- a/questions/22_sigmoid-activation-function-understanding/starter_code.py +++ b/questions/22_sigmoid-activation-function-understanding/starter_code.py @@ -1,5 +1,3 @@ -import math - def sigmoid(z: float) -> float: - #Your code here - return result + # Your code here + return result diff --git a/questions/22_sigmoid-activation-function-understanding/tinygrad/solution.py b/questions/22_sigmoid-activation-function-understanding/tinygrad/solution.py index 4309ce0b..ae2e5797 100644 --- a/questions/22_sigmoid-activation-function-understanding/tinygrad/solution.py +++ b/questions/22_sigmoid-activation-function-understanding/tinygrad/solution.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def sigmoid_tg(z: float) -> float: """ Compute the sigmoid activation function using tinygrad. diff --git a/questions/22_sigmoid-activation-function-understanding/tinygrad/starter_code.py b/questions/22_sigmoid-activation-function-understanding/tinygrad/starter_code.py index d7bda8d1..f1e3e90e 100644 --- a/questions/22_sigmoid-activation-function-understanding/tinygrad/starter_code.py +++ b/questions/22_sigmoid-activation-function-understanding/tinygrad/starter_code.py @@ -1,5 +1,3 @@ -from tinygrad.tensor import Tensor - def sigmoid_tg(z: float) -> float: """ Compute the sigmoid activation function using tinygrad. diff --git a/questions/23_softmax-activation-function-implementation/pytorch/solution.py b/questions/23_softmax-activation-function-implementation/pytorch/solution.py index c67de0f3..09141274 100644 --- a/questions/23_softmax-activation-function-implementation/pytorch/solution.py +++ b/questions/23_softmax-activation-function-implementation/pytorch/solution.py @@ -1,6 +1,7 @@ import torch import torch.nn.functional as F + def softmax(scores: list[float]) -> list[float]: """ Compute the softmax activation function using PyTorch's built-in API. diff --git a/questions/23_softmax-activation-function-implementation/pytorch/starter_code.py b/questions/23_softmax-activation-function-implementation/pytorch/starter_code.py index 92c9f722..1925a07b 100644 --- a/questions/23_softmax-activation-function-implementation/pytorch/starter_code.py +++ b/questions/23_softmax-activation-function-implementation/pytorch/starter_code.py @@ -1,6 +1,3 @@ -import torch -import torch.nn.functional as F - def softmax(scores: list[float]) -> list[float]: """ Compute the softmax activation function using PyTorch's built-in API. diff --git a/questions/23_softmax-activation-function-implementation/solution.py b/questions/23_softmax-activation-function-implementation/solution.py index e715515f..c0f0b2af 100644 --- a/questions/23_softmax-activation-function-implementation/solution.py +++ b/questions/23_softmax-activation-function-implementation/solution.py @@ -1,5 +1,6 @@ - import math + + def softmax(scores: list[float]) -> list[float]: exp_scores = [math.exp(score) for score in scores] sum_exp_scores = sum(exp_scores) diff --git a/questions/23_softmax-activation-function-implementation/starter_code.py b/questions/23_softmax-activation-function-implementation/starter_code.py index e4daa5cb..c8234764 100644 --- a/questions/23_softmax-activation-function-implementation/starter_code.py +++ b/questions/23_softmax-activation-function-implementation/starter_code.py @@ -1,5 +1,3 @@ -import math - def softmax(scores: list[float]) -> list[float]: - # Your code here - return probabilities + # Your code here + return probabilities diff --git a/questions/23_softmax-activation-function-implementation/tinygrad/solution.py b/questions/23_softmax-activation-function-implementation/tinygrad/solution.py index 28d20dd0..13bedf12 100644 --- a/questions/23_softmax-activation-function-implementation/tinygrad/solution.py +++ b/questions/23_softmax-activation-function-implementation/tinygrad/solution.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def softmax_tg(scores: list[float]) -> list[float]: """ Compute the softmax activation function using tinygrad. diff --git a/questions/23_softmax-activation-function-implementation/tinygrad/starter_code.py b/questions/23_softmax-activation-function-implementation/tinygrad/starter_code.py index c393b378..3f6c89ca 100644 --- a/questions/23_softmax-activation-function-implementation/tinygrad/starter_code.py +++ b/questions/23_softmax-activation-function-implementation/tinygrad/starter_code.py @@ -1,5 +1,3 @@ -from tinygrad.tensor import Tensor - def softmax_tg(scores: list[float]) -> list[float]: """ Compute the softmax activation function using tinygrad. diff --git a/questions/24_single-neuron/pytorch/solution.py b/questions/24_single-neuron/pytorch/solution.py index e107e0a4..b06d42c6 100644 --- a/questions/24_single-neuron/pytorch/solution.py +++ b/questions/24_single-neuron/pytorch/solution.py @@ -2,11 +2,9 @@ import torch.nn.functional as F from typing import List, Tuple + def single_neuron_model( - features: List[List[float]], - labels: List[float], - weights: List[float], - bias: float + features: List[List[float]], labels: List[float], weights: List[float], bias: float ) -> Tuple[List[float], float]: X = torch.tensor(features, dtype=torch.float) y = torch.tensor(labels, dtype=torch.float) @@ -17,6 +15,6 @@ def single_neuron_model( probs_t = torch.sigmoid(logits) probs = probs_t.tolist() - mse = F.mse_loss(probs_t, y, reduction='mean').item() + mse = F.mse_loss(probs_t, y, reduction="mean").item() return probs, mse diff --git a/questions/24_single-neuron/pytorch/starter_code.py b/questions/24_single-neuron/pytorch/starter_code.py index 6949c284..260a445a 100644 --- a/questions/24_single-neuron/pytorch/starter_code.py +++ b/questions/24_single-neuron/pytorch/starter_code.py @@ -1,12 +1,8 @@ -import torch -import torch.nn.functional as F from typing import List, Tuple + def single_neuron_model( - features: List[List[float]], - labels: List[float], - weights: List[float], - bias: float + features: List[List[float]], labels: List[float], weights: List[float], bias: float ) -> Tuple[List[float], float]: """ Compute output probabilities and MSE for a single neuron. diff --git a/questions/24_single-neuron/solution.py b/questions/24_single-neuron/solution.py index 273e9e03..4b502700 100644 --- a/questions/24_single-neuron/solution.py +++ b/questions/24_single-neuron/solution.py @@ -1,13 +1,19 @@ - import math + + def single_neuron_model(features, labels, weights, bias): probabilities = [] for feature_vector in features: - z = sum(weight * feature for weight, feature in zip(weights, feature_vector)) + bias + z = ( + sum(weight * feature for weight, feature in zip(weights, feature_vector)) + + bias + ) prob = 1 / (1 + math.exp(-z)) probabilities.append(round(prob, 4)) - - mse = sum((prob - label) ** 2 for prob, label in zip(probabilities, labels)) / len(labels) + + mse = sum((prob - label) ** 2 for prob, label in zip(probabilities, labels)) / len( + labels + ) mse = round(mse, 4) - + return probabilities, mse diff --git a/questions/24_single-neuron/starter_code.py b/questions/24_single-neuron/starter_code.py index 87219501..15e5cc8c 100644 --- a/questions/24_single-neuron/starter_code.py +++ b/questions/24_single-neuron/starter_code.py @@ -1,5 +1,5 @@ -import math - -def single_neuron_model(features: list[list[float]], labels: list[int], weights: list[float], bias: float) -> (list[float], float): - # Your code here - return probabilities, mse +def single_neuron_model( + features: list[list[float]], labels: list[int], weights: list[float], bias: float +) -> (list[float], float): + # Your code here + return probabilities, mse diff --git a/questions/24_single-neuron/tinygrad/solution.py b/questions/24_single-neuron/tinygrad/solution.py index e8c00bd8..c440ca02 100644 --- a/questions/24_single-neuron/tinygrad/solution.py +++ b/questions/24_single-neuron/tinygrad/solution.py @@ -1,11 +1,9 @@ from tinygrad.tensor import Tensor from typing import List, Tuple + def single_neuron_model_tg( - features: List[List[float]], - labels: List[float], - weights: List[float], - bias: float + features: List[List[float]], labels: List[float], weights: List[float], bias: float ) -> Tuple[List[float], float]: X = Tensor(features) w = Tensor(weights) @@ -16,7 +14,7 @@ def single_neuron_model_tg( p = z.sigmoid().numpy().tolist() probs.append(round(p, 4)) - mse = sum((p - y)**2 for p, y in zip(probs, labels)) / len(labels) + mse = sum((p - y) ** 2 for p, y in zip(probs, labels)) / len(labels) mse = round(mse, 4) return probs, mse diff --git a/questions/24_single-neuron/tinygrad/starter_code.py b/questions/24_single-neuron/tinygrad/starter_code.py index 5dd4e8c4..8a8722dd 100644 --- a/questions/24_single-neuron/tinygrad/starter_code.py +++ b/questions/24_single-neuron/tinygrad/starter_code.py @@ -1,11 +1,8 @@ -from tinygrad.tensor import Tensor from typing import List, Tuple + def single_neuron_model_tg( - features: List[List[float]], - labels: List[float], - weights: List[float], - bias: float + features: List[List[float]], labels: List[float], weights: List[float], bias: float ) -> Tuple[List[float], float]: """ Compute output probabilities and MSE for a single neuron using tinygrad. diff --git a/questions/25_single-neuron-with-backpropagation/pytorch/solution.py b/questions/25_single-neuron-with-backpropagation/pytorch/solution.py index 960ad81b..1292b492 100644 --- a/questions/25_single-neuron-with-backpropagation/pytorch/solution.py +++ b/questions/25_single-neuron-with-backpropagation/pytorch/solution.py @@ -4,16 +4,15 @@ def train_neuron( features: Union[List[List[float]], torch.Tensor], - labels: Union[List[float], torch.Tensor], + labels: Union[List[float], torch.Tensor], initial_weights: Union[List[float], torch.Tensor], initial_bias: float, learning_rate: float, - epochs: int + epochs: int, ) -> Tuple[List[float], float, List[float]]: - # Ensure tensors X = torch.as_tensor(features, dtype=torch.float) - y = torch.as_tensor(labels, dtype=torch.float) + y = torch.as_tensor(labels, dtype=torch.float) w = torch.as_tensor(initial_weights, dtype=torch.float) b = torch.tensor(initial_bias, dtype=torch.float) @@ -22,9 +21,9 @@ def train_neuron( for _ in range(epochs): # Forward - z = X @ w + b # (n,) - preds = torch.sigmoid(z) # (n,) - errors = preds - y # (n,) + z = X @ w + b # (n,) + preds = torch.sigmoid(z) # (n,) + errors = preds - y # (n,) # MSE mse = torch.mean(errors**2).item() @@ -32,10 +31,10 @@ def train_neuron( # Manual gradients (chain-rule): dMSE/dz = 2/n * (preds-y) * σ'(z) sigma_prime = preds * (1 - preds) - delta = (2.0 / n) * errors * sigma_prime # (n,) + delta = (2.0 / n) * errors * sigma_prime # (n,) - grad_w = X.t() @ delta # (f,) - grad_b = delta.sum() # scalar + grad_w = X.t() @ delta # (f,) + grad_b = delta.sum() # scalar # Parameter update (gradient descent) w -= learning_rate * grad_w @@ -43,5 +42,5 @@ def train_neuron( # Round final params for return updated_weights = [round(val, 4) for val in w.tolist()] - updated_bias = round(b.item(), 4) + updated_bias = round(b.item(), 4) return updated_weights, updated_bias, mse_values diff --git a/questions/25_single-neuron-with-backpropagation/pytorch/starter_code.py b/questions/25_single-neuron-with-backpropagation/pytorch/starter_code.py index 91dffc29..9b0b0d93 100644 --- a/questions/25_single-neuron-with-backpropagation/pytorch/starter_code.py +++ b/questions/25_single-neuron-with-backpropagation/pytorch/starter_code.py @@ -4,11 +4,11 @@ def train_neuron( features: Union[List[List[float]], torch.Tensor], - labels: Union[List[float], torch.Tensor], + labels: Union[List[float], torch.Tensor], initial_weights: Union[List[float], torch.Tensor], initial_bias: float, learning_rate: float, - epochs: int + epochs: int, ) -> Tuple[List[float], float, List[float]]: """ Train a single neuron (sigmoid activation) with mean-squared-error loss. diff --git a/questions/25_single-neuron-with-backpropagation/solution.py b/questions/25_single-neuron-with-backpropagation/solution.py index b4d38e8e..f1fe9a65 100644 --- a/questions/25_single-neuron-with-backpropagation/solution.py +++ b/questions/25_single-neuron-with-backpropagation/solution.py @@ -1,10 +1,13 @@ - import numpy as np + def sigmoid(x): return 1 / (1 + np.exp(-x)) -def train_neuron(features, labels, initial_weights, initial_bias, learning_rate, epochs): + +def train_neuron( + features, labels, initial_weights, initial_bias, learning_rate, epochs +): weights = np.array(initial_weights) bias = initial_bias features = np.array(features) @@ -14,15 +17,19 @@ def train_neuron(features, labels, initial_weights, initial_bias, learning_rate, for _ in range(epochs): z = np.dot(features, weights) + bias predictions = sigmoid(z) - + mse = np.mean((predictions - labels) ** 2) mse_values.append(round(mse, 4)) # Gradient calculation for weights and bias errors = predictions - labels - weight_gradients = (2/len(labels)) * np.dot(features.T, errors * predictions * (1 - predictions)) - bias_gradient = (2/len(labels)) * np.sum(errors * predictions * (1 - predictions)) - + weight_gradients = (2 / len(labels)) * np.dot( + features.T, errors * predictions * (1 - predictions) + ) + bias_gradient = (2 / len(labels)) * np.sum( + errors * predictions * (1 - predictions) + ) + # Update weights and bias weights -= learning_rate * weight_gradients bias -= learning_rate * bias_gradient diff --git a/questions/25_single-neuron-with-backpropagation/starter_code.py b/questions/25_single-neuron-with-backpropagation/starter_code.py index a92792bf..6d1f896e 100644 --- a/questions/25_single-neuron-with-backpropagation/starter_code.py +++ b/questions/25_single-neuron-with-backpropagation/starter_code.py @@ -1,4 +1,13 @@ import numpy as np -def train_neuron(features: np.ndarray, labels: np.ndarray, initial_weights: np.ndarray, initial_bias: float, learning_rate: float, epochs: int) -> (np.ndarray, float, list[float]): - # Your code here - return updated_weights, updated_bias, mse_values + + +def train_neuron( + features: np.ndarray, + labels: np.ndarray, + initial_weights: np.ndarray, + initial_bias: float, + learning_rate: float, + epochs: int, +) -> (np.ndarray, float, list[float]): + # Your code here + return updated_weights, updated_bias, mse_values diff --git a/questions/25_single-neuron-with-backpropagation/tinygrad/solution.py b/questions/25_single-neuron-with-backpropagation/tinygrad/solution.py index 7ec48fff..507a904c 100644 --- a/questions/25_single-neuron-with-backpropagation/tinygrad/solution.py +++ b/questions/25_single-neuron-with-backpropagation/tinygrad/solution.py @@ -4,11 +4,11 @@ def train_neuron_tg( features: List[List[float]], - labels: List[float], + labels: List[float], initial_weights: List[float], initial_bias: float, learning_rate: float, - epochs: int + epochs: int, ) -> Tuple[List[float], float, List[float]]: X = Tensor(features) y = Tensor(labels).reshape(len(labels), 1) @@ -19,9 +19,9 @@ def train_neuron_tg( n = len(labels) for _ in range(epochs): - z = X.matmul(w) + b # (n,1) - preds = z.sigmoid() # (n,1) - errors = preds - y # (n,1) + z = X.matmul(w) + b # (n,1) + preds = z.sigmoid() # (n,1) + errors = preds - y # (n,1) mse = float(((errors**2).mean()).numpy()) mse_values.append(round(mse, 4)) @@ -36,5 +36,5 @@ def train_neuron_tg( b -= Tensor(learning_rate) * grad_b updated_weights = [round(val, 4) for val in w.numpy().flatten().tolist()] - updated_bias = round(float(b.numpy()), 4) + updated_bias = round(float(b.numpy()), 4) return updated_weights, updated_bias, mse_values diff --git a/questions/25_single-neuron-with-backpropagation/tinygrad/starter_code.py b/questions/25_single-neuron-with-backpropagation/tinygrad/starter_code.py index 53b1796c..f04cb5df 100644 --- a/questions/25_single-neuron-with-backpropagation/tinygrad/starter_code.py +++ b/questions/25_single-neuron-with-backpropagation/tinygrad/starter_code.py @@ -1,14 +1,13 @@ -from tinygrad.tensor import Tensor from typing import List, Tuple def train_neuron_tg( features: List[List[float]], - labels: List[float], + labels: List[float], initial_weights: List[float], initial_bias: float, learning_rate: float, - epochs: int + epochs: int, ) -> Tuple[List[float], float, List[float]]: """ Tinygrad version — same contract as PyTorch implementation. diff --git a/questions/26_implementing-basic-autograd-operations/pytorch/solution.py b/questions/26_implementing-basic-autograd-operations/pytorch/solution.py index 6ebd0a1b..991141f2 100644 --- a/questions/26_implementing-basic-autograd-operations/pytorch/solution.py +++ b/questions/26_implementing-basic-autograd-operations/pytorch/solution.py @@ -1,10 +1,15 @@ import torch + class Value: """Scalar autograd value powered by PyTorch tensors.""" def __init__(self, data, _tensor=None): - self._t = _tensor if _tensor is not None else torch.tensor(float(data), requires_grad=True) + self._t = ( + _tensor + if _tensor is not None + else torch.tensor(float(data), requires_grad=True) + ) self._t.retain_grad() # ----- helpers ----- @@ -20,6 +25,7 @@ def grad(self): def __repr__(self): def fmt(x): return int(x) if float(x).is_integer() else round(x, 4) + return f"Value(data={fmt(self.data)}, grad={fmt(self.grad)})" def _wrap(self, other): diff --git a/questions/26_implementing-basic-autograd-operations/pytorch/starter_code.py b/questions/26_implementing-basic-autograd-operations/pytorch/starter_code.py index c98e2a0c..5ece49ff 100644 --- a/questions/26_implementing-basic-autograd-operations/pytorch/starter_code.py +++ b/questions/26_implementing-basic-autograd-operations/pytorch/starter_code.py @@ -1,11 +1,16 @@ import torch + class Value: """A tiny scalar wrapper that delegates all gradient work to PyTorch autograd.""" def __init__(self, data, _tensor=None): # leaf node: create fresh tensor with grad; internal node: reuse tensor - self._t = _tensor if _tensor is not None else torch.tensor(float(data), requires_grad=True) + self._t = ( + _tensor + if _tensor is not None + else torch.tensor(float(data), requires_grad=True) + ) # make sure every Tensor (leaf or not) keeps its grad for printing self._t.retain_grad() @@ -22,6 +27,7 @@ def grad(self): def __repr__(self): def fmt(x): return int(x) if float(x).is_integer() else round(x, 4) + return f"Value(data={fmt(self.data)}, grad={fmt(self.grad)})" # ensure rhs is Value diff --git a/questions/26_implementing-basic-autograd-operations/solution.py b/questions/26_implementing-basic-autograd-operations/solution.py index fe158bef..61aab2ff 100644 --- a/questions/26_implementing-basic-autograd-operations/solution.py +++ b/questions/26_implementing-basic-autograd-operations/solution.py @@ -1,6 +1,5 @@ - class Value: - def __init__(self, data, _children=(), _op=''): + def __init__(self, data, _children=(), _op=""): self.data = data self.grad = 0 self._backward = lambda: None @@ -9,41 +8,50 @@ def __init__(self, data, _children=(), _op=''): def __add__(self, other): other = other if isinstance(other, Value) else Value(other) - out = Value(self.data + other.data, (self, other), '+') + out = Value(self.data + other.data, (self, other), "+") + def _backward(): self.grad += out.grad other.grad += out.grad + out._backward = _backward return out def __mul__(self, other): other = other if isinstance(other, Value) else Value(other) - out = Value(self.data * other.data, (self, other), '*') + out = Value(self.data * other.data, (self, other), "*") + def _backward(): self.grad += other.data * out.grad other.grad += self.data * out.grad + out._backward = _backward return out def relu(self): - out = Value(0 if self.data < 0 else self.data, (self,), 'ReLU') + out = Value(0 if self.data < 0 else self.data, (self,), "ReLU") + def _backward(): self.grad += (out.data > 0) * out.grad + out._backward = _backward return out def backward(self): topo = [] visited = set() + def build_topo(v): if v not in visited: visited.add(v) for child in v._prev: build_topo(child) topo.append(v) + build_topo(self) self.grad = 1 for v in reversed(topo): v._backward() + def __repr__(self): return f"Value(data={self.data}, grad={self.grad})" diff --git a/questions/26_implementing-basic-autograd-operations/starter_code.py b/questions/26_implementing-basic-autograd-operations/starter_code.py index 5c002e14..8e844a11 100644 --- a/questions/26_implementing-basic-autograd-operations/starter_code.py +++ b/questions/26_implementing-basic-autograd-operations/starter_code.py @@ -1,25 +1,26 @@ class Value: - def __init__(self, data, _children=(), _op=''): - self.data = data - self.grad = 0 - self._backward = lambda: None - self._prev = set(_children) - self._op = _op - def __repr__(self): - return f"Value(data={self.data}, grad={self.grad})" + def __init__(self, data, _children=(), _op=""): + self.data = data + self.grad = 0 + self._backward = lambda: None + self._prev = set(_children) + self._op = _op - def __add__(self, other): - # Implement addition here - pass + def __repr__(self): + return f"Value(data={self.data}, grad={self.grad})" - def __mul__(self, other): - # Implement multiplication here - pass + def __add__(self, other): + # Implement addition here + pass - def relu(self): - # Implement ReLU here - pass + def __mul__(self, other): + # Implement multiplication here + pass - def backward(self): - # Implement backward pass here - pass + def relu(self): + # Implement ReLU here + pass + + def backward(self): + # Implement backward pass here + pass diff --git a/questions/26_implementing-basic-autograd-operations/tinygrad/solution.py b/questions/26_implementing-basic-autograd-operations/tinygrad/solution.py index 2ecbecc3..322d305f 100644 --- a/questions/26_implementing-basic-autograd-operations/tinygrad/solution.py +++ b/questions/26_implementing-basic-autograd-operations/tinygrad/solution.py @@ -1,8 +1,11 @@ from tinygrad.tensor import Tensor + class Value: def __init__(self, data, _tensor=None): - self._t = _tensor if _tensor is not None else Tensor(float(data), requires_grad=True) + self._t = ( + _tensor if _tensor is not None else Tensor(float(data), requires_grad=True) + ) @property def data(self): @@ -16,6 +19,7 @@ def grad(self): def __repr__(self): def fmt(x): return int(x) if float(x).is_integer() else round(x, 4) + return f"Value(data={fmt(self.data)}, grad={fmt(self.grad)})" def _wrap(self, other): diff --git a/questions/26_implementing-basic-autograd-operations/tinygrad/starter_code.py b/questions/26_implementing-basic-autograd-operations/tinygrad/starter_code.py index e5b75577..97d5b3d7 100644 --- a/questions/26_implementing-basic-autograd-operations/tinygrad/starter_code.py +++ b/questions/26_implementing-basic-autograd-operations/tinygrad/starter_code.py @@ -1,10 +1,13 @@ from tinygrad.tensor import Tensor + class Value: """Same idea, but using tinygrad’s automatic differentiation.""" def __init__(self, data, _tensor=None): - self._t = _tensor if _tensor is not None else Tensor(float(data), requires_grad=True) + self._t = ( + _tensor if _tensor is not None else Tensor(float(data), requires_grad=True) + ) @property def data(self): @@ -18,6 +21,7 @@ def grad(self): def __repr__(self): def fmt(x): return int(x) if float(x).is_integer() else round(x, 4) + return f"Value(data={fmt(self.data)}, grad={fmt(self.grad)})" def _wrap(self, other): diff --git a/questions/27_transformation-matrix-from-basis-b-to-c/solution.py b/questions/27_transformation-matrix-from-basis-b-to-c/solution.py index 3ed4fc56..b7ebe3c9 100644 --- a/questions/27_transformation-matrix-from-basis-b-to-c/solution.py +++ b/questions/27_transformation-matrix-from-basis-b-to-c/solution.py @@ -1,4 +1,6 @@ import numpy as np + + def transform_basis(B, C): C = np.array(C) B = np.array(B) diff --git a/questions/27_transformation-matrix-from-basis-b-to-c/starter_code.py b/questions/27_transformation-matrix-from-basis-b-to-c/starter_code.py index fbca1c18..c51008d4 100644 --- a/questions/27_transformation-matrix-from-basis-b-to-c/starter_code.py +++ b/questions/27_transformation-matrix-from-basis-b-to-c/starter_code.py @@ -1,2 +1,2 @@ def transform_basis(B: list[list[int]], C: list[list[int]]) -> list[list[float]]: - return P + return P diff --git a/questions/28_svd-of-a-2x2-matrix-using-eigen-values-vectors/solution.py b/questions/28_svd-of-a-2x2-matrix-using-eigen-values-vectors/solution.py index afc802ae..c1114c66 100644 --- a/questions/28_svd-of-a-2x2-matrix-using-eigen-values-vectors/solution.py +++ b/questions/28_svd-of-a-2x2-matrix-using-eigen-values-vectors/solution.py @@ -1,5 +1,6 @@ import numpy as np + def svd_2x2(A: np.ndarray) -> tuple: y1, x1 = (A[1, 0] + A[0, 1]), (A[0, 0] - A[1, 1]) y2, x2 = (A[1, 0] - A[0, 1]), (A[0, 0] + A[1, 1]) @@ -23,4 +24,3 @@ def svd_2x2(A: np.ndarray) -> tuple: V = np.diag(1.0 / s) @ U.T @ A return U, s, V - diff --git a/questions/28_svd-of-a-2x2-matrix-using-eigen-values-vectors/starter_code.py b/questions/28_svd-of-a-2x2-matrix-using-eigen-values-vectors/starter_code.py index cc445909..84995f6d 100644 --- a/questions/28_svd-of-a-2x2-matrix-using-eigen-values-vectors/starter_code.py +++ b/questions/28_svd-of-a-2x2-matrix-using-eigen-values-vectors/starter_code.py @@ -1,5 +1,6 @@ import numpy as np + def svd_2x2(A: np.ndarray) -> tuple: - # Your code here - pass + # Your code here + pass diff --git a/questions/29_random-shuffle-of-dataset/solution.py b/questions/29_random-shuffle-of-dataset/solution.py index f9b91d92..c88a1c5e 100644 --- a/questions/29_random-shuffle-of-dataset/solution.py +++ b/questions/29_random-shuffle-of-dataset/solution.py @@ -1,9 +1,9 @@ import numpy as np + def shuffle_data(X, y, seed=None): if seed: np.random.seed(seed) idx = np.arange(X.shape[0]) np.random.shuffle(idx) return X[idx], y[idx] - diff --git a/questions/29_random-shuffle-of-dataset/starter_code.py b/questions/29_random-shuffle-of-dataset/starter_code.py index ca6942c5..aab13a2d 100644 --- a/questions/29_random-shuffle-of-dataset/starter_code.py +++ b/questions/29_random-shuffle-of-dataset/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def shuffle_data(X, y, seed=None): - # Your code here - pass + # Your code here + pass diff --git a/questions/2_transpose-of-a-matrix/pytorch/solution.py b/questions/2_transpose-of-a-matrix/pytorch/solution.py index 34643c08..287953f8 100644 --- a/questions/2_transpose-of-a-matrix/pytorch/solution.py +++ b/questions/2_transpose-of-a-matrix/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def transpose_matrix(a) -> torch.Tensor: """ Transpose a 2D matrix `a` using PyTorch. diff --git a/questions/2_transpose-of-a-matrix/pytorch/starter_code.py b/questions/2_transpose-of-a-matrix/pytorch/starter_code.py index 1c648f73..3b4326d0 100644 --- a/questions/2_transpose-of-a-matrix/pytorch/starter_code.py +++ b/questions/2_transpose-of-a-matrix/pytorch/starter_code.py @@ -1,11 +1,12 @@ import torch + def transpose_matrix(a) -> torch.Tensor: """ Transpose a 2D matrix `a` using PyTorch. Inputs can be Python lists, NumPy arrays, or torch Tensors. Returns a transposed tensor. """ - a_t = torch.as_tensor(a) + torch.as_tensor(a) # Your implementation here pass diff --git a/questions/2_transpose-of-a-matrix/solution.py b/questions/2_transpose-of-a-matrix/solution.py index 10158c7e..51092ddb 100644 --- a/questions/2_transpose-of-a-matrix/solution.py +++ b/questions/2_transpose-of-a-matrix/solution.py @@ -1,2 +1,2 @@ -def transpose_matrix(a: list[list[int|float]]) -> list[list[int|float]]: +def transpose_matrix(a: list[list[int | float]]) -> list[list[int | float]]: return [list(i) for i in zip(*a)] diff --git a/questions/2_transpose-of-a-matrix/starter_code.py b/questions/2_transpose-of-a-matrix/starter_code.py index a247d5ba..24aa0400 100644 --- a/questions/2_transpose-of-a-matrix/starter_code.py +++ b/questions/2_transpose-of-a-matrix/starter_code.py @@ -1,2 +1,2 @@ -def transpose_matrix(a: list[list[int|float]]) -> list[list[int|float]]: - return b +def transpose_matrix(a: list[list[int | float]]) -> list[list[int | float]]: + return b diff --git a/questions/2_transpose-of-a-matrix/tinygrad/solution.py b/questions/2_transpose-of-a-matrix/tinygrad/solution.py index 52be5f2d..07f3115d 100644 --- a/questions/2_transpose-of-a-matrix/tinygrad/solution.py +++ b/questions/2_transpose-of-a-matrix/tinygrad/solution.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def transpose_matrix_tg(a) -> Tensor: """ Transpose a 2D matrix `a` using tinygrad. diff --git a/questions/30_batch-iterator-for-dataset/solution.py b/questions/30_batch-iterator-for-dataset/solution.py index b4dee373..37355502 100644 --- a/questions/30_batch-iterator-for-dataset/solution.py +++ b/questions/30_batch-iterator-for-dataset/solution.py @@ -1,13 +1,13 @@ import numpy as np + def batch_iterator(X, y=None, batch_size=64): n_samples = X.shape[0] batches = [] for i in np.arange(0, n_samples, batch_size): - begin, end = i, min(i+batch_size, n_samples) + begin, end = i, min(i + batch_size, n_samples) if y is not None: batches.append([X[begin:end], y[begin:end]]) else: - batches.append( X[begin:end]) + batches.append(X[begin:end]) return batches - diff --git a/questions/30_batch-iterator-for-dataset/starter_code.py b/questions/30_batch-iterator-for-dataset/starter_code.py index 68d236ca..447bed19 100644 --- a/questions/30_batch-iterator-for-dataset/starter_code.py +++ b/questions/30_batch-iterator-for-dataset/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def batch_iterator(X, y=None, batch_size=64): - # Your code here - pass + # Your code here + pass diff --git a/questions/31_divide-dataset-based-on-feature-threshold/solution.py b/questions/31_divide-dataset-based-on-feature-threshold/solution.py index 458a2c4f..28f3ec0b 100644 --- a/questions/31_divide-dataset-based-on-feature-threshold/solution.py +++ b/questions/31_divide-dataset-based-on-feature-threshold/solution.py @@ -1,14 +1,17 @@ import numpy as np + def divide_on_feature(X, feature_i, threshold): # Define the split function based on the threshold type split_func = None if isinstance(threshold, int) or isinstance(threshold, float): # For numeric threshold, check if feature value is greater than or equal to the threshold - split_func = lambda sample: sample[feature_i] >= threshold + def split_func(sample): + return sample[feature_i] >= threshold else: # For non-numeric threshold, check if feature value is equal to the threshold - split_func = lambda sample: sample[feature_i] == threshold + def split_func(sample): + return sample[feature_i] == threshold # Create two subsets based on the split function X_1 = np.array([sample for sample in X if split_func(sample)]) @@ -16,4 +19,3 @@ def divide_on_feature(X, feature_i, threshold): # Return the two subsets return [X_1, X_2] - diff --git a/questions/31_divide-dataset-based-on-feature-threshold/starter_code.py b/questions/31_divide-dataset-based-on-feature-threshold/starter_code.py index d7118c47..0f8c7485 100644 --- a/questions/31_divide-dataset-based-on-feature-threshold/starter_code.py +++ b/questions/31_divide-dataset-based-on-feature-threshold/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def divide_on_feature(X, feature_i, threshold): - # Your code here - pass + # Your code here + pass diff --git a/questions/32_generate-sorted-polynomial-features/solution.py b/questions/32_generate-sorted-polynomial-features/solution.py index 66551401..eae33931 100644 --- a/questions/32_generate-sorted-polynomial-features/solution.py +++ b/questions/32_generate-sorted-polynomial-features/solution.py @@ -1,12 +1,16 @@ import numpy as np from itertools import combinations_with_replacement + def polynomial_features(X, degree): n_samples, n_features = X.shape # All index combinations for powers 0 … degree (constant term included) - combs = [c for d in range(degree + 1) - for c in combinations_with_replacement(range(n_features), d)] + combs = [ + c + for d in range(degree + 1) + for c in combinations_with_replacement(range(n_features), d) + ] # Compute raw polynomial terms X_poly = np.empty((n_samples, len(combs))) diff --git a/questions/32_generate-sorted-polynomial-features/starter_code.py b/questions/32_generate-sorted-polynomial-features/starter_code.py index 41a4c312..a4845a49 100644 --- a/questions/32_generate-sorted-polynomial-features/starter_code.py +++ b/questions/32_generate-sorted-polynomial-features/starter_code.py @@ -1,6 +1,3 @@ -import numpy as np -from itertools import combinations_with_replacement - def polynomial_features(X, degree): # ✏️ Your code here pass diff --git a/questions/33_generate-random-subsets-of-a-dataset/solution.py b/questions/33_generate-random-subsets-of-a-dataset/solution.py index 73a80d2e..850c15de 100644 --- a/questions/33_generate-random-subsets-of-a-dataset/solution.py +++ b/questions/33_generate-random-subsets-of-a-dataset/solution.py @@ -1,12 +1,17 @@ import numpy as np + def get_random_subsets(X, y, n_subsets, replacements=True, seed=42): np.random.seed(seed) n, m = X.shape - + subset_size = n if replacements else n // 2 - idx = np.array([np.random.choice(n, subset_size, replace=replacements) for _ in range(n_subsets)]) + idx = np.array( + [ + np.random.choice(n, subset_size, replace=replacements) + for _ in range(n_subsets) + ] + ) # convert all ndarrays to lists return [(X[idx][i].tolist(), y[idx][i].tolist()) for i in range(n_subsets)] - diff --git a/questions/33_generate-random-subsets-of-a-dataset/starter_code.py b/questions/33_generate-random-subsets-of-a-dataset/starter_code.py index fa59e9f1..015e28ce 100644 --- a/questions/33_generate-random-subsets-of-a-dataset/starter_code.py +++ b/questions/33_generate-random-subsets-of-a-dataset/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def get_random_subsets(X, y, n_subsets, replacements=True, seed=42): - # Your code here - pass + # Your code here + pass diff --git a/questions/34_one-hot-encoding-of-nominal-values/solution.py b/questions/34_one-hot-encoding-of-nominal-values/solution.py index 7fbb679d..828cac34 100644 --- a/questions/34_one-hot-encoding-of-nominal-values/solution.py +++ b/questions/34_one-hot-encoding-of-nominal-values/solution.py @@ -1,5 +1,6 @@ import numpy as np + def to_categorical(x, n_col=None): # One-hot encoding of nominal values # If n_col is not provided, determine the number of columns from the input array @@ -10,4 +11,3 @@ def to_categorical(x, n_col=None): # Set the appropriate elements to 1 one_hot[np.arange(x.shape[0]), x] = 1 return one_hot - diff --git a/questions/34_one-hot-encoding-of-nominal-values/starter_code.py b/questions/34_one-hot-encoding-of-nominal-values/starter_code.py index f510543c..92b93e5a 100644 --- a/questions/34_one-hot-encoding-of-nominal-values/starter_code.py +++ b/questions/34_one-hot-encoding-of-nominal-values/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def to_categorical(x, n_col=None): - # Your code here - pass + # Your code here + pass diff --git a/questions/35_convert-vector-to-diagonal-matrix/solution.py b/questions/35_convert-vector-to-diagonal-matrix/solution.py index 6d70ed68..d6ab720a 100644 --- a/questions/35_convert-vector-to-diagonal-matrix/solution.py +++ b/questions/35_convert-vector-to-diagonal-matrix/solution.py @@ -1,6 +1,6 @@ import numpy as np + def make_diagonal(x): identity_matrix = np.identity(np.size(x)) - return (identity_matrix*x) - + return identity_matrix * x diff --git a/questions/35_convert-vector-to-diagonal-matrix/starter_code.py b/questions/35_convert-vector-to-diagonal-matrix/starter_code.py index 2d840a10..436e1382 100644 --- a/questions/35_convert-vector-to-diagonal-matrix/starter_code.py +++ b/questions/35_convert-vector-to-diagonal-matrix/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def make_diagonal(x): - # Your code here - pass + # Your code here + pass diff --git a/questions/36_calculate-accuracy-score/solution.py b/questions/36_calculate-accuracy-score/solution.py index 590b51e5..24ec0344 100644 --- a/questions/36_calculate-accuracy-score/solution.py +++ b/questions/36_calculate-accuracy-score/solution.py @@ -1,6 +1,6 @@ import numpy as np + def accuracy_score(y_true, y_pred): accuracy = np.sum(y_true == y_pred, axis=0) / len(y_true) return accuracy - diff --git a/questions/36_calculate-accuracy-score/starter_code.py b/questions/36_calculate-accuracy-score/starter_code.py index e34f69e4..7a2dbfb3 100644 --- a/questions/36_calculate-accuracy-score/starter_code.py +++ b/questions/36_calculate-accuracy-score/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def accuracy_score(y_true, y_pred): - # Your code here - pass + # Your code here + pass diff --git a/questions/37_calculate-correlation-matrix/solution.py b/questions/37_calculate-correlation-matrix/solution.py index 60334207..6b9784e0 100644 --- a/questions/37_calculate-correlation-matrix/solution.py +++ b/questions/37_calculate-correlation-matrix/solution.py @@ -1,10 +1,11 @@ import numpy as np + def calculate_correlation_matrix(X, Y=None): # Helper function to calculate standard deviation def calculate_std_dev(A): - return np.sqrt(np.mean((A - A.mean(0))**2, axis=0)) - + return np.sqrt(np.mean((A - A.mean(0)) ** 2, axis=0)) + if Y is None: Y = X n_samples = np.shape(X)[0] @@ -17,4 +18,3 @@ def calculate_std_dev(A): correlation_matrix = np.divide(covariance, std_dev_X.dot(std_dev_y.T)) return np.array(correlation_matrix, dtype=float) - diff --git a/questions/37_calculate-correlation-matrix/starter_code.py b/questions/37_calculate-correlation-matrix/starter_code.py index 3629df50..372b3084 100644 --- a/questions/37_calculate-correlation-matrix/starter_code.py +++ b/questions/37_calculate-correlation-matrix/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def calculate_correlation_matrix(X, Y=None): - # Your code here - pass + # Your code here + pass diff --git a/questions/38_implement-adaboost-fit-method/solution.py b/questions/38_implement-adaboost-fit-method/solution.py index 763a9b25..0c94ddcb 100644 --- a/questions/38_implement-adaboost-fit-method/solution.py +++ b/questions/38_implement-adaboost-fit-method/solution.py @@ -1,41 +1,43 @@ import math import numpy as np + + def adaboost_fit(X, y, n_clf): n_samples, n_features = np.shape(X) w = np.full(n_samples, (1 / n_samples)) clfs = [] - + for _ in range(n_clf): clf = {} - min_error = float('inf') - + min_error = float("inf") + for feature_i in range(n_features): feature_values = np.expand_dims(X[:, feature_i], axis=1) unique_values = np.unique(feature_values) - + for threshold in unique_values: p = 1 prediction = np.ones(np.shape(y)) prediction[X[:, feature_i] < threshold] = -1 error = sum(w[y != prediction]) - + if error > 0.5: error = 1 - error p = -1 - + if error < min_error: - clf['polarity'] = p - clf['threshold'] = threshold - clf['feature_index'] = feature_i + clf["polarity"] = p + clf["threshold"] = threshold + clf["feature_index"] = feature_i min_error = error - - clf['alpha'] = 0.5 * math.log((1.0 - min_error) / (min_error + 1e-10)) + + clf["alpha"] = 0.5 * math.log((1.0 - min_error) / (min_error + 1e-10)) predictions = np.ones(np.shape(y)) - negative_idx = (X[:, clf['feature_index']] < clf['threshold']) - if clf['polarity'] == -1: + negative_idx = X[:, clf["feature_index"]] < clf["threshold"] + if clf["polarity"] == -1: negative_idx = np.logical_not(negative_idx) predictions[negative_idx] = -1 - w *= np.exp(-clf['alpha'] * y * predictions) + w *= np.exp(-clf["alpha"] * y * predictions) w /= np.sum(w) clfs.append(clf) diff --git a/questions/38_implement-adaboost-fit-method/starter_code.py b/questions/38_implement-adaboost-fit-method/starter_code.py index c64371c7..d704d049 100644 --- a/questions/38_implement-adaboost-fit-method/starter_code.py +++ b/questions/38_implement-adaboost-fit-method/starter_code.py @@ -1,12 +1,11 @@ import numpy as np -import math + def adaboost_fit(X, y, n_clf): - n_samples, n_features = np.shape(X) - w = np.full(n_samples, (1 / n_samples)) - clfs = [] + n_samples, n_features = np.shape(X) + np.full(n_samples, (1 / n_samples)) + clfs = [] - # Your code here + # Your code here - return clfs - + return clfs diff --git a/questions/39_implementation-of-log-softmax-function/solution.py b/questions/39_implementation-of-log-softmax-function/solution.py index 27a508f2..7c456109 100644 --- a/questions/39_implementation-of-log-softmax-function/solution.py +++ b/questions/39_implementation-of-log-softmax-function/solution.py @@ -1,5 +1,6 @@ import numpy as np + def log_softmax(scores: list) -> np.ndarray: # Subtract the maximum value for numerical stability scores = scores - np.max(scores) diff --git a/questions/39_implementation-of-log-softmax-function/starter_code.py b/questions/39_implementation-of-log-softmax-function/starter_code.py index f1cd1bd9..866beafb 100644 --- a/questions/39_implementation-of-log-softmax-function/starter_code.py +++ b/questions/39_implementation-of-log-softmax-function/starter_code.py @@ -1,5 +1,6 @@ import numpy as np + def log_softmax(scores: list) -> np.ndarray: - # Your code here - pass + # Your code here + pass diff --git a/questions/3_reshape-matrix/pytorch/solution.py b/questions/3_reshape-matrix/pytorch/solution.py index 9f453142..70c5719d 100644 --- a/questions/3_reshape-matrix/pytorch/solution.py +++ b/questions/3_reshape-matrix/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def reshape_matrix(a, new_shape) -> torch.Tensor: """ Reshape a 2D matrix `a` to shape `new_shape` using PyTorch. diff --git a/questions/3_reshape-matrix/pytorch/starter_code.py b/questions/3_reshape-matrix/pytorch/starter_code.py index 59f70dda..d684a6b1 100644 --- a/questions/3_reshape-matrix/pytorch/starter_code.py +++ b/questions/3_reshape-matrix/pytorch/starter_code.py @@ -1,5 +1,6 @@ import torch + def reshape_matrix(a, new_shape) -> torch.Tensor: """ Reshape a 2D matrix `a` to shape `new_shape` using PyTorch. @@ -10,6 +11,6 @@ def reshape_matrix(a, new_shape) -> torch.Tensor: if len(a) * len(a[0]) != new_shape[0] * new_shape[1]: return torch.tensor([]) # Convert to tensor and reshape - a_t = torch.as_tensor(a, dtype=torch.float) + torch.as_tensor(a, dtype=torch.float) # Your implementation here pass diff --git a/questions/3_reshape-matrix/solution.py b/questions/3_reshape-matrix/solution.py index bca93b75..0192eaf1 100644 --- a/questions/3_reshape-matrix/solution.py +++ b/questions/3_reshape-matrix/solution.py @@ -1,7 +1,10 @@ import numpy as np -def reshape_matrix(a: list[list[int|float]], new_shape: tuple[int|float]) -> list[list[int|float]]: + +def reshape_matrix( + a: list[list[int | float]], new_shape: tuple[int | float] +) -> list[list[int | float]]: # Not compatible case - if len(a)*len(a[0]) != new_shape[0]*new_shape[1]: + if len(a) * len(a[0]) != new_shape[0] * new_shape[1]: return [] return np.array(a).reshape(new_shape).tolist() diff --git a/questions/3_reshape-matrix/starter_code.py b/questions/3_reshape-matrix/starter_code.py index e4c8e214..91ea2426 100644 --- a/questions/3_reshape-matrix/starter_code.py +++ b/questions/3_reshape-matrix/starter_code.py @@ -1,5 +1,5 @@ -import numpy as np - -def reshape_matrix(a: list[list[int|float]], new_shape: tuple[int, int]) -> list[list[int|float]]: - #Write your code here and return a python list after reshaping by using numpy's tolist() method - return reshaped_matrix +def reshape_matrix( + a: list[list[int | float]], new_shape: tuple[int, int] +) -> list[list[int | float]]: + # Write your code here and return a python list after reshaping by using numpy's tolist() method + return reshaped_matrix diff --git a/questions/3_reshape-matrix/tinygrad/solution.py b/questions/3_reshape-matrix/tinygrad/solution.py index 67e4cad9..22c87152 100644 --- a/questions/3_reshape-matrix/tinygrad/solution.py +++ b/questions/3_reshape-matrix/tinygrad/solution.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def reshape_matrix_tg(a, new_shape) -> Tensor: """ Reshape a 2D matrix `a` to shape `new_shape` using tinygrad. diff --git a/questions/40_implementing-a-custom-dense-layer-in-python/solution.py b/questions/40_implementing-a-custom-dense-layer-in-python/solution.py index deb07195..bf730f01 100644 --- a/questions/40_implementing-a-custom-dense-layer-in-python/solution.py +++ b/questions/40_implementing-a-custom-dense-layer-in-python/solution.py @@ -1,4 +1,3 @@ - class Dense(Layer): def __init__(self, n_units, input_shape=None): self.layer_input = None @@ -10,9 +9,9 @@ def __init__(self, n_units, input_shape=None): def initialize(self, optimizer): limit = 1 / math.sqrt(self.input_shape[0]) - self.W = np.random.uniform(-limit, limit, (self.input_shape[0], self.n_units)) + self.W = np.random.uniform(-limit, limit, (self.input_shape[0], self.n_units)) self.w0 = np.zeros((1, self.n_units)) - self.W_opt = copy.copy(optimizer) + self.W_opt = copy.copy(optimizer) self.w0_opt = copy.copy(optimizer) def parameters(self): @@ -33,5 +32,4 @@ def backward_pass(self, accum_grad): return accum_grad def output_shape(self): - return (self.n_units, ) - + return (self.n_units,) diff --git a/questions/40_implementing-a-custom-dense-layer-in-python/starter_code.py b/questions/40_implementing-a-custom-dense-layer-in-python/starter_code.py index 10d711c0..dfe53523 100644 --- a/questions/40_implementing-a-custom-dense-layer-in-python/starter_code.py +++ b/questions/40_implementing-a-custom-dense-layer-in-python/starter_code.py @@ -1,4 +1,3 @@ - import numpy as np import copy import math @@ -38,13 +37,16 @@ def __init__(self, n_units, input_shape=None): self.W = None self.w0 = None - def forward_pass(): + def forward_pass(self): + # Your code here + pass def backward_pass(self, accum_grad): + # Your code here + pass - def number_of_parameters(): - - - + def number_of_parameters(self): + # Your code here + pass diff --git a/questions/41_simple-convolutional-2d-layer/solution.py b/questions/41_simple-convolutional-2d-layer/solution.py index 0eb1a9d0..53cde2b8 100644 --- a/questions/41_simple-convolutional-2d-layer/solution.py +++ b/questions/41_simple-convolutional-2d-layer/solution.py @@ -1,10 +1,15 @@ import numpy as np -def simple_conv2d(input_matrix: np.ndarray, kernel: np.ndarray, padding: int, stride: int): + +def simple_conv2d( + input_matrix: np.ndarray, kernel: np.ndarray, padding: int, stride: int +): input_height, input_width = input_matrix.shape kernel_height, kernel_width = kernel.shape - padded_input = np.pad(input_matrix, ((padding, padding), (padding, padding)), mode='constant') + padded_input = np.pad( + input_matrix, ((padding, padding), (padding, padding)), mode="constant" + ) input_height_padded, input_width_padded = padded_input.shape output_height = (input_height_padded - kernel_height) // stride + 1 @@ -14,7 +19,10 @@ def simple_conv2d(input_matrix: np.ndarray, kernel: np.ndarray, padding: int, st for i in range(output_height): for j in range(output_width): - region = padded_input[i*stride:i*stride + kernel_height, j*stride:j*stride + kernel_width] + region = padded_input[ + i * stride : i * stride + kernel_height, + j * stride : j * stride + kernel_width, + ] output_matrix[i, j] = np.sum(region * kernel) return output_matrix diff --git a/questions/41_simple-convolutional-2d-layer/starter_code.py b/questions/41_simple-convolutional-2d-layer/starter_code.py index ce0d3708..e747b6ce 100644 --- a/questions/41_simple-convolutional-2d-layer/starter_code.py +++ b/questions/41_simple-convolutional-2d-layer/starter_code.py @@ -1,9 +1,12 @@ import numpy as np -def simple_conv2d(input_matrix: np.ndarray, kernel: np.ndarray, padding: int, stride: int): - input_height, input_width = input_matrix.shape - kernel_height, kernel_width = kernel.shape - # Your code here - - return output_matrix +def simple_conv2d( + input_matrix: np.ndarray, kernel: np.ndarray, padding: int, stride: int +): + input_height, input_width = input_matrix.shape + kernel_height, kernel_width = kernel.shape + + # Your code here + + return output_matrix diff --git a/questions/42_implement-relu-activation-function/starter_code.py b/questions/42_implement-relu-activation-function/starter_code.py index 7f8448a5..3e408399 100644 --- a/questions/42_implement-relu-activation-function/starter_code.py +++ b/questions/42_implement-relu-activation-function/starter_code.py @@ -1,3 +1,3 @@ def relu(z: float) -> float: - # Your code here - pass + # Your code here + pass diff --git a/questions/43_implement-ridge-regression-loss-function/solution.py b/questions/43_implement-ridge-regression-loss-function/solution.py index d11dd544..801bfa86 100644 --- a/questions/43_implement-ridge-regression-loss-function/solution.py +++ b/questions/43_implement-ridge-regression-loss-function/solution.py @@ -1,5 +1,6 @@ import numpy as np + def ridge_loss(X: np.ndarray, w: np.ndarray, y_true: np.ndarray, alpha: float) -> float: - loss = np.mean((y_true - X @ w)**2) + alpha * np.sum(w**2) + loss = np.mean((y_true - X @ w) ** 2) + alpha * np.sum(w**2) return loss diff --git a/questions/43_implement-ridge-regression-loss-function/starter_code.py b/questions/43_implement-ridge-regression-loss-function/starter_code.py index 3322d600..c741737e 100644 --- a/questions/43_implement-ridge-regression-loss-function/starter_code.py +++ b/questions/43_implement-ridge-regression-loss-function/starter_code.py @@ -1,5 +1,6 @@ import numpy as np + def ridge_loss(X: np.ndarray, w: np.ndarray, y_true: np.ndarray, alpha: float) -> float: - # Your code here - pass + # Your code here + pass diff --git a/questions/44_leaky-relu-activation-function/solution.py b/questions/44_leaky-relu-activation-function/solution.py index 64be7210..0c3c77d5 100644 --- a/questions/44_leaky-relu-activation-function/solution.py +++ b/questions/44_leaky-relu-activation-function/solution.py @@ -1,2 +1,2 @@ -def leaky_relu(z: float, alpha: float = 0.01) -> float|int: +def leaky_relu(z: float, alpha: float = 0.01) -> float | int: return z if z > 0 else alpha * z diff --git a/questions/44_leaky-relu-activation-function/starter_code.py b/questions/44_leaky-relu-activation-function/starter_code.py index bb2327fe..7620badd 100644 --- a/questions/44_leaky-relu-activation-function/starter_code.py +++ b/questions/44_leaky-relu-activation-function/starter_code.py @@ -1,3 +1,3 @@ -def leaky_relu(z: float, alpha: float = 0.01) -> float|int: - # Your code here - pass +def leaky_relu(z: float, alpha: float = 0.01) -> float | int: + # Your code here + pass diff --git a/questions/45_linear-kernel-function/solution.py b/questions/45_linear-kernel-function/solution.py index 488266c9..56d72d10 100644 --- a/questions/45_linear-kernel-function/solution.py +++ b/questions/45_linear-kernel-function/solution.py @@ -1,4 +1,5 @@ import numpy as np + def kernel_function(x1, x2): return np.inner(x1, x2) diff --git a/questions/45_linear-kernel-function/starter_code.py b/questions/45_linear-kernel-function/starter_code.py index 9a45be24..b420a29e 100644 --- a/questions/45_linear-kernel-function/starter_code.py +++ b/questions/45_linear-kernel-function/starter_code.py @@ -1,5 +1,3 @@ -import numpy as np - def kernel_function(x1, x2): - # Your code here - pass + # Your code here + pass diff --git a/questions/46_implement-precision-metric/solution.py b/questions/46_implement-precision-metric/solution.py index 92fb27ee..1ddaf22b 100644 --- a/questions/46_implement-precision-metric/solution.py +++ b/questions/46_implement-precision-metric/solution.py @@ -1,6 +1,11 @@ import numpy as np + def precision(y_true, y_pred): true_positives = np.sum((y_true == 1) & (y_pred == 1)) false_positives = np.sum((y_true == 0) & (y_pred == 1)) - return true_positives / (true_positives + false_positives) if (true_positives + false_positives) > 0 else 0.0 + return ( + true_positives / (true_positives + false_positives) + if (true_positives + false_positives) > 0 + else 0.0 + ) diff --git a/questions/46_implement-precision-metric/starter_code.py b/questions/46_implement-precision-metric/starter_code.py index 9cedd696..b4931b3b 100644 --- a/questions/46_implement-precision-metric/starter_code.py +++ b/questions/46_implement-precision-metric/starter_code.py @@ -1,4 +1,3 @@ -import numpy as np def precision(y_true, y_pred): - # Your code here - pass + # Your code here + pass diff --git a/questions/47_implement-gradient-descent-variants-with-mse-loss/solution.py b/questions/47_implement-gradient-descent-variants-with-mse-loss/solution.py index fa4579b3..acefcde3 100644 --- a/questions/47_implement-gradient-descent-variants-with-mse-loss/solution.py +++ b/questions/47_implement-gradient-descent-variants-with-mse-loss/solution.py @@ -1,32 +1,32 @@ -import numpy as np - -def gradient_descent(X, y, weights, learning_rate, n_iterations, batch_size=1, method='batch'): +def gradient_descent( + X, y, weights, learning_rate, n_iterations, batch_size=1, method="batch" +): m = len(y) - + for _ in range(n_iterations): - if method == 'batch': + if method == "batch": # Calculate the gradient using all data points predictions = X.dot(weights) errors = predictions - y gradient = 2 * X.T.dot(errors) / m weights = weights - learning_rate * gradient - - elif method == 'stochastic': + + elif method == "stochastic": # Update weights for each data point individually for i in range(m): prediction = X[i].dot(weights) error = prediction - y[i] gradient = 2 * X[i].T.dot(error) weights = weights - learning_rate * gradient - - elif method == 'mini_batch': + + elif method == "mini_batch": # Update weights using sequential batches of data points without shuffling for i in range(0, m, batch_size): - X_batch = X[i:i+batch_size] - y_batch = y[i:i+batch_size] + X_batch = X[i : i + batch_size] + y_batch = y[i : i + batch_size] predictions = X_batch.dot(weights) errors = predictions - y_batch gradient = 2 * X_batch.T.dot(errors) / batch_size weights = weights - learning_rate * gradient - + return weights diff --git a/questions/47_implement-gradient-descent-variants-with-mse-loss/starter_code.py b/questions/47_implement-gradient-descent-variants-with-mse-loss/starter_code.py index 41108c48..91fee248 100644 --- a/questions/47_implement-gradient-descent-variants-with-mse-loss/starter_code.py +++ b/questions/47_implement-gradient-descent-variants-with-mse-loss/starter_code.py @@ -1,5 +1,5 @@ -import numpy as np - -def gradient_descent(X, y, weights, learning_rate, n_iterations, batch_size=1, method='batch'): - # Your code here - pass +def gradient_descent( + X, y, weights, learning_rate, n_iterations, batch_size=1, method="batch" +): + # Your code here + pass diff --git a/questions/48_implement-reduced-row-echelon-form-rref-function/solution.py b/questions/48_implement-reduced-row-echelon-form-rref-function/solution.py index f6c83dd4..0a65cac5 100644 --- a/questions/48_implement-reduced-row-echelon-form-rref-function/solution.py +++ b/questions/48_implement-reduced-row-echelon-form-rref-function/solution.py @@ -1,33 +1,34 @@ import numpy as np + def rref(matrix): # Convert to float for division operations A = matrix.astype(np.float32) n, m = A.shape row = 0 # Current row index for pivot placement - + # Iterate over columns, up to the number of columns m for col in range(m): if row >= n: # No more rows to process break - + # Find a row with a non-zero entry in the current column nonzero_rel_id = np.nonzero(A[row:, col])[0] if len(nonzero_rel_id) == 0: # No pivot in this column continue - + # Swap the current row with the row containing the non-zero entry k = nonzero_rel_id[0] + row A[[row, k]] = A[[k, row]] - + # Normalize the pivot row to make the pivot 1 A[row] = A[row] / A[row, col] - + # Eliminate all other entries in this column for j in range(n): if j != row: A[j] -= A[j, col] * A[row] - + row += 1 # Move to the next row for the next pivot - + return A diff --git a/questions/48_implement-reduced-row-echelon-form-rref-function/starter_code.py b/questions/48_implement-reduced-row-echelon-form-rref-function/starter_code.py index c7869868..f3b68d26 100644 --- a/questions/48_implement-reduced-row-echelon-form-rref-function/starter_code.py +++ b/questions/48_implement-reduced-row-echelon-form-rref-function/starter_code.py @@ -1,5 +1,5 @@ import numpy as np def rref(matrix): - Your code here + #Your code here pass diff --git a/questions/49_implement-adam-optimization-algorithm/solution.py b/questions/49_implement-adam-optimization-algorithm/solution.py index f4651e78..d9c3d80b 100644 --- a/questions/49_implement-adam-optimization-algorithm/solution.py +++ b/questions/49_implement-adam-optimization-algorithm/solution.py @@ -1,6 +1,16 @@ import numpy as np -def adam_optimizer(f, grad, x0, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8, num_iterations=10): + +def adam_optimizer( + f, + grad, + x0, + learning_rate=0.001, + beta1=0.9, + beta2=0.999, + epsilon=1e-8, + num_iterations=10, +): x = x0 m = np.zeros_like(x) v = np.zeros_like(x) diff --git a/questions/49_implement-adam-optimization-algorithm/starter_code.py b/questions/49_implement-adam-optimization-algorithm/starter_code.py index 0ed4610a..f00c2505 100644 --- a/questions/49_implement-adam-optimization-algorithm/starter_code.py +++ b/questions/49_implement-adam-optimization-algorithm/starter_code.py @@ -1,5 +1,12 @@ -import numpy as np - -def adam_optimizer(f, grad, x0, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8, num_iterations=10): - # Your code here - pass +def adam_optimizer( + f, + grad, + x0, + learning_rate=0.001, + beta1=0.9, + beta2=0.999, + epsilon=1e-8, + num_iterations=10, +): + # Your code here + pass diff --git a/questions/4_calculate-mean-by-row-or-column/pytorch/solution.py b/questions/4_calculate-mean-by-row-or-column/pytorch/solution.py index 5501b2e5..50bd374c 100644 --- a/questions/4_calculate-mean-by-row-or-column/pytorch/solution.py +++ b/questions/4_calculate-mean-by-row-or-column/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def calculate_matrix_mean(matrix, mode: str) -> torch.Tensor: """ Calculate mean of a 2D matrix per row or per column using PyTorch. @@ -7,9 +8,9 @@ def calculate_matrix_mean(matrix, mode: str) -> torch.Tensor: Returns a 1-D tensor of means or raises ValueError on invalid mode. """ a_t = torch.as_tensor(matrix, dtype=torch.float) - if mode == 'column': + if mode == "column": return a_t.mean(dim=0) - elif mode == 'row': + elif mode == "row": return a_t.mean(dim=1) else: raise ValueError("Mode must be 'row' or 'column'") diff --git a/questions/4_calculate-mean-by-row-or-column/pytorch/starter_code.py b/questions/4_calculate-mean-by-row-or-column/pytorch/starter_code.py index f30b54e6..8d0e3f38 100644 --- a/questions/4_calculate-mean-by-row-or-column/pytorch/starter_code.py +++ b/questions/4_calculate-mean-by-row-or-column/pytorch/starter_code.py @@ -1,11 +1,12 @@ import torch + def calculate_matrix_mean(matrix, mode: str) -> torch.Tensor: """ Calculate mean of a 2D matrix per row or per column using PyTorch. Inputs can be Python lists, NumPy arrays, or torch Tensors. Returns a 1-D tensor of means or raises ValueError on invalid mode. """ - a_t = torch.as_tensor(matrix, dtype=torch.float) + torch.as_tensor(matrix, dtype=torch.float) # Your implementation here pass diff --git a/questions/4_calculate-mean-by-row-or-column/solution.py b/questions/4_calculate-mean-by-row-or-column/solution.py index 021ca6c2..e2508d3e 100644 --- a/questions/4_calculate-mean-by-row-or-column/solution.py +++ b/questions/4_calculate-mean-by-row-or-column/solution.py @@ -1,7 +1,7 @@ def calculate_matrix_mean(matrix: list[list[float]], mode: str) -> list[float]: - if mode == 'column': + if mode == "column": return [sum(col) / len(matrix) for col in zip(*matrix)] - elif mode == 'row': + elif mode == "row": return [sum(row) / len(row) for row in matrix] else: raise ValueError("Mode must be 'row' or 'column'") diff --git a/questions/4_calculate-mean-by-row-or-column/starter_code.py b/questions/4_calculate-mean-by-row-or-column/starter_code.py index 02ab4a1a..a1553e80 100644 --- a/questions/4_calculate-mean-by-row-or-column/starter_code.py +++ b/questions/4_calculate-mean-by-row-or-column/starter_code.py @@ -1,2 +1,2 @@ def calculate_matrix_mean(matrix: list[list[float]], mode: str) -> list[float]: - return means + return means diff --git a/questions/4_calculate-mean-by-row-or-column/tinygrad/solution.py b/questions/4_calculate-mean-by-row-or-column/tinygrad/solution.py index fb5e68d6..ef5f99c3 100644 --- a/questions/4_calculate-mean-by-row-or-column/tinygrad/solution.py +++ b/questions/4_calculate-mean-by-row-or-column/tinygrad/solution.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def calculate_matrix_mean_tg(matrix, mode: str) -> Tensor: """ Calculate mean of a 2D matrix per row or per column using tinygrad. @@ -9,9 +10,9 @@ def calculate_matrix_mean_tg(matrix, mode: str) -> Tensor: v_t = Tensor(matrix).float() n_obs = v_t.shape[1] n_feat = v_t.shape[0] - if mode == 'column': + if mode == "column": return v_t.sum(axis=1) / n_obs - elif mode == 'row': + elif mode == "row": return v_t.sum(axis=0) / n_feat else: raise ValueError("Mode must be 'row' or 'column'") diff --git a/questions/4_calculate-mean-by-row-or-column/tinygrad/starter_code.py b/questions/4_calculate-mean-by-row-or-column/tinygrad/starter_code.py index f85354a4..44f5ffe9 100644 --- a/questions/4_calculate-mean-by-row-or-column/tinygrad/starter_code.py +++ b/questions/4_calculate-mean-by-row-or-column/tinygrad/starter_code.py @@ -1,11 +1,12 @@ from tinygrad.tensor import Tensor + def calculate_matrix_mean_tg(matrix, mode: str) -> Tensor: """ Calculate mean of a 2D matrix per row or per column using tinygrad. Inputs can be Python lists, NumPy arrays, or tinygrad Tensors. Returns a 1-D Tensor of means or raises ValueError on invalid mode. """ - v_t = Tensor(matrix).float() + Tensor(matrix).float() # Your implementation here pass diff --git a/questions/50_implement-lasso-regression-using-gradient-descent/solution.py b/questions/50_implement-lasso-regression-using-gradient-descent/solution.py index d8d3a5b8..e7ab551f 100644 --- a/questions/50_implement-lasso-regression-using-gradient-descent/solution.py +++ b/questions/50_implement-lasso-regression-using-gradient-descent/solution.py @@ -1,11 +1,19 @@ import numpy as np -def l1_regularization_gradient_descent(X: np.array, y: np.array, alpha: float = 0.1, learning_rate: float = 0.01, max_iter: int = 1000, tol: float = 1e-4) -> tuple: + +def l1_regularization_gradient_descent( + X: np.array, + y: np.array, + alpha: float = 0.1, + learning_rate: float = 0.01, + max_iter: int = 1000, + tol: float = 1e-4, +) -> tuple: n_samples, n_features = X.shape # Zero out weights and bias weights = np.zeros(n_features) bias = 0 - + for iteration in range(max_iter): # Predict values y_pred = np.dot(X, weights) + bias @@ -15,13 +23,13 @@ def l1_regularization_gradient_descent(X: np.array, y: np.array, alpha: float = grad_w = (1 / n_samples) * np.dot(X.T, error) + alpha * np.sign(weights) # Gradient for bias (no penalty for bias) grad_b = (1 / n_samples) * np.sum(error) - + # Update weights and bias weights -= learning_rate * grad_w bias -= learning_rate * grad_b - + # Check for convergence if np.linalg.norm(grad_w, ord=1) < tol: break - + return weights, bias diff --git a/questions/50_implement-lasso-regression-using-gradient-descent/starter_code.py b/questions/50_implement-lasso-regression-using-gradient-descent/starter_code.py index 69ca086d..eb4d938e 100644 --- a/questions/50_implement-lasso-regression-using-gradient-descent/starter_code.py +++ b/questions/50_implement-lasso-regression-using-gradient-descent/starter_code.py @@ -1,9 +1,16 @@ import numpy as np -def l1_regularization_gradient_descent(X: np.array, y: np.array, alpha: float = 0.1, learning_rate: float = 0.01, max_iter: int = 1000, tol: float = 1e-4) -> tuple: - n_samples, n_features = X.shape - weights = np.zeros(n_features) - bias = 0 - # Your code here - pass +def l1_regularization_gradient_descent( + X: np.array, + y: np.array, + alpha: float = 0.1, + learning_rate: float = 0.01, + max_iter: int = 1000, + tol: float = 1e-4, +) -> tuple: + n_samples, n_features = X.shape + + np.zeros(n_features) + # Your code here + pass diff --git a/questions/51_optimal-string-alignment-distance/solution.py b/questions/51_optimal-string-alignment-distance/solution.py index b21c69b3..cc233d29 100644 --- a/questions/51_optimal-string-alignment-distance/solution.py +++ b/questions/51_optimal-string-alignment-distance/solution.py @@ -1,5 +1,3 @@ -import numpy as np - def OSA(source: str, target: str) -> int: source_len, target_len = len(source), len(target) @@ -18,9 +16,17 @@ def OSA(source: str, target: str) -> int: osa_matrix[i][j] = min( osa_matrix[i - 1][j] + 1, # Deletion osa_matrix[i][j - 1] + 1, # Insertion - osa_matrix[i - 1][j - 1] + (1 if source[i - 1] != target[j - 1] else 0) # Substitution + osa_matrix[i - 1][j - 1] + + (1 if source[i - 1] != target[j - 1] else 0), # Substitution ) - if i > 1 and j > 1 and source[i - 1] == target[j - 2] and source[i - 2] == target[j - 1]: - osa_matrix[i][j] = min(osa_matrix[i][j], osa_matrix[i - 2][j - 2] + 1) # Transposition + if ( + i > 1 + and j > 1 + and source[i - 1] == target[j - 2] + and source[i - 2] == target[j - 1] + ): + osa_matrix[i][j] = min( + osa_matrix[i][j], osa_matrix[i - 2][j - 2] + 1 + ) # Transposition return osa_matrix[-1][-1] diff --git a/questions/51_optimal-string-alignment-distance/starter_code.py b/questions/51_optimal-string-alignment-distance/starter_code.py index eed1af3c..2cd0e816 100644 --- a/questions/51_optimal-string-alignment-distance/starter_code.py +++ b/questions/51_optimal-string-alignment-distance/starter_code.py @@ -1,3 +1,3 @@ def OSA(source: str, target: str) -> int: - # Your code here - pass + # Your code here + pass diff --git a/questions/52_implement-recall-metric-in-binary-classification/solution.py b/questions/52_implement-recall-metric-in-binary-classification/solution.py index 54271f46..a07708ee 100644 --- a/questions/52_implement-recall-metric-in-binary-classification/solution.py +++ b/questions/52_implement-recall-metric-in-binary-classification/solution.py @@ -1,5 +1,6 @@ import numpy as np + def recall(y_true, y_pred): tp = np.sum((y_true == 1) & (y_pred == 1)) fn = np.sum((y_true == 1) & (y_pred == 0)) diff --git a/questions/52_implement-recall-metric-in-binary-classification/starter_code.py b/questions/52_implement-recall-metric-in-binary-classification/starter_code.py index d70c1d3f..54216a40 100644 --- a/questions/52_implement-recall-metric-in-binary-classification/starter_code.py +++ b/questions/52_implement-recall-metric-in-binary-classification/starter_code.py @@ -1,3 +1,4 @@ import numpy as np def recall(y_true, y_pred): - + # Your code here + pass diff --git a/questions/53_implement-self-attention-mechanism/solution.py b/questions/53_implement-self-attention-mechanism/solution.py index 2d727c7a..88088a62 100644 --- a/questions/53_implement-self-attention-mechanism/solution.py +++ b/questions/53_implement-self-attention-mechanism/solution.py @@ -1,11 +1,13 @@ import numpy as np + def compute_qkv(X, W_q, W_k, W_v): Q = np.dot(X, W_q) K = np.dot(X, W_k) V = np.dot(X, W_v) return Q, K, V + def self_attention(Q, K, V): d_k = Q.shape[1] scores = np.matmul(Q, K.T) / np.sqrt(d_k) diff --git a/questions/53_implement-self-attention-mechanism/starter_code.py b/questions/53_implement-self-attention-mechanism/starter_code.py index 230bf496..4303ff74 100644 --- a/questions/53_implement-self-attention-mechanism/starter_code.py +++ b/questions/53_implement-self-attention-mechanism/starter_code.py @@ -1,5 +1,2 @@ -import numpy as np - def self_attention(Q, K, V): - - return attention_output + return attention_output diff --git a/questions/54_implementing-a-simple-rnn/solution.py b/questions/54_implementing-a-simple-rnn/solution.py index 8bb293ba..ece11194 100644 --- a/questions/54_implementing-a-simple-rnn/solution.py +++ b/questions/54_implementing-a-simple-rnn/solution.py @@ -1,6 +1,6 @@ - import numpy as np + def rnn_forward(input_sequence, initial_hidden_state, Wx, Wh, b): h = np.array(initial_hidden_state) Wx = np.array(Wx) diff --git a/questions/54_implementing-a-simple-rnn/starter_code.py b/questions/54_implementing-a-simple-rnn/starter_code.py index 3139eed9..ff15ab7b 100644 --- a/questions/54_implementing-a-simple-rnn/starter_code.py +++ b/questions/54_implementing-a-simple-rnn/starter_code.py @@ -1,5 +1,9 @@ -import numpy as np - -def rnn_forward(input_sequence: list[list[float]], initial_hidden_state: list[float], Wx: list[list[float]], Wh: list[list[float]], b: list[float]) -> list[float]: - # Your code here - return final_hidden_state +def rnn_forward( + input_sequence: list[list[float]], + initial_hidden_state: list[float], + Wx: list[list[float]], + Wh: list[list[float]], + b: list[float], +) -> list[float]: + # Your code here + return final_hidden_state diff --git a/questions/55_2d-translation-matrix-implementation/solution.py b/questions/55_2d-translation-matrix-implementation/solution.py index e456a0c6..5198045a 100644 --- a/questions/55_2d-translation-matrix-implementation/solution.py +++ b/questions/55_2d-translation-matrix-implementation/solution.py @@ -1,14 +1,11 @@ import numpy as np + def translate_object(points, tx, ty): - translation_matrix = np.array([ - [1, 0, tx], - [0, 1, ty], - [0, 0, 1] - ]) - + translation_matrix = np.array([[1, 0, tx], [0, 1, ty], [0, 0, 1]]) + homogeneous_points = np.hstack([np.array(points), np.ones((len(points), 1))]) - + translated_points = np.dot(homogeneous_points, translation_matrix.T) - + return translated_points[:, :2].tolist() diff --git a/questions/55_2d-translation-matrix-implementation/starter_code.py b/questions/55_2d-translation-matrix-implementation/starter_code.py index 788d9056..2a6110f5 100644 --- a/questions/55_2d-translation-matrix-implementation/starter_code.py +++ b/questions/55_2d-translation-matrix-implementation/starter_code.py @@ -1,3 +1,2 @@ -import numpy as np def translate_object(points, tx, ty): - return translated_points + return translated_points diff --git a/questions/56_kl-divergence-between-two-normal-distributions/solution.py b/questions/56_kl-divergence-between-two-normal-distributions/solution.py index 82999017..03f2749d 100644 --- a/questions/56_kl-divergence-between-two-normal-distributions/solution.py +++ b/questions/56_kl-divergence-between-two-normal-distributions/solution.py @@ -1,7 +1,8 @@ import numpy as np + def kl_divergence_normal(mu_p, sigma_p, mu_q, sigma_q): term1 = np.log(sigma_q / sigma_p) - term2 = (sigma_p ** 2 + (mu_p - mu_q) ** 2) / (2 * sigma_q ** 2) + term2 = (sigma_p**2 + (mu_p - mu_q) ** 2) / (2 * sigma_q**2) kl_div = term1 + term2 - 0.5 return kl_div diff --git a/questions/56_kl-divergence-between-two-normal-distributions/starter_code.py b/questions/56_kl-divergence-between-two-normal-distributions/starter_code.py index afa7998b..1bcf31f6 100644 --- a/questions/56_kl-divergence-between-two-normal-distributions/starter_code.py +++ b/questions/56_kl-divergence-between-two-normal-distributions/starter_code.py @@ -1,4 +1,2 @@ -import numpy as np - def kl_divergence_normal(mu_p, sigma_p, mu_q, sigma_q): - return 0.0 + return 0.0 diff --git a/questions/57_gauss-seidel-method-for-solving-linear-systems/solution.py b/questions/57_gauss-seidel-method-for-solving-linear-systems/solution.py index bd5c4ad4..6e407627 100644 --- a/questions/57_gauss-seidel-method-for-solving-linear-systems/solution.py +++ b/questions/57_gauss-seidel-method-for-solving-linear-systems/solution.py @@ -1,5 +1,6 @@ import numpy as np + def gauss_seidel_it(A, b, x): rows, cols = A.shape for i in range(rows): @@ -10,6 +11,7 @@ def gauss_seidel_it(A, b, x): x[i] = x_new / A[i, i] return x + def gauss_seidel(A, b, n, x_ini=None): x = x_ini or np.zeros_like(b) for _ in range(n): diff --git a/questions/57_gauss-seidel-method-for-solving-linear-systems/starter_code.py b/questions/57_gauss-seidel-method-for-solving-linear-systems/starter_code.py index 1364f5df..ed80ee88 100644 --- a/questions/57_gauss-seidel-method-for-solving-linear-systems/starter_code.py +++ b/questions/57_gauss-seidel-method-for-solving-linear-systems/starter_code.py @@ -1,4 +1,5 @@ import numpy as np + def gauss_seidel(A, b, n, x_ini=None): - return np.zeros_like(b) + return np.zeros_like(b) diff --git a/questions/58_gaussian-elimination-for-solving-linear-systems/solution.py b/questions/58_gaussian-elimination-for-solving-linear-systems/solution.py index 6d851796..a89ba512 100644 --- a/questions/58_gaussian-elimination-for-solving-linear-systems/solution.py +++ b/questions/58_gaussian-elimination-for-solving-linear-systems/solution.py @@ -1,5 +1,6 @@ import numpy as np + def partial_pivoting(A_aug, row_num, col_num): rows, cols = A_aug.shape max_row = row_num @@ -13,16 +14,17 @@ def partial_pivoting(A_aug, row_num, col_num): A_aug[[row_num, max_row]] = A_aug[[max_row, row_num]] return A_aug + def gaussian_elimination(A, b): rows, cols = A.shape A_aug = np.hstack((A, b.reshape(-1, 1))) - for i in range(rows-1): + for i in range(rows - 1): A_aug = partial_pivoting(A_aug, i, i) - for j in range(i+1, rows): + for j in range(i + 1, rows): A_aug[j, i:] -= (A_aug[j, i] / A_aug[i, i]) * A_aug[i, i:] x = np.zeros_like(b, dtype=float) - for i in range(rows-1, -1, -1): - x[i] = (A_aug[i, -1] - np.dot(A_aug[i, i+1:cols], x[i+1:])) / A_aug[i, i] + for i in range(rows - 1, -1, -1): + x[i] = (A_aug[i, -1] - np.dot(A_aug[i, i + 1 : cols], x[i + 1 :])) / A_aug[i, i] return x diff --git a/questions/58_gaussian-elimination-for-solving-linear-systems/starter_code.py b/questions/58_gaussian-elimination-for-solving-linear-systems/starter_code.py index 9da83506..e2d412f2 100644 --- a/questions/58_gaussian-elimination-for-solving-linear-systems/starter_code.py +++ b/questions/58_gaussian-elimination-for-solving-linear-systems/starter_code.py @@ -1,11 +1,12 @@ import numpy as np + def gaussian_elimination(A, b): - """ - Solves the system Ax = b using Gaussian Elimination with partial pivoting. - - :param A: Coefficient matrix - :param b: Right-hand side vector - :return: Solution vector x - """ - return np.zeros_like(b) + """ + Solves the system Ax = b using Gaussian Elimination with partial pivoting. + + :param A: Coefficient matrix + :param b: Right-hand side vector + :return: Solution vector x + """ + return np.zeros_like(b) diff --git a/questions/59_implement-long-short-term-memory-lstm-network/solution.py b/questions/59_implement-long-short-term-memory-lstm-network/solution.py index 3437bfe2..68105aff 100644 --- a/questions/59_implement-long-short-term-memory-lstm-network/solution.py +++ b/questions/59_implement-long-short-term-memory-lstm-network/solution.py @@ -1,5 +1,6 @@ import numpy as np + class LSTM: def __init__(self, input_size, hidden_size): self.input_size = input_size diff --git a/questions/59_implement-long-short-term-memory-lstm-network/starter_code.py b/questions/59_implement-long-short-term-memory-lstm-network/starter_code.py index d9db3696..195bb652 100644 --- a/questions/59_implement-long-short-term-memory-lstm-network/starter_code.py +++ b/questions/59_implement-long-short-term-memory-lstm-network/starter_code.py @@ -1,23 +1,24 @@ import numpy as np + class LSTM: - def __init__(self, input_size, hidden_size): - self.input_size = input_size - self.hidden_size = hidden_size + def __init__(self, input_size, hidden_size): + self.input_size = input_size + self.hidden_size = hidden_size - # Initialize weights and biases - self.Wf = np.random.randn(hidden_size, input_size + hidden_size) - self.Wi = np.random.randn(hidden_size, input_size + hidden_size) - self.Wc = np.random.randn(hidden_size, input_size + hidden_size) - self.Wo = np.random.randn(hidden_size, input_size + hidden_size) + # Initialize weights and biases + self.Wf = np.random.randn(hidden_size, input_size + hidden_size) + self.Wi = np.random.randn(hidden_size, input_size + hidden_size) + self.Wc = np.random.randn(hidden_size, input_size + hidden_size) + self.Wo = np.random.randn(hidden_size, input_size + hidden_size) - self.bf = np.zeros((hidden_size, 1)) - self.bi = np.zeros((hidden_size, 1)) - self.bc = np.zeros((hidden_size, 1)) - self.bo = np.zeros((hidden_size, 1)) + self.bf = np.zeros((hidden_size, 1)) + self.bi = np.zeros((hidden_size, 1)) + self.bc = np.zeros((hidden_size, 1)) + self.bo = np.zeros((hidden_size, 1)) - def forward(self, x, initial_hidden_state, initial_cell_state): - """ - Processes a sequence of inputs and returns the hidden states, final hidden state, and final cell state. - """ - pass + def forward(self, x, initial_hidden_state, initial_cell_state): + """ + Processes a sequence of inputs and returns the hidden states, final hidden state, and final cell state. + """ + pass diff --git a/questions/5_scalar-multiplication-of-a-matrix/pytorch/solution.py b/questions/5_scalar-multiplication-of-a-matrix/pytorch/solution.py index 195a9048..05bcbd4e 100644 --- a/questions/5_scalar-multiplication-of-a-matrix/pytorch/solution.py +++ b/questions/5_scalar-multiplication-of-a-matrix/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def scalar_multiply(matrix, scalar) -> torch.Tensor: """ Multiply each element of a 2D matrix by a scalar using PyTorch. diff --git a/questions/5_scalar-multiplication-of-a-matrix/pytorch/starter_code.py b/questions/5_scalar-multiplication-of-a-matrix/pytorch/starter_code.py index e02b71c3..a157f6ed 100644 --- a/questions/5_scalar-multiplication-of-a-matrix/pytorch/starter_code.py +++ b/questions/5_scalar-multiplication-of-a-matrix/pytorch/starter_code.py @@ -1,5 +1,6 @@ import torch + def scalar_multiply(matrix, scalar) -> torch.Tensor: """ Multiply each element of a 2D matrix by a scalar using PyTorch. @@ -7,6 +8,6 @@ def scalar_multiply(matrix, scalar) -> torch.Tensor: Returns a 2D tensor of the same shape. """ # Convert input to tensor - m_t = torch.as_tensor(matrix, dtype=torch.float) + torch.as_tensor(matrix, dtype=torch.float) # Your implementation here pass diff --git a/questions/5_scalar-multiplication-of-a-matrix/solution.py b/questions/5_scalar-multiplication-of-a-matrix/solution.py index a025c49e..f642dbce 100644 --- a/questions/5_scalar-multiplication-of-a-matrix/solution.py +++ b/questions/5_scalar-multiplication-of-a-matrix/solution.py @@ -1,2 +1,4 @@ -def scalar_multiply(matrix: list[list[int|float]], scalar: int|float) -> list[list[int|float]]: +def scalar_multiply( + matrix: list[list[int | float]], scalar: int | float +) -> list[list[int | float]]: return [[element * scalar for element in row] for row in matrix] diff --git a/questions/5_scalar-multiplication-of-a-matrix/starter_code.py b/questions/5_scalar-multiplication-of-a-matrix/starter_code.py index 2f260f30..e1dd4561 100644 --- a/questions/5_scalar-multiplication-of-a-matrix/starter_code.py +++ b/questions/5_scalar-multiplication-of-a-matrix/starter_code.py @@ -1,2 +1,4 @@ -def scalar_multiply(matrix: list[list[int|float]], scalar: int|float) -> list[list[int|float]]: - return result +def scalar_multiply( + matrix: list[list[int | float]], scalar: int | float +) -> list[list[int | float]]: + return result diff --git a/questions/5_scalar-multiplication-of-a-matrix/tinygrad/solution.py b/questions/5_scalar-multiplication-of-a-matrix/tinygrad/solution.py index 3c58ac52..951ca3b4 100644 --- a/questions/5_scalar-multiplication-of-a-matrix/tinygrad/solution.py +++ b/questions/5_scalar-multiplication-of-a-matrix/tinygrad/solution.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def scalar_multiply_tg(matrix, scalar) -> Tensor: """ Multiply each element of a 2D matrix by a scalar using tinygrad. diff --git a/questions/5_scalar-multiplication-of-a-matrix/tinygrad/starter_code.py b/questions/5_scalar-multiplication-of-a-matrix/tinygrad/starter_code.py index 0d96bc7e..87b6206b 100644 --- a/questions/5_scalar-multiplication-of-a-matrix/tinygrad/starter_code.py +++ b/questions/5_scalar-multiplication-of-a-matrix/tinygrad/starter_code.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def scalar_multiply_tg(matrix, scalar) -> Tensor: """ Multiply each element of a 2D matrix by a scalar using tinygrad. @@ -7,6 +8,6 @@ def scalar_multiply_tg(matrix, scalar) -> Tensor: Returns a 2D Tensor of the same shape. """ # Convert input to Tensor - m_t = Tensor(matrix) + Tensor(matrix) # Your implementation here pass diff --git a/questions/60_implement-tf-idf-term-frequency-inverse-document-f/solution.py b/questions/60_implement-tf-idf-term-frequency-inverse-document-f/solution.py index 1bd42c03..5542c4a7 100644 --- a/questions/60_implement-tf-idf-term-frequency-inverse-document-f/solution.py +++ b/questions/60_implement-tf-idf-term-frequency-inverse-document-f/solution.py @@ -1,5 +1,6 @@ import numpy as np + def compute_tf_idf(corpus, query): """ Compute TF-IDF scores for a query against a corpus of documents using only NumPy. diff --git a/questions/60_implement-tf-idf-term-frequency-inverse-document-f/starter_code.py b/questions/60_implement-tf-idf-term-frequency-inverse-document-f/starter_code.py index 9bbd011f..cb1aef17 100644 --- a/questions/60_implement-tf-idf-term-frequency-inverse-document-f/starter_code.py +++ b/questions/60_implement-tf-idf-term-frequency-inverse-document-f/starter_code.py @@ -1,11 +1,9 @@ -import numpy as np - def compute_tf_idf(corpus, query): - """ - Compute TF-IDF scores for a query against a corpus of documents. - - :param corpus: List of documents, where each document is a list of words - :param query: List of words in the query - :return: List of lists containing TF-IDF scores for the query words in each document - """ - pass + """ + Compute TF-IDF scores for a query against a corpus of documents. + + :param corpus: List of documents, where each document is a list of words + :param query: List of words in the query + :return: List of lists containing TF-IDF scores for the query words in each document + """ + pass diff --git a/questions/61_implement-f-score-calculation-for-binary-classific/solution.py b/questions/61_implement-f-score-calculation-for-binary-classific/solution.py index 8b6deab6..8776ae39 100644 --- a/questions/61_implement-f-score-calculation-for-binary-classific/solution.py +++ b/questions/61_implement-f-score-calculation-for-binary-classific/solution.py @@ -1,5 +1,6 @@ import numpy as np + def f_score(y_true, y_pred, beta): tp = np.sum((y_true == 1) & (y_pred == 1)) fn = np.sum((y_true == 1) & (y_pred == 0)) @@ -14,5 +15,5 @@ def f_score(y_true, y_pred, beta): if div == 0 or op == 0: return 0.0 - score = (1 + (beta ** 2)) * op / div + score = (1 + (beta**2)) * op / div return round(score, 3) diff --git a/questions/61_implement-f-score-calculation-for-binary-classific/starter_code.py b/questions/61_implement-f-score-calculation-for-binary-classific/starter_code.py index dfdb6834..c6261c1f 100644 --- a/questions/61_implement-f-score-calculation-for-binary-classific/starter_code.py +++ b/questions/61_implement-f-score-calculation-for-binary-classific/starter_code.py @@ -1,12 +1,10 @@ -import numpy as np - def f_score(y_true, y_pred, beta): - """ - Calculate F-Score for a binary classification task. + """ + Calculate F-Score for a binary classification task. - :param y_true: Numpy array of true labels - :param y_pred: Numpy array of predicted labels - :param beta: The weight of precision in the harmonic mean - :return: F-Score rounded to three decimal places - """ - pass + :param y_true: Numpy array of true labels + :param y_pred: Numpy array of predicted labels + :param beta: The weight of precision in the harmonic mean + :return: F-Score rounded to three decimal places + """ + pass diff --git a/questions/62_implement-a-simple-rnn-with-backpropagation-throug/solution.py b/questions/62_implement-a-simple-rnn-with-backpropagation-throug/solution.py index d28e5063..2075cee8 100644 --- a/questions/62_implement-a-simple-rnn-with-backpropagation-throug/solution.py +++ b/questions/62_implement-a-simple-rnn-with-backpropagation-throug/solution.py @@ -1,5 +1,6 @@ import numpy as np + class SimpleRNN: def __init__(self, input_size, hidden_size, output_size): self.hidden_size = hidden_size @@ -14,14 +15,16 @@ def forward(self, x): outputs = [] self.last_inputs = [] self.last_hiddens = [h] - + for t in range(len(x)): self.last_inputs.append(x[t].reshape(-1, 1)) - h = np.tanh(np.dot(self.W_xh, self.last_inputs[t]) + np.dot(self.W_hh, h) + self.b_h) + h = np.tanh( + np.dot(self.W_xh, self.last_inputs[t]) + np.dot(self.W_hh, h) + self.b_h + ) y = np.dot(self.W_hy, h) + self.b_y outputs.append(y) self.last_hiddens.append(h) - + self.last_outputs = outputs return np.array(outputs) @@ -36,11 +39,11 @@ def backward(self, x, y, learning_rate): for t in reversed(range(len(x))): dy = self.last_outputs[t] - y[t].reshape(-1, 1) # (Predicted - Actual) - dW_hy += np.dot(dy, self.last_hiddens[t+1].T) + dW_hy += np.dot(dy, self.last_hiddens[t + 1].T) db_y += dy dh = np.dot(self.W_hy.T, dy) + dh_next - dh_raw = (1 - self.last_hiddens[t+1] ** 2) * dh # Derivative of tanh + dh_raw = (1 - self.last_hiddens[t + 1] ** 2) * dh # Derivative of tanh dW_xh += np.dot(dh_raw, self.last_inputs[t].T) dW_hh += np.dot(dh_raw, self.last_hiddens[t].T) diff --git a/questions/62_implement-a-simple-rnn-with-backpropagation-throug/starter_code.py b/questions/62_implement-a-simple-rnn-with-backpropagation-throug/starter_code.py index 52b6f515..f9b354d6 100644 --- a/questions/62_implement-a-simple-rnn-with-backpropagation-throug/starter_code.py +++ b/questions/62_implement-a-simple-rnn-with-backpropagation-throug/starter_code.py @@ -1,17 +1,16 @@ - import numpy as np class SimpleRNN: - def __init__(self, input_size, hidden_size, output_size): + def __init__(self, input_size, hidden_size, output_size): """ Initializes the RNN with random weights and zero biases. """ - self.hidden_size = hidden_size - self.W_xh = np.random.randn(hidden_size, input_size)*0.01 - self.W_hh = np.random.randn(hidden_size, hidden_size)*0.01 - self.W_hy = np.random.randn(output_size, hidden_size)*0.01 - self.b_h = np.zeros((hidden_size, 1)) - self.b_y = np.zeros((output_size, 1)) - def forward(self, x): + self.hidden_size = hidden_size + self.W_xh = np.random.randn(hidden_size, input_size)*0.01 + self.W_hh = np.random.randn(hidden_size, hidden_size)*0.01 + self.W_hy = np.random.randn(output_size, hidden_size)*0.01 + self.b_h = np.zeros((hidden_size, 1)) + self.b_y = np.zeros((output_size, 1)) + def forward(self, x): """ Forward pass through the RNN for a given sequence of inputs. """ diff --git a/questions/63_implement-the-conjugate-gradient-method-for-solvin/solution.py b/questions/63_implement-the-conjugate-gradient-method-for-solvin/solution.py index cfc4f6b5..4896802c 100644 --- a/questions/63_implement-the-conjugate-gradient-method-for-solvin/solution.py +++ b/questions/63_implement-the-conjugate-gradient-method-for-solvin/solution.py @@ -1,21 +1,22 @@ import numpy as np -def conjugate_gradient(A: np.array, b: np.array, n: int, x0: np.array=None, tol=1e-8) -> np.array: +def conjugate_gradient( + A: np.array, b: np.array, n: int, x0: np.array = None, tol=1e-8 +) -> np.array: # calculate initial residual vector x = np.zeros_like(b) - r = residual(A, b, x) # residual vector + r = residual(A, b, x) # residual vector rPlus1 = r - p = r # search direction vector + p = r # search direction vector for i in range(n): - # line search step value - this minimizes the error along the current search direction alp = alpha(A, r, p) # new x and r based on current p (the search direction vector) x = x + alp * p - rPlus1 = r - alp * (A@p) + rPlus1 = r - alp * (A @ p) # calculate beta - this ensures that all vectors are A-orthogonal to each other bet = beta(r, rPlus1) @@ -28,27 +29,28 @@ def conjugate_gradient(A: np.array, b: np.array, n: int, x0: np.array=None, tol= r = rPlus1 # break if less than tolerance - if np.linalg.norm(residual(A,b,x)) < tol: + if np.linalg.norm(residual(A, b, x)) < tol: break return x + def residual(A: np.array, b: np.array, x: np.array) -> np.array: # calculate linear system residuals return b - A @ x -def alpha(A: np.array, r: np.array, p: np.array) -> float: +def alpha(A: np.array, r: np.array, p: np.array) -> float: # calculate step size alpha_num = np.dot(r, r) alpha_den = np.dot(p @ A, p) - return alpha_num/alpha_den + return alpha_num / alpha_den -def beta(r: np.array, r_plus1: np.array) -> float: +def beta(r: np.array, r_plus1: np.array) -> float: # calculate direction scaling beta_num = np.dot(r_plus1, r_plus1) beta_den = np.dot(r, r) - return beta_num/beta_den + return beta_num / beta_den diff --git a/questions/63_implement-the-conjugate-gradient-method-for-solvin/starter_code.py b/questions/63_implement-the-conjugate-gradient-method-for-solvin/starter_code.py index 781f48f0..c60966b6 100644 --- a/questions/63_implement-the-conjugate-gradient-method-for-solvin/starter_code.py +++ b/questions/63_implement-the-conjugate-gradient-method-for-solvin/starter_code.py @@ -1,15 +1,16 @@ import numpy as np + def conjugate_gradient(A, b, n, x0=None, tol=1e-8): - """ - Solve the system Ax = b using the Conjugate Gradient method. + """ + Solve the system Ax = b using the Conjugate Gradient method. - :param A: Symmetric positive-definite matrix - :param b: Right-hand side vector - :param n: Maximum number of iterations - :param x0: Initial guess for solution (default is zero vector) - :param tol: Convergence tolerance - :return: Solution vector x - """ - # calculate initial residual vector - x = np.zeros_like(b) + :param A: Symmetric positive-definite matrix + :param b: Right-hand side vector + :param n: Maximum number of iterations + :param x0: Initial guess for solution (default is zero vector) + :param tol: Convergence tolerance + :return: Solution vector x + """ + # calculate initial residual vector + np.zeros_like(b) diff --git a/questions/64_implement-gini-impurity-calculation-for-a-set-of-c/solution.py b/questions/64_implement-gini-impurity-calculation-for-a-set-of-c/solution.py index 3b369812..236ab92f 100644 --- a/questions/64_implement-gini-impurity-calculation-for-a-set-of-c/solution.py +++ b/questions/64_implement-gini-impurity-calculation-for-a-set-of-c/solution.py @@ -1,13 +1,10 @@ -import numpy as np - def gini_impurity(y: list[int]) -> float: - classes = set(y) n = len(y) gini_impurity = 0 for cls in classes: - gini_impurity += (y.count(cls)/n)**2 + gini_impurity += (y.count(cls) / n) ** 2 - return round(1-gini_impurity,3) + return round(1 - gini_impurity, 3) diff --git a/questions/64_implement-gini-impurity-calculation-for-a-set-of-c/starter_code.py b/questions/64_implement-gini-impurity-calculation-for-a-set-of-c/starter_code.py index 4ea57fe8..346301af 100644 --- a/questions/64_implement-gini-impurity-calculation-for-a-set-of-c/starter_code.py +++ b/questions/64_implement-gini-impurity-calculation-for-a-set-of-c/starter_code.py @@ -1,12 +1,9 @@ - -import numpy as np - def gini_impurity(y): - """ - Calculate Gini Impurity for a list of class labels. + """ + Calculate Gini Impurity for a list of class labels. - :param y: List of class labels - :return: Gini Impurity rounded to three decimal places - """ - pass - return round(val,3) + :param y: List of class labels + :return: Gini Impurity rounded to three decimal places + """ + pass + return round(val, 3) diff --git a/questions/65_implement-compressed-row-sparse-matrix-csr-format-/solution.py b/questions/65_implement-compressed-row-sparse-matrix-csr-format-/solution.py index 9dd50aea..3ea88117 100644 --- a/questions/65_implement-compressed-row-sparse-matrix-csr-format-/solution.py +++ b/questions/65_implement-compressed-row-sparse-matrix-csr-format-/solution.py @@ -1,5 +1,3 @@ -import numpy as np - def compressed_row_sparse_matrix(dense_matrix): vals = [] col_idx = [] diff --git a/questions/65_implement-compressed-row-sparse-matrix-csr-format-/starter_code.py b/questions/65_implement-compressed-row-sparse-matrix-csr-format-/starter_code.py index 0c731d2d..28c9c294 100644 --- a/questions/65_implement-compressed-row-sparse-matrix-csr-format-/starter_code.py +++ b/questions/65_implement-compressed-row-sparse-matrix-csr-format-/starter_code.py @@ -1,10 +1,8 @@ -import numpy as np - def compressed_row_sparse_matrix(dense_matrix): - """ - Convert a dense matrix to its Compressed Row Sparse (CSR) representation. + """ + Convert a dense matrix to its Compressed Row Sparse (CSR) representation. - :param dense_matrix: 2D list representing a dense matrix - :return: A tuple containing (values array, column indices array, row pointer array) - """ - pass + :param dense_matrix: 2D list representing a dense matrix + :return: A tuple containing (values array, column indices array, row pointer array) + """ + pass diff --git a/questions/66_implement-orthogonal-projection-of-a-vector-onto-a/solution.py b/questions/66_implement-orthogonal-projection-of-a-vector-onto-a/solution.py index c3ce7ff2..b10cb195 100644 --- a/questions/66_implement-orthogonal-projection-of-a-vector-onto-a/solution.py +++ b/questions/66_implement-orthogonal-projection-of-a-vector-onto-a/solution.py @@ -1,9 +1,11 @@ def dot(v1, v2): return sum([ax1 * ax2 for ax1, ax2 in zip(v1, v2)]) + def scalar_mult(scalar, v): return [scalar * ax for ax in v] + def orthogonal_projection(v, L): L_mag_sq = dot(L, L) proj_scalar = dot(v, L) / L_mag_sq diff --git a/questions/66_implement-orthogonal-projection-of-a-vector-onto-a/starter_code.py b/questions/66_implement-orthogonal-projection-of-a-vector-onto-a/starter_code.py index 4a131145..28cd3912 100644 --- a/questions/66_implement-orthogonal-projection-of-a-vector-onto-a/starter_code.py +++ b/questions/66_implement-orthogonal-projection-of-a-vector-onto-a/starter_code.py @@ -1,10 +1,9 @@ - def orthogonal_projection(v, L): - """ - Compute the orthogonal projection of vector v onto line L. + """ + Compute the orthogonal projection of vector v onto line L. - :param v: The vector to be projected - :param L: The line vector defining the direction of projection - :return: List representing the projection of v onto L - """ - pass + :param v: The vector to be projected + :param L: The line vector defining the direction of projection + :return: List representing the projection of v onto L + """ + pass diff --git a/questions/67_implement-compressed-column-sparse-matrix-format-c/starter_code.py b/questions/67_implement-compressed-column-sparse-matrix-format-c/starter_code.py index eb9c107a..5840923b 100644 --- a/questions/67_implement-compressed-column-sparse-matrix-format-c/starter_code.py +++ b/questions/67_implement-compressed-column-sparse-matrix-format-c/starter_code.py @@ -1,8 +1,8 @@ def compressed_col_sparse_matrix(dense_matrix): - """ - Convert a dense matrix into its Compressed Column Sparse (CSC) representation. + """ + Convert a dense matrix into its Compressed Column Sparse (CSC) representation. - :param dense_matrix: List of lists representing the dense matrix - :return: Tuple of (values, row indices, column pointer) - """ - pass + :param dense_matrix: List of lists representing the dense matrix + :return: Tuple of (values, row indices, column pointer) + """ + pass diff --git a/questions/68_find-the-image-of-a-matrix-using-row-echelon-form/solution.py b/questions/68_find-the-image-of-a-matrix-using-row-echelon-form/solution.py index 83653e26..1a3684b8 100644 --- a/questions/68_find-the-image-of-a-matrix-using-row-echelon-form/solution.py +++ b/questions/68_find-the-image-of-a-matrix-using-row-echelon-form/solution.py @@ -1,6 +1,6 @@ - import numpy as np + def rref(A): # Convert to float for division operations A = A.astype(np.float32) @@ -20,6 +20,7 @@ def rref(A): A[j] -= A[i] * A[j, i] return A + def find_pivot_columns(A): n, m = A.shape pivot_columns = [] @@ -29,6 +30,7 @@ def find_pivot_columns(A): pivot_columns.append(nonzero[0]) return pivot_columns + def matrix_image(A): # Find the RREF of the matrix Arref = rref(A) diff --git a/questions/68_find-the-image-of-a-matrix-using-row-echelon-form/starter_code.py b/questions/68_find-the-image-of-a-matrix-using-row-echelon-form/starter_code.py index e59e24cb..3f5dbc68 100644 --- a/questions/68_find-the-image-of-a-matrix-using-row-echelon-form/starter_code.py +++ b/questions/68_find-the-image-of-a-matrix-using-row-echelon-form/starter_code.py @@ -1,6 +1,3 @@ - -import numpy as np - def matrix_image(A): - # Write your code here - pass + # Write your code here + pass diff --git a/questions/69_calculate-r-squared-for-regression-analysis/solution.py b/questions/69_calculate-r-squared-for-regression-analysis/solution.py index 159ac2b1..2986b7f1 100644 --- a/questions/69_calculate-r-squared-for-regression-analysis/solution.py +++ b/questions/69_calculate-r-squared-for-regression-analysis/solution.py @@ -1,14 +1,14 @@ - import numpy as np + def r_squared(y_true, y_pred): """ Calculate the R-squared (R²) coefficient of determination. - + Args: y_true (numpy.ndarray): Array of true values y_pred (numpy.ndarray): Array of predicted values - + Returns: float: R-squared value rounded to 3 decimal places """ diff --git a/questions/69_calculate-r-squared-for-regression-analysis/starter_code.py b/questions/69_calculate-r-squared-for-regression-analysis/starter_code.py index 5fbe9bb2..b41e4150 100644 --- a/questions/69_calculate-r-squared-for-regression-analysis/starter_code.py +++ b/questions/69_calculate-r-squared-for-regression-analysis/starter_code.py @@ -1,6 +1,3 @@ - -import numpy as np - def r_squared(y_true, y_pred): - # Write your code here - pass + # Write your code here + pass diff --git a/questions/6_calculate-eigenvalues-of-a-matrix/pytorch/solution.py b/questions/6_calculate-eigenvalues-of-a-matrix/pytorch/solution.py index 7d5c4354..ca98ce86 100644 --- a/questions/6_calculate-eigenvalues-of-a-matrix/pytorch/solution.py +++ b/questions/6_calculate-eigenvalues-of-a-matrix/pytorch/solution.py @@ -1,12 +1,15 @@ import torch + def calculate_eigenvalues(matrix: torch.Tensor) -> torch.Tensor: """ Compute eigenvalues of a 2×2 matrix using PyTorch. Input: 2×2 tensor; Output: 1-D tensor with the two eigenvalues in ascending order. """ - a = matrix[0,0]; b = matrix[0,1] - c = matrix[1,0]; d = matrix[1,1] + a = matrix[0, 0] + b = matrix[0, 1] + c = matrix[1, 0] + d = matrix[1, 1] trace = a + d det = a * d - b * c disc = trace * trace - 4 * det diff --git a/questions/6_calculate-eigenvalues-of-a-matrix/pytorch/starter_code.py b/questions/6_calculate-eigenvalues-of-a-matrix/pytorch/starter_code.py index 84d0f873..dbbd6a97 100644 --- a/questions/6_calculate-eigenvalues-of-a-matrix/pytorch/starter_code.py +++ b/questions/6_calculate-eigenvalues-of-a-matrix/pytorch/starter_code.py @@ -1,5 +1,6 @@ import torch + def calculate_eigenvalues(matrix: torch.Tensor) -> torch.Tensor: """ Compute eigenvalues of a 2×2 matrix using PyTorch. diff --git a/questions/6_calculate-eigenvalues-of-a-matrix/starter_code.py b/questions/6_calculate-eigenvalues-of-a-matrix/starter_code.py index e197597b..a223bd51 100644 --- a/questions/6_calculate-eigenvalues-of-a-matrix/starter_code.py +++ b/questions/6_calculate-eigenvalues-of-a-matrix/starter_code.py @@ -1,2 +1,2 @@ -def calculate_eigenvalues(matrix: list[list[float|int]]) -> list[float]: - return eigenvalues +def calculate_eigenvalues(matrix: list[list[float | int]]) -> list[float]: + return eigenvalues diff --git a/questions/6_calculate-eigenvalues-of-a-matrix/tinygrad/solution.py b/questions/6_calculate-eigenvalues-of-a-matrix/tinygrad/solution.py index b79fcdd6..30fe130e 100644 --- a/questions/6_calculate-eigenvalues-of-a-matrix/tinygrad/solution.py +++ b/questions/6_calculate-eigenvalues-of-a-matrix/tinygrad/solution.py @@ -1,13 +1,16 @@ from tinygrad.tensor import Tensor + def calculate_eigenvalues_tg(matrix) -> Tensor: """ Compute eigenvalues of a 2×2 matrix using tinygrad. Input: 2×2 list, NumPy array, or Tensor; Output: 1-D Tensor with eigenvalues in ascending order. """ m = Tensor(matrix).float() - a = m[0,0]; b = m[0,1] - c = m[1,0]; d = m[1,1] + a = m[0, 0] + b = m[0, 1] + c = m[1, 0] + d = m[1, 1] trace = a + d det = a * d - b * c disc = trace * trace - 4 * det diff --git a/questions/6_calculate-eigenvalues-of-a-matrix/tinygrad/starter_code.py b/questions/6_calculate-eigenvalues-of-a-matrix/tinygrad/starter_code.py index 7645439f..653f1a5b 100644 --- a/questions/6_calculate-eigenvalues-of-a-matrix/tinygrad/starter_code.py +++ b/questions/6_calculate-eigenvalues-of-a-matrix/tinygrad/starter_code.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def calculate_eigenvalues_tg(matrix) -> Tensor: """ Compute eigenvalues of a 2×2 matrix using tinygrad. diff --git a/questions/70_calculate-image-brightness/solution.py b/questions/70_calculate-image-brightness/solution.py index 15b70614..d26d4bc3 100644 --- a/questions/70_calculate-image-brightness/solution.py +++ b/questions/70_calculate-image-brightness/solution.py @@ -1,4 +1,3 @@ - def calculate_brightness(img): # Check if image is empty or has no columns if not img or not img[0]: diff --git a/questions/70_calculate-image-brightness/starter_code.py b/questions/70_calculate-image-brightness/starter_code.py index e5dfa325..f8fb6e94 100644 --- a/questions/70_calculate-image-brightness/starter_code.py +++ b/questions/70_calculate-image-brightness/starter_code.py @@ -1,4 +1,3 @@ - def calculate_brightness(img): - # Write your code here - pass + # Write your code here + pass diff --git a/questions/71_calculate-root-mean-square-error-rmse/solution.py b/questions/71_calculate-root-mean-square-error-rmse/solution.py index a0d527f2..f72c8e4f 100644 --- a/questions/71_calculate-root-mean-square-error-rmse/solution.py +++ b/questions/71_calculate-root-mean-square-error-rmse/solution.py @@ -1,6 +1,6 @@ - import numpy as np + def rmse(y_true, y_pred): if y_true.shape != y_pred.shape: raise ValueError("Arrays must have the same shape") diff --git a/questions/71_calculate-root-mean-square-error-rmse/starter_code.py b/questions/71_calculate-root-mean-square-error-rmse/starter_code.py index 4084991e..4bfedc7c 100644 --- a/questions/71_calculate-root-mean-square-error-rmse/starter_code.py +++ b/questions/71_calculate-root-mean-square-error-rmse/starter_code.py @@ -1,6 +1,3 @@ - -import numpy as np - def rmse(y_true, y_pred): - # Write your code here - return round(rmse_res,3) + # Write your code here + return round(rmse_res, 3) diff --git a/questions/72_calculate-jaccard-index-for-binary-classification/solution.py b/questions/72_calculate-jaccard-index-for-binary-classification/solution.py index ce640a5e..e2087caa 100644 --- a/questions/72_calculate-jaccard-index-for-binary-classification/solution.py +++ b/questions/72_calculate-jaccard-index-for-binary-classification/solution.py @@ -1,6 +1,6 @@ - import numpy as np + def jaccard_index(y_true, y_pred): intersection = np.sum((y_true == 1) & (y_pred == 1)) union = np.sum((y_true == 1) | (y_pred == 1)) diff --git a/questions/72_calculate-jaccard-index-for-binary-classification/starter_code.py b/questions/72_calculate-jaccard-index-for-binary-classification/starter_code.py index f00476ed..b2109807 100644 --- a/questions/72_calculate-jaccard-index-for-binary-classification/starter_code.py +++ b/questions/72_calculate-jaccard-index-for-binary-classification/starter_code.py @@ -1,6 +1,3 @@ - -import numpy as np - def jaccard_index(y_true, y_pred): - # Write your code here - return round(result, 3) + # Write your code here + return round(result, 3) diff --git a/questions/73_calculate-dice-score-for-classification/solution.py b/questions/73_calculate-dice-score-for-classification/solution.py index 65a3928c..1f222c47 100644 --- a/questions/73_calculate-dice-score-for-classification/solution.py +++ b/questions/73_calculate-dice-score-for-classification/solution.py @@ -1,6 +1,6 @@ - import numpy as np + def dice_score(y_true, y_pred): intersection = np.logical_and(y_true, y_pred).sum() true_sum = y_true.sum() diff --git a/questions/73_calculate-dice-score-for-classification/starter_code.py b/questions/73_calculate-dice-score-for-classification/starter_code.py index 146784ea..fd430df4 100644 --- a/questions/73_calculate-dice-score-for-classification/starter_code.py +++ b/questions/73_calculate-dice-score-for-classification/starter_code.py @@ -1,6 +1,3 @@ - -import numpy as np - def dice_score(y_true, y_pred): - # Write your code here - return round(res, 3) + # Write your code here + return round(res, 3) diff --git a/questions/74_create-composite-hypervector-for-a-dataset-row/solution.py b/questions/74_create-composite-hypervector-for-a-dataset-row/solution.py index 39887062..00a596d7 100644 --- a/questions/74_create-composite-hypervector-for-a-dataset-row/solution.py +++ b/questions/74_create-composite-hypervector-for-a-dataset-row/solution.py @@ -1,23 +1,28 @@ - import numpy as np + def create_hv(dim): return np.random.choice([-1, 1], dim) + def create_col_hvs(dim, seed): np.random.seed(seed) return create_hv(dim), create_hv(dim) + def bind(hv1, hv2): return hv1 * hv2 + def bundle(hvs, dim): bundled = np.sum(list(hvs.values()), axis=0) return sign(bundled) + def sign(vector, threshold=0.01): return np.array([1 if v >= 0 else -1 for v in vector]) + def create_row_hv(row, dim, random_seeds): row_hvs = {col: bind(*create_col_hvs(dim, random_seeds[col])) for col in row.keys()} return bundle(row_hvs, dim) diff --git a/questions/74_create-composite-hypervector-for-a-dataset-row/starter_code.py b/questions/74_create-composite-hypervector-for-a-dataset-row/starter_code.py index 94223eee..e6f56fa3 100644 --- a/questions/74_create-composite-hypervector-for-a-dataset-row/starter_code.py +++ b/questions/74_create-composite-hypervector-for-a-dataset-row/starter_code.py @@ -1,6 +1,3 @@ - -import numpy as np - def create_row_hv(row, dim, random_seeds): - # Write your code here - pass + # Write your code here + pass diff --git a/questions/75_generate-a-confusion-matrix-for-binary-classificat/solution.py b/questions/75_generate-a-confusion-matrix-for-binary-classificat/solution.py index 4cded5f8..b030bfbc 100644 --- a/questions/75_generate-a-confusion-matrix-for-binary-classificat/solution.py +++ b/questions/75_generate-a-confusion-matrix-for-binary-classificat/solution.py @@ -1,6 +1,6 @@ - from collections import Counter + def confusion_matrix(data): # Count all occurrences counts = Counter(tuple(pair) for pair in data) diff --git a/questions/75_generate-a-confusion-matrix-for-binary-classificat/starter_code.py b/questions/75_generate-a-confusion-matrix-for-binary-classificat/starter_code.py index ff8f4564..fcdabe56 100644 --- a/questions/75_generate-a-confusion-matrix-for-binary-classificat/starter_code.py +++ b/questions/75_generate-a-confusion-matrix-for-binary-classificat/starter_code.py @@ -1,6 +1,3 @@ - -from collections import Counter - def confusion_matrix(data): - # Implement the function here - pass + # Implement the function here + pass diff --git a/questions/76_calculate-cosine-similarity-between-vectors/solution.py b/questions/76_calculate-cosine-similarity-between-vectors/solution.py index 7f008790..73202825 100644 --- a/questions/76_calculate-cosine-similarity-between-vectors/solution.py +++ b/questions/76_calculate-cosine-similarity-between-vectors/solution.py @@ -1,6 +1,6 @@ - import numpy as np + def cosine_similarity(v1, v2): if v1.shape != v2.shape: raise ValueError("Arrays must have the same shape") diff --git a/questions/76_calculate-cosine-similarity-between-vectors/starter_code.py b/questions/76_calculate-cosine-similarity-between-vectors/starter_code.py index 12c19667..c8d67387 100644 --- a/questions/76_calculate-cosine-similarity-between-vectors/starter_code.py +++ b/questions/76_calculate-cosine-similarity-between-vectors/starter_code.py @@ -1,6 +1,3 @@ - -import numpy as np - def cosine_similarity(v1, v2): - # Implement your code here - pass + # Implement your code here + pass diff --git a/questions/77_calculate-performance-metrics-for-a-classification/solution.py b/questions/77_calculate-performance-metrics-for-a-classification/solution.py index 46639dcb..c9620a40 100644 --- a/questions/77_calculate-performance-metrics-for-a-classification/solution.py +++ b/questions/77_calculate-performance-metrics-for-a-classification/solution.py @@ -1,6 +1,6 @@ - from collections import Counter + def performance_metrics(actual: list[int], predicted: list[int]) -> tuple: data = list(zip(actual, predicted)) counts = Counter(tuple(pair) for pair in data) @@ -12,4 +12,10 @@ def performance_metrics(actual: list[int], predicted: list[int]) -> tuple: f1 = 2 * precision * recall / (precision + recall) negativePredictive = TN / (TN + FN) specificity = TN / (TN + FP) - return confusion_matrix, round(accuracy, 3), round(f1, 3), round(specificity, 3), round(negativePredictive, 3) + return ( + confusion_matrix, + round(accuracy, 3), + round(f1, 3), + round(specificity, 3), + round(negativePredictive, 3), + ) diff --git a/questions/77_calculate-performance-metrics-for-a-classification/starter_code.py b/questions/77_calculate-performance-metrics-for-a-classification/starter_code.py index 667cc658..be22b9dd 100644 --- a/questions/77_calculate-performance-metrics-for-a-classification/starter_code.py +++ b/questions/77_calculate-performance-metrics-for-a-classification/starter_code.py @@ -1,4 +1,9 @@ - def performance_metrics(actual: list[int], predicted: list[int]) -> tuple: - # Implement your code here - return confusion_matrix, round(accuracy, 3), round(f1, 3), round(specificity, 3), round(negativePredictive, 3) + # Implement your code here + return ( + confusion_matrix, + round(accuracy, 3), + round(f1, 3), + round(specificity, 3), + round(negativePredictive, 3), + ) diff --git a/questions/78_descriptive-statistics-calculator/solution.py b/questions/78_descriptive-statistics-calculator/solution.py index 7d4b8506..d537c175 100644 --- a/questions/78_descriptive-statistics-calculator/solution.py +++ b/questions/78_descriptive-statistics-calculator/solution.py @@ -1,5 +1,6 @@ import numpy as np + def descriptive_statistics(data): """ Calculate various descriptive statistics metrics for a given dataset. @@ -37,12 +38,12 @@ def descriptive_statistics(data): "mean": mean, "median": median, "mode": mode, - "variance": np.round(variance,4), - "standard_deviation": np.round(std_dev,4), + "variance": np.round(variance, 4), + "standard_deviation": np.round(std_dev, 4), "25th_percentile": percentiles[0], "50th_percentile": percentiles[1], "75th_percentile": percentiles[2], - "interquartile_range": iqr + "interquartile_range": iqr, } return stats_dict diff --git a/questions/78_descriptive-statistics-calculator/starter_code.py b/questions/78_descriptive-statistics-calculator/starter_code.py index be9c5ca4..30c56cdc 100644 --- a/questions/78_descriptive-statistics-calculator/starter_code.py +++ b/questions/78_descriptive-statistics-calculator/starter_code.py @@ -1,15 +1,17 @@ -import numpy as np +import numpy as np + + def descriptive_statistics(data): - # Your code here - stats_dict = { + # Your code here + { "mean": mean, "median": median, "mode": mode, - "variance": np.round(variance,4), - "standard_deviation": np.round(std_dev,4), + "variance": np.round(variance, 4), + "standard_deviation": np.round(std_dev, 4), "25th_percentile": percentiles[0], "50th_percentile": percentiles[1], "75th_percentile": percentiles[2], - "interquartile_range": iqr + "interquartile_range": iqr, } - return {} + return {} diff --git a/questions/79_binomial-distribution-probability/solution.py b/questions/79_binomial-distribution-probability/solution.py index 13d5c98d..14e6770c 100644 --- a/questions/79_binomial-distribution-probability/solution.py +++ b/questions/79_binomial-distribution-probability/solution.py @@ -1,5 +1,6 @@ import math + def binomial_probability(n, k, p): """ Calculate the probability of achieving exactly k successes in n independent Bernoulli trials, @@ -12,6 +13,6 @@ def binomial_probability(n, k, p): # Calculate binomial coefficient (n choose k) binomial_coeff = math.comb(n, k) # Calculate the probability using the binomial formula - probability = binomial_coeff * (p ** k) * ((1 - p) ** (n - k)) + probability = binomial_coeff * (p**k) * ((1 - p) ** (n - k)) # Return the probability, rounded to five decimal places return round(probability, 5) diff --git a/questions/79_binomial-distribution-probability/starter_code.py b/questions/79_binomial-distribution-probability/starter_code.py index b2f0f1b0..190fb9cb 100644 --- a/questions/79_binomial-distribution-probability/starter_code.py +++ b/questions/79_binomial-distribution-probability/starter_code.py @@ -1,9 +1,7 @@ -import math - def binomial_probability(n, k, p): - """ + """ Calculate the probability of achieving exactly k successes in n independent Bernoulli trials, each with probability p of success, using the Binomial distribution formula. """ - # Your code here - return round(probability, 5) + # Your code here + return round(probability, 5) diff --git a/questions/7_matrix-transformation/pytorch/solution.py b/questions/7_matrix-transformation/pytorch/solution.py index 7708d4d8..380d23be 100644 --- a/questions/7_matrix-transformation/pytorch/solution.py +++ b/questions/7_matrix-transformation/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def transform_matrix(A, T, S) -> torch.Tensor: """ Perform the change-of-basis transform T⁻¹ A S and round to 3 decimals using PyTorch. @@ -10,7 +11,7 @@ def transform_matrix(A, T, S) -> torch.Tensor: T_t = torch.as_tensor(T, dtype=torch.float) S_t = torch.as_tensor(S, dtype=torch.float) if torch.det(T_t) == 0 or torch.det(S_t) == 0: - return torch.tensor(-1.) + return torch.tensor(-1.0) T_inv = torch.inverse(T_t) out = T_inv @ A_t @ S_t return torch.round(out * 1000) / 1000 diff --git a/questions/7_matrix-transformation/pytorch/starter_code.py b/questions/7_matrix-transformation/pytorch/starter_code.py index 8edada84..244a88d3 100644 --- a/questions/7_matrix-transformation/pytorch/starter_code.py +++ b/questions/7_matrix-transformation/pytorch/starter_code.py @@ -1,13 +1,14 @@ import torch + def transform_matrix(A, T, S) -> torch.Tensor: """ Perform the change-of-basis transform T⁻¹ A S and round to 3 decimals using PyTorch. Inputs A, T, S can be Python lists, NumPy arrays, or torch Tensors. Returns a 2×2 tensor or tensor(-1.) if T or S is singular. """ - A_t = torch.as_tensor(A, dtype=torch.float) - T_t = torch.as_tensor(T, dtype=torch.float) - S_t = torch.as_tensor(S, dtype=torch.float) + torch.as_tensor(A, dtype=torch.float) + torch.as_tensor(T, dtype=torch.float) + torch.as_tensor(S, dtype=torch.float) # Your implementation here pass diff --git a/questions/7_matrix-transformation/solution.py b/questions/7_matrix-transformation/solution.py index 08e8482d..234ad023 100644 --- a/questions/7_matrix-transformation/solution.py +++ b/questions/7_matrix-transformation/solution.py @@ -1,20 +1,23 @@ import numpy as np -def transform_matrix(A: list[list[int|float]], T: list[list[int|float]], S: list[list[int|float]]) -> list[list[int|float]]: + +def transform_matrix( + A: list[list[int | float]], T: list[list[int | float]], S: list[list[int | float]] +) -> list[list[int | float]]: # Convert to numpy arrays for easier manipulation A = np.array(A, dtype=float) T = np.array(T, dtype=float) S = np.array(S, dtype=float) - + # Check if the matrices T and S are invertible if np.linalg.det(T) == 0 or np.linalg.det(S) == 0: # raise ValueError("The matrices T and/or S are not invertible.") return -1 - + # Compute the inverse of T T_inv = np.linalg.inv(T) # Perform the matrix transformation; use @ for better readability transformed_matrix = np.round(T_inv @ A @ S, 3) - + return transformed_matrix.tolist() diff --git a/questions/7_matrix-transformation/starter_code.py b/questions/7_matrix-transformation/starter_code.py index 075d3b6d..bfac63cf 100644 --- a/questions/7_matrix-transformation/starter_code.py +++ b/questions/7_matrix-transformation/starter_code.py @@ -1,4 +1,4 @@ -import numpy as np - -def transform_matrix(A: list[list[int|float]], T: list[list[int|float]], S: list[list[int|float]]) -> list[list[int|float]]: - return transformed_matrix +def transform_matrix( + A: list[list[int | float]], T: list[list[int | float]], S: list[list[int | float]] +) -> list[list[int | float]]: + return transformed_matrix diff --git a/questions/7_matrix-transformation/tinygrad/solution.py b/questions/7_matrix-transformation/tinygrad/solution.py index 31048e70..7b103fa4 100644 --- a/questions/7_matrix-transformation/tinygrad/solution.py +++ b/questions/7_matrix-transformation/tinygrad/solution.py @@ -1,6 +1,7 @@ import numpy as np from tinygrad.tensor import Tensor + def transform_matrix_tg(A, T, S) -> Tensor: """ Perform the change-of-basis transform T⁻¹ A S for 2×2 matrices using tinygrad. @@ -11,12 +12,12 @@ def transform_matrix_tg(A, T, S) -> Tensor: T_t = Tensor(T).float() S_t = Tensor(S).float() # manual 2×2 determinant - detT = T_t[0,0]*T_t[1,1] - T_t[0,1]*T_t[1,0] - detS = S_t[0,0]*S_t[1,1] - S_t[0,1]*S_t[1,0] + detT = T_t[0, 0] * T_t[1, 1] - T_t[0, 1] * T_t[1, 0] + detS = S_t[0, 0] * S_t[1, 1] - S_t[0, 1] * S_t[1, 0] if detT.numpy() == 0 or detS.numpy() == 0: - return Tensor(-1.) + return Tensor(-1.0) # inverse of 2×2 - a,b,c,d = T_t[0,0], T_t[0,1], T_t[1,0], T_t[1,1] + a, b, c, d = T_t[0, 0], T_t[0, 1], T_t[1, 0], T_t[1, 1] T_inv = Tensor([[d, -b], [-c, a]]) / detT out = T_inv.matmul(A_t).matmul(S_t) # round via NumPy then wrap back diff --git a/questions/7_matrix-transformation/tinygrad/starter_code.py b/questions/7_matrix-transformation/tinygrad/starter_code.py index 8e24281b..b1f6680f 100644 --- a/questions/7_matrix-transformation/tinygrad/starter_code.py +++ b/questions/7_matrix-transformation/tinygrad/starter_code.py @@ -1,13 +1,14 @@ from tinygrad.tensor import Tensor + def transform_matrix_tg(A, T, S) -> Tensor: """ Perform the change-of-basis transform T⁻¹ A S for 2×2 matrices using tinygrad. Inputs A, T, S can be Python lists, NumPy arrays, or tinygrad Tensors. Returns a 2×2 Tensor or Tensor(-1.) if T or S is singular. """ - A_t = Tensor(A).float() - T_t = Tensor(T).float() - S_t = Tensor(S).float() + Tensor(A).float() + Tensor(T).float() + Tensor(S).float() # Your implementation here pass diff --git a/questions/80_normal-distribution-pdf-calculator/solution.py b/questions/80_normal-distribution-pdf-calculator/solution.py index f0d49ec9..4e06bfea 100644 --- a/questions/80_normal-distribution-pdf-calculator/solution.py +++ b/questions/80_normal-distribution-pdf-calculator/solution.py @@ -1,5 +1,6 @@ import math + def normal_pdf(x, mean, std_dev): """ Calculate the probability density function (PDF) of the normal distribution. @@ -9,5 +10,5 @@ def normal_pdf(x, mean, std_dev): :return: The PDF value for the given x. """ coefficient = 1 / (math.sqrt(2 * math.pi) * std_dev) - exponent = math.exp(-((x - mean) ** 2) / (2 * std_dev ** 2)) + exponent = math.exp(-((x - mean) ** 2) / (2 * std_dev**2)) return round(coefficient * exponent, 5) diff --git a/questions/80_normal-distribution-pdf-calculator/starter_code.py b/questions/80_normal-distribution-pdf-calculator/starter_code.py index eb259558..7e84deb5 100644 --- a/questions/80_normal-distribution-pdf-calculator/starter_code.py +++ b/questions/80_normal-distribution-pdf-calculator/starter_code.py @@ -1,12 +1,10 @@ -import math - def normal_pdf(x, mean, std_dev): - """ - Calculate the probability density function (PDF) of the normal distribution. - :param x: The value at which the PDF is evaluated. - :param mean: The mean (μ) of the distribution. - :param std_dev: The standard deviation (σ) of the distribution. - """ - # Your code here - pass - return round(val,5) + """ + Calculate the probability density function (PDF) of the normal distribution. + :param x: The value at which the PDF is evaluated. + :param mean: The mean (μ) of the distribution. + :param std_dev: The standard deviation (σ) of the distribution. + """ + # Your code here + pass + return round(val, 5) diff --git a/questions/81_poisson-distribution-probability-calculator/solution.py b/questions/81_poisson-distribution-probability-calculator/solution.py index c43e9dfe..02060981 100644 --- a/questions/81_poisson-distribution-probability-calculator/solution.py +++ b/questions/81_poisson-distribution-probability-calculator/solution.py @@ -1,5 +1,6 @@ import math + def poisson_probability(k, lam): """ Calculate the probability of observing exactly k events in a fixed interval, @@ -9,6 +10,6 @@ def poisson_probability(k, lam): :return: Probability of k events occurring """ # Calculate the Poisson probability using the formula - probability = (lam ** k) * math.exp(-lam) / math.factorial(k) + probability = (lam**k) * math.exp(-lam) / math.factorial(k) # Return the probability, rounded to five decimal places return round(probability, 5) diff --git a/questions/81_poisson-distribution-probability-calculator/starter_code.py b/questions/81_poisson-distribution-probability-calculator/starter_code.py index cf0abc0d..bc0c9039 100644 --- a/questions/81_poisson-distribution-probability-calculator/starter_code.py +++ b/questions/81_poisson-distribution-probability-calculator/starter_code.py @@ -1,12 +1,10 @@ -import math - def poisson_probability(k, lam): - """ - Calculate the probability of observing exactly k events in a fixed interval, - given the mean rate of events lam, using the Poisson distribution formula. - :param k: Number of events (non-negative integer) - :param lam: The average rate (mean) of occurrences in a fixed interval - """ - # Your code here - pass - return round(val,5) + """ + Calculate the probability of observing exactly k events in a fixed interval, + given the mean rate of events lam, using the Poisson distribution formula. + :param k: Number of events (non-negative integer) + :param lam: The average rate (mean) of occurrences in a fixed interval + """ + # Your code here + pass + return round(val, 5) diff --git a/questions/82_grayscale-image-contrast-calculator/solution.py b/questions/82_grayscale-image-contrast-calculator/solution.py index ab98171c..8d20f096 100644 --- a/questions/82_grayscale-image-contrast-calculator/solution.py +++ b/questions/82_grayscale-image-contrast-calculator/solution.py @@ -1,5 +1,6 @@ import numpy as np + def calculate_contrast(img): """ Calculate the contrast of a grayscale image. diff --git a/questions/82_grayscale-image-contrast-calculator/starter_code.py b/questions/82_grayscale-image-contrast-calculator/starter_code.py index 5f2d03be..25f07d73 100644 --- a/questions/82_grayscale-image-contrast-calculator/starter_code.py +++ b/questions/82_grayscale-image-contrast-calculator/starter_code.py @@ -1,10 +1,8 @@ -import numpy as np - def calculate_contrast(img) -> int: - """ - Calculate the contrast of a grayscale image. - Args: - img (numpy.ndarray): 2D array representing a grayscale image with pixel values between 0 and 255. - """ - # Your code here - pass + """ + Calculate the contrast of a grayscale image. + Args: + img (numpy.ndarray): 2D array representing a grayscale image with pixel values between 0 and 255. + """ + # Your code here + pass diff --git a/questions/83_dot-product-calculator/solution.py b/questions/83_dot-product-calculator/solution.py index 3adf233a..722fafd2 100644 --- a/questions/83_dot-product-calculator/solution.py +++ b/questions/83_dot-product-calculator/solution.py @@ -1,5 +1,6 @@ import numpy as np + def calculate_dot_product(vec1, vec2): """ Calculate the dot product of two vectors. diff --git a/questions/83_dot-product-calculator/starter_code.py b/questions/83_dot-product-calculator/starter_code.py index 7c6e3f29..13533d74 100644 --- a/questions/83_dot-product-calculator/starter_code.py +++ b/questions/83_dot-product-calculator/starter_code.py @@ -1,11 +1,9 @@ -import numpy as np - def calculate_dot_product(vec1, vec2) -> float: - """ - Calculate the dot product of two vectors. - Args: - vec1 (numpy.ndarray): 1D array representing the first vector. - vec2 (numpy.ndarray): 1D array representing the second vector. - """ - # Your code here - pass + """ + Calculate the dot product of two vectors. + Args: + vec1 (numpy.ndarray): 1D array representing the first vector. + vec2 (numpy.ndarray): 1D array representing the second vector. + """ + # Your code here + pass diff --git a/questions/84_phi-transformation-for-polynomial-features/solution.py b/questions/84_phi-transformation-for-polynomial-features/solution.py index 631462e1..514f317e 100644 --- a/questions/84_phi-transformation-for-polynomial-features/solution.py +++ b/questions/84_phi-transformation-for-polynomial-features/solution.py @@ -1,16 +1,17 @@ import numpy as np + def phi_transform(data: list[float], degree: int) -> list[list[float]]: - """ - Perform a Phi Transformation to map input features into a higher-dimensional space by generating polynomial features. + """ + Perform a Phi Transformation to map input features into a higher-dimensional space by generating polynomial features. - Args: - data (list[float]): A list of numerical values to transform. - degree (int): The degree of the polynomial expansion. + Args: + data (list[float]): A list of numerical values to transform. + degree (int): The degree of the polynomial expansion. - Returns: - list[list[float]]: A nested list where each inner list represents the transformed features of a data point. - """ - if degree < 0 or not data: - return [] - return np.array([[x ** i for i in range(degree + 1)] for x in data]).tolist() + Returns: + list[list[float]]: A nested list where each inner list represents the transformed features of a data point. + """ + if degree < 0 or not data: + return [] + return np.array([[x**i for i in range(degree + 1)] for x in data]).tolist() diff --git a/questions/84_phi-transformation-for-polynomial-features/starter_code.py b/questions/84_phi-transformation-for-polynomial-features/starter_code.py index d4f6ea52..7adfb3df 100644 --- a/questions/84_phi-transformation-for-polynomial-features/starter_code.py +++ b/questions/84_phi-transformation-for-polynomial-features/starter_code.py @@ -1,13 +1,11 @@ -import numpy as np - def phi_transform(data: list[float], degree: int) -> list[list[float]]: - """ - Perform a Phi Transformation to map input features into a higher-dimensional space by generating polynomial features. + """ + Perform a Phi Transformation to map input features into a higher-dimensional space by generating polynomial features. - Args: - data (list[float]): A list of numerical values to transform. - degree (int): The degree of the polynomial expansion. + Args: + data (list[float]): A list of numerical values to transform. + degree (int): The degree of the polynomial expansion. - """ - # Your code here - pass + """ + # Your code here + pass diff --git a/questions/85_positional-encoding-calculator/solution.py b/questions/85_positional-encoding-calculator/solution.py index 8be23d67..0ba4b88c 100644 --- a/questions/85_positional-encoding-calculator/solution.py +++ b/questions/85_positional-encoding-calculator/solution.py @@ -1,7 +1,7 @@ import numpy as np + def pos_encoding(position: int, d_model: int): - if position == 0 or d_model <= 0: return -1 diff --git a/questions/85_positional-encoding-calculator/starter_code.py b/questions/85_positional-encoding-calculator/starter_code.py index 950eb203..494f29b7 100644 --- a/questions/85_positional-encoding-calculator/starter_code.py +++ b/questions/85_positional-encoding-calculator/starter_code.py @@ -1,6 +1,7 @@ import numpy as np + def pos_encoding(position: int, d_model: int): - # Your code here - pos_encoding = np.float16(pos_encoding) - return pos_encoding + # Your code here + pos_encoding = np.float16(pos_encoding) + return pos_encoding diff --git a/questions/86_detect-overfitting-or-underfitting/starter_code.py b/questions/86_detect-overfitting-or-underfitting/starter_code.py index 07c9e2a5..5666b664 100644 --- a/questions/86_detect-overfitting-or-underfitting/starter_code.py +++ b/questions/86_detect-overfitting-or-underfitting/starter_code.py @@ -1,9 +1,9 @@ def model_fit_quality(training_accuracy, test_accuracy): - """ - Determine if the model is overfitting, underfitting, or a good fit based on training and test accuracy. - :param training_accuracy: float, training accuracy of the model (0 <= training_accuracy <= 1) - :param test_accuracy: float, test accuracy of the model (0 <= test_accuracy <= 1) - :return: int, one of '1', '-1', or '0'. - """ - # Your code here - pass + """ + Determine if the model is overfitting, underfitting, or a good fit based on training and test accuracy. + :param training_accuracy: float, training accuracy of the model (0 <= training_accuracy <= 1) + :param test_accuracy: float, test accuracy of the model (0 <= test_accuracy <= 1) + :return: int, one of '1', '-1', or '0'. + """ + # Your code here + pass diff --git a/questions/87_adam-optimizer/solution.py b/questions/87_adam-optimizer/solution.py index 9264cb23..c74ec039 100644 --- a/questions/87_adam-optimizer/solution.py +++ b/questions/87_adam-optimizer/solution.py @@ -1,6 +1,9 @@ import numpy as np -def adam_optimizer(parameter, grad, m, v, t, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8): + +def adam_optimizer( + parameter, grad, m, v, t, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8 +): """ Update parameters using the Adam optimizer. Adjusts the learning rate based on the moving averages of the gradient and squared gradient. @@ -31,4 +34,4 @@ def adam_optimizer(parameter, grad, m, v, t, learning_rate=0.001, beta1=0.9, bet update = learning_rate * m_hat / (np.sqrt(v_hat) + epsilon) parameter = parameter - update - return np.round(parameter,5), np.round(m,5), np.round(v,5) + return np.round(parameter, 5), np.round(m, 5), np.round(v, 5) diff --git a/questions/87_adam-optimizer/starter_code.py b/questions/87_adam-optimizer/starter_code.py index 30a72312..4839e688 100644 --- a/questions/87_adam-optimizer/starter_code.py +++ b/questions/87_adam-optimizer/starter_code.py @@ -1,19 +1,22 @@ import numpy as np -def adam_optimizer(parameter, grad, m, v, t, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8): - """ - Update parameters using the Adam optimizer. - Adjusts the learning rate based on the moving averages of the gradient and squared gradient. - :param parameter: Current parameter value - :param grad: Current gradient - :param m: First moment estimate - :param v: Second moment estimate - :param t: Current timestep - :param learning_rate: Learning rate (default=0.001) - :param beta1: First moment decay rate (default=0.9) - :param beta2: Second moment decay rate (default=0.999) - :param epsilon: Small constant for numerical stability (default=1e-8) - :return: tuple: (updated_parameter, updated_m, updated_v) - """ - # Your code here - return np.round(parameter,5), np.round(m,5), np.round(v,5) + +def adam_optimizer( + parameter, grad, m, v, t, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8 +): + """ + Update parameters using the Adam optimizer. + Adjusts the learning rate based on the moving averages of the gradient and squared gradient. + :param parameter: Current parameter value + :param grad: Current gradient + :param m: First moment estimate + :param v: Second moment estimate + :param t: Current timestep + :param learning_rate: Learning rate (default=0.001) + :param beta1: First moment decay rate (default=0.9) + :param beta2: Second moment decay rate (default=0.999) + :param epsilon: Small constant for numerical stability (default=1e-8) + :return: tuple: (updated_parameter, updated_m, updated_v) + """ + # Your code here + return np.round(parameter, 5), np.round(m, 5), np.round(v, 5) diff --git a/questions/88_gpt-2-text-generation/solution.py b/questions/88_gpt-2-text-generation/solution.py index 56f70e93..df843321 100644 --- a/questions/88_gpt-2-text-generation/solution.py +++ b/questions/88_gpt-2-text-generation/solution.py @@ -1,51 +1,64 @@ import numpy as np + def gelu(x): return 0.5 * x * (1 + np.tanh(np.sqrt(2 / np.pi) * (x + 0.044715 * x**3))) + def softmax(x): exp_x = np.exp(x - np.max(x, axis=-1, keepdims=True)) return exp_x / np.sum(exp_x, axis=-1, keepdims=True) + def layer_norm(x, g, b, eps=1e-5): mean = np.mean(x, axis=-1, keepdims=True) variance = np.var(x, axis=-1, keepdims=True) return g * (x - mean) / np.sqrt(variance + eps) + b + def linear(x, w, b): return x @ w + b + def ffn(x, c_fc, c_proj): return linear(gelu(linear(x, **c_fc)), **c_proj) + def attention(q, k, v, mask): return softmax(q @ k.T / np.sqrt(q.shape[-1]) + mask) @ v + def mha(x, c_attn, c_proj, n_head): x = linear(x, **c_attn) - qkv_heads = list(map(lambda x: np.split(x, n_head, axis=-1), np.split(x, 3, axis=-1))) + qkv_heads = list( + map(lambda x: np.split(x, n_head, axis=-1), np.split(x, 3, axis=-1)) + ) causal_mask = (1 - np.tri(x.shape[0], dtype=x.dtype)) * -1e10 out_heads = [attention(q, k, v, causal_mask) for q, k, v in zip(*qkv_heads)] x = linear(np.hstack(out_heads), **c_proj) return x + def transformer_block(x, mlp, attn, ln_1, ln_2, n_head): x = x + mha(layer_norm(x, **ln_1), **attn, n_head=n_head) x = x + ffn(layer_norm(x, **ln_2), **mlp) return x + def gpt2(inputs, wte, wpe, blocks, ln_f, n_head): x = wte[inputs] + wpe[range(len(inputs))] for block in blocks: x = transformer_block(x, **block, n_head=n_head) return layer_norm(x, **ln_f) @ wte.T + def generate(inputs, params, n_head, n_tokens_to_generate): for _ in range(n_tokens_to_generate): logits = gpt2(inputs, **params, n_head=n_head) next_id = np.argmax(logits[-1]) inputs.append(int(next_id)) - return inputs[len(inputs) - n_tokens_to_generate:] + return inputs[len(inputs) - n_tokens_to_generate :] + def gen_text(prompt: str, n_tokens_to_generate: int = 40): np.random.seed(42) # Set the random seed for reproducibility diff --git a/questions/88_gpt-2-text-generation/starter_code.py b/questions/88_gpt-2-text-generation/starter_code.py index 8d977c38..0955dc27 100644 --- a/questions/88_gpt-2-text-generation/starter_code.py +++ b/questions/88_gpt-2-text-generation/starter_code.py @@ -1,34 +1,39 @@ def gen_text(prompt: str, n_tokens_to_generate: int = 40): - ####your code goes here#### - pass + ####your code goes here#### + pass -def load_encoder_hparams_and_params(model_size: str = "124M", models_dir: str = "models"): - class DummyBPE: - def __init__(self): - self.encoder_dict = {"hello": 1, "world": 2, "": 0} - def encode(self, text: str): - tokens = text.strip().split() - return [self.encoder_dict.get(token, self.encoder_dict[""]) for token in tokens] +def load_encoder_hparams_and_params( + model_size: str = "124M", models_dir: str = "models" +): + class DummyBPE: + def __init__(self): + self.encoder_dict = {"hello": 1, "world": 2, "": 0} - def decode(self, token_ids: list): - reversed_dict = {v: k for k, v in self.encoder_dict.items()} - return " ".join([reversed_dict.get(tok_id, "") for tok_id in token_ids]) + def encode(self, text: str): + tokens = text.strip().split() + return [ + self.encoder_dict.get(token, self.encoder_dict[""]) + for token in tokens + ] - hparams = { - "n_ctx": 1024, - "n_head": 12 - } + def decode(self, token_ids: list): + reversed_dict = {v: k for k, v in self.encoder_dict.items()} + return " ".join( + [reversed_dict.get(tok_id, "") for tok_id in token_ids] + ) - params = { - "wte": np.random.rand(3, 10), - "wpe": np.random.rand(1024, 10), - "blocks": [], - "ln_f": { - "g": np.ones(10), - "b": np.zeros(10), - } - } + hparams = {"n_ctx": 1024, "n_head": 12} - encoder = DummyBPE() - return encoder, hparams, params + params = { + "wte": np.random.rand(3, 10), + "wpe": np.random.rand(1024, 10), + "blocks": [], + "ln_f": { + "g": np.ones(10), + "b": np.zeros(10), + }, + } + + encoder = DummyBPE() + return encoder, hparams, params diff --git a/questions/89_the-pattern-weaver-s-code/solution.py b/questions/89_the-pattern-weaver-s-code/solution.py index 153b61e5..770083b1 100644 --- a/questions/89_the-pattern-weaver-s-code/solution.py +++ b/questions/89_the-pattern-weaver-s-code/solution.py @@ -1,9 +1,11 @@ import numpy as np + def softmax(values): exps = np.exp(values - np.max(values)) return exps / np.sum(exps) + def pattern_weaver(n, crystal_values, dimension): dimension_sqrt = np.sqrt(dimension) final_patterns = [] diff --git a/questions/89_the-pattern-weaver-s-code/starter_code.py b/questions/89_the-pattern-weaver-s-code/starter_code.py index 0c458d41..c5a40387 100644 --- a/questions/89_the-pattern-weaver-s-code/starter_code.py +++ b/questions/89_the-pattern-weaver-s-code/starter_code.py @@ -1,9 +1,11 @@ import numpy as np + def softmax(values): - # Implement the softmax function - pass + # Implement the softmax function + pass + def pattern_weaver(n, crystal_values, dimension): - # Your code here - return np.round(x,3) + # Your code here + return np.round(x, 3) diff --git a/questions/8_calculate-2x2-matrix-inverse/pytorch/solution.py b/questions/8_calculate-2x2-matrix-inverse/pytorch/solution.py index 71bd48d9..8eb71366 100644 --- a/questions/8_calculate-2x2-matrix-inverse/pytorch/solution.py +++ b/questions/8_calculate-2x2-matrix-inverse/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def inverse_2x2(matrix) -> torch.Tensor | None: """ Compute inverse of a 2×2 matrix using PyTorch. @@ -7,13 +8,12 @@ def inverse_2x2(matrix) -> torch.Tensor | None: Returns a 2×2 tensor or None if the matrix is singular. """ m = torch.as_tensor(matrix, dtype=torch.float) - a, b = m[0,0], m[0,1] - c, d = m[1,0], m[1,1] + a, b = m[0, 0], m[0, 1] + c, d = m[1, 0], m[1, 1] det = a * d - b * c if det == 0: return None - inv = torch.stack([ - torch.stack([ d/det, -b/det]), - torch.stack([-c/det, a/det]) - ]) + inv = torch.stack( + [torch.stack([d / det, -b / det]), torch.stack([-c / det, a / det])] + ) return inv diff --git a/questions/8_calculate-2x2-matrix-inverse/pytorch/starter_code.py b/questions/8_calculate-2x2-matrix-inverse/pytorch/starter_code.py index fdcf698c..cf2168b0 100644 --- a/questions/8_calculate-2x2-matrix-inverse/pytorch/starter_code.py +++ b/questions/8_calculate-2x2-matrix-inverse/pytorch/starter_code.py @@ -1,11 +1,12 @@ import torch + def inverse_2x2(matrix) -> torch.Tensor | None: """ Compute inverse of a 2×2 matrix using PyTorch. Input can be Python list, NumPy array, or torch Tensor. Returns a 2×2 tensor or None if the matrix is singular. """ - m = torch.as_tensor(matrix, dtype=torch.float) + torch.as_tensor(matrix, dtype=torch.float) # Your implementation here pass diff --git a/questions/8_calculate-2x2-matrix-inverse/solution.py b/questions/8_calculate-2x2-matrix-inverse/solution.py index bb81ec34..5981ae28 100644 --- a/questions/8_calculate-2x2-matrix-inverse/solution.py +++ b/questions/8_calculate-2x2-matrix-inverse/solution.py @@ -3,5 +3,5 @@ def inverse_2x2(matrix: list[list[float]]) -> list[list[float]]: determinant = a * d - b * c if determinant == 0: return None - inverse = [[d/determinant, -b/determinant], [-c/determinant, a/determinant]] + inverse = [[d / determinant, -b / determinant], [-c / determinant, a / determinant]] return inverse diff --git a/questions/8_calculate-2x2-matrix-inverse/starter_code.py b/questions/8_calculate-2x2-matrix-inverse/starter_code.py index 7fd34bd1..b143d0da 100644 --- a/questions/8_calculate-2x2-matrix-inverse/starter_code.py +++ b/questions/8_calculate-2x2-matrix-inverse/starter_code.py @@ -1,2 +1,2 @@ def inverse_2x2(matrix: list[list[float]]) -> list[list[float]]: - return inverse + return inverse diff --git a/questions/8_calculate-2x2-matrix-inverse/tinygrad/solution.py b/questions/8_calculate-2x2-matrix-inverse/tinygrad/solution.py index a3b5e97b..dea96bc6 100644 --- a/questions/8_calculate-2x2-matrix-inverse/tinygrad/solution.py +++ b/questions/8_calculate-2x2-matrix-inverse/tinygrad/solution.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def inverse_2x2_tg(matrix) -> Tensor | None: """ Compute inverse of a 2×2 matrix using tinygrad. @@ -7,10 +8,10 @@ def inverse_2x2_tg(matrix) -> Tensor | None: Returns a 2×2 Tensor or None if the matrix is singular. """ m = Tensor(matrix).float() - a, b = m[0,0], m[0,1] - c, d = m[1,0], m[1,1] + a, b = m[0, 0], m[0, 1] + c, d = m[1, 0], m[1, 1] det = a * d - b * c if det.numpy() == 0: return None - inv = Tensor([[ d, -b], [-c, a]]) / det + inv = Tensor([[d, -b], [-c, a]]) / det return inv diff --git a/questions/8_calculate-2x2-matrix-inverse/tinygrad/starter_code.py b/questions/8_calculate-2x2-matrix-inverse/tinygrad/starter_code.py index cbd9226d..80c50294 100644 --- a/questions/8_calculate-2x2-matrix-inverse/tinygrad/starter_code.py +++ b/questions/8_calculate-2x2-matrix-inverse/tinygrad/starter_code.py @@ -1,11 +1,12 @@ from tinygrad.tensor import Tensor + def inverse_2x2_tg(matrix) -> Tensor | None: """ Compute inverse of a 2×2 matrix using tinygrad. Input can be Python list, NumPy array, or tinygrad Tensor. Returns a 2×2 Tensor or None if the matrix is singular. """ - m = Tensor(matrix).float() + Tensor(matrix).float() # Your implementation here pass diff --git a/questions/90_bm25-ranking/solution.py b/questions/90_bm25-ranking/solution.py index 5182ab96..c8abeaf4 100644 --- a/questions/90_bm25-ranking/solution.py +++ b/questions/90_bm25-ranking/solution.py @@ -1,6 +1,7 @@ import numpy as np from collections import Counter + def calculate_bm25_scores(corpus, query, k1=1.5, b=0.75): if not corpus or not query: raise ValueError("Corpus and query cannot be empty") diff --git a/questions/90_bm25-ranking/starter_code.py b/questions/90_bm25-ranking/starter_code.py index 1f2482ed..b80bdded 100644 --- a/questions/90_bm25-ranking/starter_code.py +++ b/questions/90_bm25-ranking/starter_code.py @@ -1,7 +1,7 @@ import numpy as np -from collections import Counter + def calculate_bm25_scores(corpus, query, k1=1.5, b=0.75): - # Your code here - pass - return np.round(scores,3) + # Your code here + pass + return np.round(scores, 3) diff --git a/questions/91_calculate-f1-score-from-predicted-and-true-labels/starter_code.py b/questions/91_calculate-f1-score-from-predicted-and-true-labels/starter_code.py index f803bd87..ae531524 100644 --- a/questions/91_calculate-f1-score-from-predicted-and-true-labels/starter_code.py +++ b/questions/91_calculate-f1-score-from-predicted-and-true-labels/starter_code.py @@ -1,14 +1,14 @@ def calculate_f1_score(y_true, y_pred): - """ - Calculate the F1 score based on true and predicted labels. + """ + Calculate the F1 score based on true and predicted labels. - Args: - y_true (list): True labels (ground truth). - y_pred (list): Predicted labels. + Args: + y_true (list): True labels (ground truth). + y_pred (list): Predicted labels. - Returns: - float: The F1 score rounded to three decimal places. - """ - # Your code here - pass - return round(f1,3) + Returns: + float: The F1 score rounded to three decimal places. + """ + # Your code here + pass + return round(f1, 3) diff --git a/questions/92_linear-regression-power-grid-optimization/solution.py b/questions/92_linear-regression-power-grid-optimization/solution.py index e70e2e9f..a1d72e4a 100644 --- a/questions/92_linear-regression-power-grid-optimization/solution.py +++ b/questions/92_linear-regression-power-grid-optimization/solution.py @@ -2,6 +2,7 @@ PI = 3.14159 + def power_grid_forecast(consumption_data): # consumption_data: list of 10 daily consumption values # days: 1 through 10 diff --git a/questions/92_linear-regression-power-grid-optimization/starter_code.py b/questions/92_linear-regression-power-grid-optimization/starter_code.py index ed373110..5c8a1b56 100644 --- a/questions/92_linear-regression-power-grid-optimization/starter_code.py +++ b/questions/92_linear-regression-power-grid-optimization/starter_code.py @@ -1,12 +1,11 @@ -import math - PI = 3.14159 + def power_grid_forecast(consumption_data): - # 1) Subtract the daily fluctuation (10 * sin(2π * i / 10)) from each data point. - # 2) Perform linear regression on the detrended data. - # 3) Predict day 15's base consumption. - # 4) Add the day 15 fluctuation back. - # 5) Round, then add a 5% safety margin (rounded up). - # 6) Return the final integer. - pass + # 1) Subtract the daily fluctuation (10 * sin(2π * i / 10)) from each data point. + # 2) Perform linear regression on the detrended data. + # 3) Predict day 15's base consumption. + # 4) Add the day 15 fluctuation back. + # 5) Round, then add a 5% safety margin (rounded up). + # 6) Return the final integer. + pass diff --git a/questions/93_calculate-mean-absolute-error-mae/solution.py b/questions/93_calculate-mean-absolute-error-mae/solution.py index 090fd72a..e2076f3b 100644 --- a/questions/93_calculate-mean-absolute-error-mae/solution.py +++ b/questions/93_calculate-mean-absolute-error-mae/solution.py @@ -1,5 +1,6 @@ import numpy as np + def mae(y_true, y_pred): """ Calculate Mean Absolute Error between two arrays. diff --git a/questions/93_calculate-mean-absolute-error-mae/starter_code.py b/questions/93_calculate-mean-absolute-error-mae/starter_code.py index 77758060..366af9df 100644 --- a/questions/93_calculate-mean-absolute-error-mae/starter_code.py +++ b/questions/93_calculate-mean-absolute-error-mae/starter_code.py @@ -1,16 +1,14 @@ -import numpy as np - def mae(y_true, y_pred): - """ - Calculate Mean Absolute Error between two arrays. + """ + Calculate Mean Absolute Error between two arrays. - Parameters: - y_true (numpy.ndarray): Array of true values + Parameters: + y_true (numpy.ndarray): Array of true values y_pred (numpy.ndarray): Array of predicted values - Returns: - float: Mean Absolute Error rounded to 3 decimal places - """ - # Your code here - pass - return round(val,3) + Returns: + float: Mean Absolute Error rounded to 3 decimal places + """ + # Your code here + pass + return round(val, 3) diff --git a/questions/94_implement-multi-head-attention/solution.py b/questions/94_implement-multi-head-attention/solution.py index 19250794..16cbed38 100644 --- a/questions/94_implement-multi-head-attention/solution.py +++ b/questions/94_implement-multi-head-attention/solution.py @@ -1,14 +1,17 @@ import numpy as np -from typing import Tuple, List +from typing import Tuple -def compute_qkv(X: np.ndarray, W_q: np.ndarray, W_k: np.ndarray, W_v: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + +def compute_qkv( + X: np.ndarray, W_q: np.ndarray, W_k: np.ndarray, W_v: np.ndarray +) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: """ Compute the Query (Q), Key (K), and Value (V) matrices. - + Args: X: numpy array of shape (seq_len, d_model), input sequence W_q, W_k, W_v: numpy arrays of shape (d_model, d_model), weight matrices for Q, K, and V - + Returns: Q, K, V: numpy arrays of shape (seq_len, d_model) """ @@ -17,33 +20,45 @@ def compute_qkv(X: np.ndarray, W_q: np.ndarray, W_k: np.ndarray, W_v: np.ndarray V = np.dot(X, W_v) # Compute the Value matrix V return Q, K, V + def self_attention(Q: np.ndarray, K: np.ndarray, V: np.ndarray) -> np.ndarray: """ Compute self-attention for a single head. - + Args: Q: numpy array of shape (seq_len, d_k), Query matrix K: numpy array of shape (seq_len, d_k), Key matrix V: numpy array of shape (seq_len, d_k), Value matrix - + Returns: attention_output: numpy array of shape (seq_len, d_k), output of the self-attention mechanism """ d_k = Q.shape[1] # Get the dimension of the keys - scores = np.matmul(Q, K.T) / np.sqrt(d_k) # Compute scaled dot-product attention scores - score_max = np.max(scores, axis=1, keepdims=True) # Find the maximum score for numerical stability - attention_weights = np.exp(scores - score_max) / np.sum(np.exp(scores - score_max), axis=1, keepdims=True) # Compute softmax to get attention weights - attention_output = np.matmul(attention_weights, V) # Compute the final attention output + scores = np.matmul(Q, K.T) / np.sqrt( + d_k + ) # Compute scaled dot-product attention scores + score_max = np.max( + scores, axis=1, keepdims=True + ) # Find the maximum score for numerical stability + attention_weights = np.exp(scores - score_max) / np.sum( + np.exp(scores - score_max), axis=1, keepdims=True + ) # Compute softmax to get attention weights + attention_output = np.matmul( + attention_weights, V + ) # Compute the final attention output return attention_output -def multi_head_attention(Q: np.ndarray, K: np.ndarray, V: np.ndarray, n_heads: int) -> np.ndarray: + +def multi_head_attention( + Q: np.ndarray, K: np.ndarray, V: np.ndarray, n_heads: int +) -> np.ndarray: """ Compute multi-head attention. - + Args: Q, K, V: numpy arrays of shape (seq_len, d_model), Query, Key, and Value matrices n_heads: int, number of attention heads - + Returns: attention_output: numpy array of shape (seq_len, d_model), final attention output """ @@ -52,17 +67,27 @@ def multi_head_attention(Q: np.ndarray, K: np.ndarray, V: np.ndarray, n_heads: i d_k = d_model // n_heads # Dimension for each head # Reshape Q, K, V to separate heads - Q_reshaped = Q.reshape(Q.shape[0], n_heads, d_k).transpose(1, 0, 2) # Reshape and transpose to (n_heads, seq_len, d_k) - K_reshaped = K.reshape(K.shape[0], n_heads, d_k).transpose(1, 0, 2) # Reshape and transpose to (n_heads, seq_len, d_k) - V_reshaped = V.reshape(V.shape[0], n_heads, d_k).transpose(1, 0, 2) # Reshape and transpose to (n_heads, seq_len, d_k) + Q_reshaped = Q.reshape(Q.shape[0], n_heads, d_k).transpose( + 1, 0, 2 + ) # Reshape and transpose to (n_heads, seq_len, d_k) + K_reshaped = K.reshape(K.shape[0], n_heads, d_k).transpose( + 1, 0, 2 + ) # Reshape and transpose to (n_heads, seq_len, d_k) + V_reshaped = V.reshape(V.shape[0], n_heads, d_k).transpose( + 1, 0, 2 + ) # Reshape and transpose to (n_heads, seq_len, d_k) # Compute attention scores for each head attentions = [] # Store attention outputs for each head for i in range(n_heads): - attn = self_attention(Q_reshaped[i], K_reshaped[i], V_reshaped[i]) # Compute attention for the i-th head + attn = self_attention( + Q_reshaped[i], K_reshaped[i], V_reshaped[i] + ) # Compute attention for the i-th head attentions.append(attn) # Collect attention output # Concatenate all head outputs - attention_output = np.concatenate(attentions, axis=-1) # Concatenate along the last axis (columns) + attention_output = np.concatenate( + attentions, axis=-1 + ) # Concatenate along the last axis (columns) return attention_output # Return the final attention output diff --git a/questions/94_implement-multi-head-attention/starter_code.py b/questions/94_implement-multi-head-attention/starter_code.py index d6a92880..a58052a4 100644 --- a/questions/94_implement-multi-head-attention/starter_code.py +++ b/questions/94_implement-multi-head-attention/starter_code.py @@ -1,10 +1,10 @@ -import numpy as np - def compute_qkv(X, W_q, W_k, W_v): - pass + pass + def self_attention(Q, K, V): - pass + pass + def multi_head_attention(Q, K, V, n_heads): - pass + pass diff --git a/questions/95_calculate-the-phi-coefficient/starter_code.py b/questions/95_calculate-the-phi-coefficient/starter_code.py index 59b46f08..e30a69cb 100644 --- a/questions/95_calculate-the-phi-coefficient/starter_code.py +++ b/questions/95_calculate-the-phi-coefficient/starter_code.py @@ -1,14 +1,14 @@ def phi_corr(x: list[int], y: list[int]) -> float: - """ - Calculate the Phi coefficient between two binary variables. + """ + Calculate the Phi coefficient between two binary variables. - Args: - x (list[int]): A list of binary values (0 or 1). - y (list[int]): A list of binary values (0 or 1). + Args: + x (list[int]): A list of binary values (0 or 1). + y (list[int]): A list of binary values (0 or 1). - Returns: - float: The Phi coefficient rounded to 4 decimal places. - """ - # Your code here - pass - return round(val,4) + Returns: + float: The Phi coefficient rounded to 4 decimal places. + """ + # Your code here + pass + return round(val, 4) diff --git a/questions/96_implement-the-hard-sigmoid-activation-function/starter_code.py b/questions/96_implement-the-hard-sigmoid-activation-function/starter_code.py index 235b390a..418bd8ae 100644 --- a/questions/96_implement-the-hard-sigmoid-activation-function/starter_code.py +++ b/questions/96_implement-the-hard-sigmoid-activation-function/starter_code.py @@ -1,12 +1,12 @@ def hard_sigmoid(x: float) -> float: - """ - Implements the Hard Sigmoid activation function. + """ + Implements the Hard Sigmoid activation function. - Args: - x (float): Input value + Args: + x (float): Input value - Returns: - float: The Hard Sigmoid of the input - """ - # Your code here - pass + Returns: + float: The Hard Sigmoid of the input + """ + # Your code here + pass diff --git a/questions/97_implement-the-elu-activation-function/solution.py b/questions/97_implement-the-elu-activation-function/solution.py index bcabbec6..2479b2ee 100644 --- a/questions/97_implement-the-elu-activation-function/solution.py +++ b/questions/97_implement-the-elu-activation-function/solution.py @@ -1,5 +1,6 @@ import math + def elu(x: float, alpha: float = 1.0) -> float: """ Compute the ELU activation function. @@ -11,4 +12,4 @@ def elu(x: float, alpha: float = 1.0) -> float: Returns: float: ELU activation value """ - return round(x if x > 0 else alpha * (math.exp(x) - 1),4) + return round(x if x > 0 else alpha * (math.exp(x) - 1), 4) diff --git a/questions/97_implement-the-elu-activation-function/starter_code.py b/questions/97_implement-the-elu-activation-function/starter_code.py index 2e3b9416..7ad87493 100644 --- a/questions/97_implement-the-elu-activation-function/starter_code.py +++ b/questions/97_implement-the-elu-activation-function/starter_code.py @@ -1,14 +1,14 @@ def elu(x: float, alpha: float = 1.0) -> float: - """ - Compute the ELU activation function. + """ + Compute the ELU activation function. - Args: - x (float): Input value - alpha (float): ELU parameter for negative values (default: 1.0) + Args: + x (float): Input value + alpha (float): ELU parameter for negative values (default: 1.0) - Returns: - float: ELU activation value - """ - # Your code here - pass - return round(val,4) + Returns: + float: ELU activation value + """ + # Your code here + pass + return round(val, 4) diff --git a/questions/98_implement-the-prelu-activation-function/starter_code.py b/questions/98_implement-the-prelu-activation-function/starter_code.py index 7fd1049a..ae3ed547 100644 --- a/questions/98_implement-the-prelu-activation-function/starter_code.py +++ b/questions/98_implement-the-prelu-activation-function/starter_code.py @@ -1,13 +1,13 @@ def prelu(x: float, alpha: float = 0.25) -> float: - """ - Implements the PReLU (Parametric ReLU) activation function. + """ + Implements the PReLU (Parametric ReLU) activation function. - Args: - x: Input value - alpha: Slope parameter for negative values (default: 0.25) + Args: + x: Input value + alpha: Slope parameter for negative values (default: 0.25) - Returns: - float: PReLU activation value - """ - # Your code here - pass + Returns: + float: PReLU activation value + """ + # Your code here + pass diff --git a/questions/99_implement-the-softplus-activation-function/solution.py b/questions/99_implement-the-softplus-activation-function/solution.py index fd955bc7..13a70c0f 100644 --- a/questions/99_implement-the-softplus-activation-function/solution.py +++ b/questions/99_implement-the-softplus-activation-function/solution.py @@ -1,5 +1,6 @@ import math + def softplus(x: float) -> float: """ Compute the softplus activation function. @@ -17,4 +18,4 @@ def softplus(x: float) -> float: if x < -100: return 0.0 - return round (math.log(1.0 + math.exp(x)),4) + return round(math.log(1.0 + math.exp(x)), 4) diff --git a/questions/99_implement-the-softplus-activation-function/starter_code.py b/questions/99_implement-the-softplus-activation-function/starter_code.py index 7da7016c..80ccdbaa 100644 --- a/questions/99_implement-the-softplus-activation-function/starter_code.py +++ b/questions/99_implement-the-softplus-activation-function/starter_code.py @@ -10,4 +10,4 @@ def softplus(x: float) -> float: """ # Your code here pass - return round(val,4) + return round(val,4) diff --git a/questions/9_matrix-times-matrix/pytorch/solution.py b/questions/9_matrix-times-matrix/pytorch/solution.py index 5947bf61..81b77fe2 100644 --- a/questions/9_matrix-times-matrix/pytorch/solution.py +++ b/questions/9_matrix-times-matrix/pytorch/solution.py @@ -1,5 +1,6 @@ import torch + def matrixmul(a, b) -> torch.Tensor: """ Multiply two matrices using PyTorch. diff --git a/questions/9_matrix-times-matrix/pytorch/starter_code.py b/questions/9_matrix-times-matrix/pytorch/starter_code.py index c33a93b3..e1d50d18 100644 --- a/questions/9_matrix-times-matrix/pytorch/starter_code.py +++ b/questions/9_matrix-times-matrix/pytorch/starter_code.py @@ -1,5 +1,6 @@ import torch + def matrixmul(a, b) -> torch.Tensor: """ Multiply two matrices using PyTorch. diff --git a/questions/9_matrix-times-matrix/solution.py b/questions/9_matrix-times-matrix/solution.py index 82c5891c..a4e7baef 100644 --- a/questions/9_matrix-times-matrix/solution.py +++ b/questions/9_matrix-times-matrix/solution.py @@ -1,9 +1,9 @@ - -def matrixmul(a:list[list[int|float]], - b:list[list[int|float]])-> list[list[int|float]]: +def matrixmul( + a: list[list[int | float]], b: list[list[int | float]] +) -> list[list[int | float]]: if len(a[0]) != len(b): return -1 - + vals = [] for i in range(len(a)): hold = [] @@ -11,7 +11,7 @@ def matrixmul(a:list[list[int|float]], val = 0 for k in range(len(b)): val += a[i][k] * b[k][j] - + hold.append(val) vals.append(hold) diff --git a/questions/9_matrix-times-matrix/starter_code.py b/questions/9_matrix-times-matrix/starter_code.py index ce18d76e..0f6c098d 100644 --- a/questions/9_matrix-times-matrix/starter_code.py +++ b/questions/9_matrix-times-matrix/starter_code.py @@ -1,3 +1,4 @@ -def matrixmul(a:list[list[int|float]], - b:list[list[int|float]])-> list[list[int|float]]: - return c +def matrixmul( + a: list[list[int | float]], b: list[list[int | float]] +) -> list[list[int | float]]: + return c diff --git a/questions/9_matrix-times-matrix/tinygrad/solution.py b/questions/9_matrix-times-matrix/tinygrad/solution.py index 29ac51be..f437be1e 100644 --- a/questions/9_matrix-times-matrix/tinygrad/solution.py +++ b/questions/9_matrix-times-matrix/tinygrad/solution.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def matrixmul_tg(a, b) -> Tensor: """ Multiply two matrices using tinygrad. diff --git a/questions/9_matrix-times-matrix/tinygrad/starter_code.py b/questions/9_matrix-times-matrix/tinygrad/starter_code.py index e1f41794..b18b9e09 100644 --- a/questions/9_matrix-times-matrix/tinygrad/starter_code.py +++ b/questions/9_matrix-times-matrix/tinygrad/starter_code.py @@ -1,5 +1,6 @@ from tinygrad.tensor import Tensor + def matrixmul_tg(a, b) -> Tensor: """ Multiply two matrices using tinygrad. diff --git a/questions/_template/tinygrad/starter_code.py b/questions/_template/tinygrad/starter_code.py index d3e5beb5..22c1b928 100644 --- a/questions/_template/tinygrad/starter_code.py +++ b/questions/_template/tinygrad/starter_code.py @@ -1,2 +1,2 @@ -def your_function(...): +def your_function(): pass diff --git a/utils/build_bundle.py b/utils/build_bundle.py index 0edf110b..e05136d2 100644 --- a/utils/build_bundle.py +++ b/utils/build_bundle.py @@ -3,29 +3,35 @@ Walk questions/* folders → emit build/.json bundles. """ -import json, pathlib, re +import json +import pathlib -ROOT = pathlib.Path("questions") +ROOT = pathlib.Path("questions") OUTDIR = pathlib.Path("build") OUTDIR.mkdir(exist_ok=True) -def load_text(p): return p.read_text(encoding="utf-8").rstrip("\n") -def load_json(p): return json.loads(load_text(p)) + +def load_text(p): + return p.read_text(encoding="utf-8").rstrip("\n") + + +def load_json(p): + return json.loads(load_text(p)) + def bundle_one(folder: pathlib.Path): meta = load_json(folder / "meta.json") - meta["description"] = load_text(folder / "description.md") + meta["description"] = load_text(folder / "description.md") meta["learn_section"] = load_text(folder / "learn.md") - meta["starter_code"] = load_text(folder / "starter_code.py") - meta["solution"] = load_text(folder / "solution.py") - meta["example"] = load_json(folder / "example.json") - meta["test_cases"] = load_json(folder / "tests.json") + meta["starter_code"] = load_text(folder / "starter_code.py") + meta["solution"] = load_text(folder / "solution.py") + meta["example"] = load_json(folder / "example.json") + meta["test_cases"] = load_json(folder / "tests.json") if "marimo_link" in meta: meta["marimo_link"] = meta["marimo_link"] - for lang in ("tinygrad", "pytorch"): sub = folder / lang if sub.exists(): @@ -40,9 +46,13 @@ def bundle_one(folder: pathlib.Path): out_path.write_text(json.dumps(meta, indent=2, ensure_ascii=False)) print(f"✓ bundled {out_path.name}") + def main(): - for qdir in sorted(p for p in ROOT.iterdir() if p.is_dir() and not p.name.startswith('_')): + for qdir in sorted( + p for p in ROOT.iterdir() if p.is_dir() and not p.name.startswith("_") + ): bundle_one(qdir) + if __name__ == "__main__": main() diff --git a/utils/make_question_template.py b/utils/make_question_template.py index 9eb1516c..a93b73ed 100644 --- a/utils/make_question_template.py +++ b/utils/make_question_template.py @@ -1,14 +1,17 @@ #!/usr/bin/env python -import json, pathlib, textwrap +import json +import pathlib TEMPLATE = pathlib.Path("questions/_template") -LANGS = ["tinygrad", "pytorch"] +LANGS = ["tinygrad", "pytorch"] + def w(path, txt): path.parent.mkdir(parents=True, exist_ok=True) if not path.exists(): path.write_text(txt.rstrip() + "\n") + def main(): META = { "id": "XXX", @@ -20,21 +23,36 @@ def main(): "dislikes": "0", "contributor": [], "tinygrad_difficulty": "", - "pytorch_difficulty": "" + "pytorch_difficulty": "", } w(TEMPLATE / "meta.json", json.dumps(META, indent=2)) w(TEMPLATE / "description.md", "## Problem\n\nDescribe the task.") - w(TEMPLATE / "learn.md", "## Solution Explanation\n\nExplain here.") - w(TEMPLATE / "starter_code.py","def your_function(...):\n pass") - w(TEMPLATE / "solution.py", "def your_function(...):\n ...") - w(TEMPLATE / "example.json", json.dumps({"input":"...", "output":"...", "reasoning":"..."}, indent=2)) - w(TEMPLATE / "tests.json", json.dumps([{"test":"print(your_function(...))","expected_output":"..."}], indent=2)) + w(TEMPLATE / "learn.md", "## Solution Explanation\n\nExplain here.") + w(TEMPLATE / "starter_code.py", "def your_function(...):\n pass") + w(TEMPLATE / "solution.py", "def your_function(...):\n ...") + w( + TEMPLATE / "example.json", + json.dumps({"input": "...", "output": "...", "reasoning": "..."}, indent=2), + ) + w( + TEMPLATE / "tests.json", + json.dumps( + [{"test": "print(your_function(...))", "expected_output": "..."}], indent=2 + ), + ) for lang in LANGS: sub = TEMPLATE / lang w(sub / "starter_code.py", "def your_function(...):\n pass") - w(sub / "solution.py", "def your_function(...):\n ...") - w(sub / "tests.json", json.dumps([{"test":"print(your_function(...))","expected_output":"..."}], indent=2)) + w(sub / "solution.py", "def your_function(...):\n ...") + w( + sub / "tests.json", + json.dumps( + [{"test": "print(your_function(...))", "expected_output": "..."}], + indent=2, + ), + ) print("Template ready at questions/_template/") + if __name__ == "__main__": main() diff --git a/utils/validate_questions.py b/utils/validate_questions.py index 1f13d3e0..ef269bb8 100644 --- a/utils/validate_questions.py +++ b/utils/validate_questions.py @@ -60,6 +60,7 @@ def validate_file(validator: Draft7Validator, fp: pathlib.Path) -> bool: print(f"✓ {fp.name}") return True + def main(): schema = load_schema() validator = Draft7Validator(schema) @@ -86,5 +87,6 @@ def main(): sys.exit(0 if ok else 1) + if __name__ == "__main__": main()