Implement comprehensive inline testing for Tensor module

- Replace basic inline tests with comprehensive educational tests
- Add thorough tensor creation testing (8 test cases)
- Add comprehensive property testing (6 test cases)
- Add complete arithmetic testing (8 test cases)
- Add ML integration test with realistic scenarios
- Provide detailed feedback, hints, and progress tracking
- Follow inline-first testing approach for immediate feedback
This commit is contained in:
Vijay Janapa Reddi
2025-07-12 19:39:07 -04:00
parent 1d3314add5
commit 00169e266b

View File

@@ -440,198 +440,604 @@ class Tensor:
# %% [markdown]
"""
### 🧪 Quick Test: Tensor Creation
### 🧪 Unit Test: Tensor Creation
Let's test your tensor creation implementation right away! This gives you immediate feedback on whether your `__init__` method works correctly.
**This is a unit test** - it tests one specific function (tensor creation) in isolation.
"""
# %% nbgrader={"grade": true, "grade_id": "test-tensor-creation-immediate", "locked": true, "points": 10, "schema_version": 3, "solution": false, "task": false}
# Test tensor creation immediately after implementation
print("🔬 Testing tensor creation...")
# Test scalar
try:
scalar = Tensor(5.0)
print(f"✅ Scalar creation: {scalar}")
assert hasattr(scalar, '_data'), "Tensor should have _data attribute"
assert scalar._data.shape == (), f"Scalar should have shape (), got {scalar._data.shape}"
except Exception as e:
print(f"❌ Scalar creation failed: {e}")
raise
# Test list
try:
vector = Tensor([1, 2, 3])
print(f"✅ Vector creation: {vector}")
assert vector._data.shape == (3,), f"Vector should have shape (3,), got {vector._data.shape}"
except Exception as e:
print(f"❌ Vector creation failed: {e}")
raise
# Test matrix
try:
matrix = Tensor([[1, 2], [3, 4]])
print(f"✅ Matrix creation: {matrix}")
assert matrix._data.shape == (2, 2), f"Matrix should have shape (2, 2), got {matrix._data.shape}"
except Exception as e:
print(f"❌ Matrix creation failed: {e}")
raise
print("🎉 Tensor creation works! You can create scalars, vectors, and matrices.")
print("📈 Progress: Tensor creation ✓")
# %% [markdown]
"""
### 🧪 Quick Test: Tensor Properties
### 🧪 Comprehensive Test: Tensor Creation
Now let's test the tensor properties (shape, size, dtype, data access) to make sure they work correctly.
Let's thoroughly test your tensor creation to make sure it handles all the cases you'll encounter in ML.
This tests the foundation of everything else we'll build.
"""
# %% nbgrader={"grade": true, "grade_id": "test-tensor-properties-immediate", "locked": true, "points": 10, "schema_version": 3, "solution": false, "task": false}
# Test tensor properties immediately after implementation
print("🔬 Testing tensor properties...")
# %% nbgrader={"grade": true, "grade_id": "test-tensor-creation-comprehensive", "locked": true, "points": 15, "schema_version": 3, "solution": false, "task": false}
def test_tensor_creation_comprehensive():
"""Comprehensive test of tensor creation with all data types and shapes."""
print("🔬 Testing comprehensive tensor creation...")
tests_passed = 0
total_tests = 8
# Test 1: Scalar creation (0D tensor)
try:
scalar_int = Tensor(42)
scalar_float = Tensor(3.14)
scalar_zero = Tensor(0)
assert hasattr(scalar_int, '_data'), "Tensor should have _data attribute"
assert scalar_int._data.shape == (), f"Scalar should have shape (), got {scalar_int._data.shape}"
assert scalar_float._data.shape == (), f"Float scalar should have shape (), got {scalar_float._data.shape}"
assert scalar_zero._data.shape == (), f"Zero scalar should have shape (), got {scalar_zero._data.shape}"
print("✅ Scalar creation: integers, floats, and zero")
tests_passed += 1
except Exception as e:
print(f"❌ Scalar creation failed: {e}")
# Test 2: Vector creation (1D tensor)
try:
vector_int = Tensor([1, 2, 3, 4, 5])
vector_float = Tensor([1.0, 2.5, 3.7])
vector_single = Tensor([42])
vector_empty = Tensor([])
assert vector_int._data.shape == (5,), f"Int vector should have shape (5,), got {vector_int._data.shape}"
assert vector_float._data.shape == (3,), f"Float vector should have shape (3,), got {vector_float._data.shape}"
assert vector_single._data.shape == (1,), f"Single element vector should have shape (1,), got {vector_single._data.shape}"
assert vector_empty._data.shape == (0,), f"Empty vector should have shape (0,), got {vector_empty._data.shape}"
print("✅ Vector creation: integers, floats, single element, and empty")
tests_passed += 1
except Exception as e:
print(f"❌ Vector creation failed: {e}")
# Test 3: Matrix creation (2D tensor)
try:
matrix_2x2 = Tensor([[1, 2], [3, 4]])
matrix_3x2 = Tensor([[1, 2], [3, 4], [5, 6]])
matrix_1x3 = Tensor([[1, 2, 3]])
assert matrix_2x2._data.shape == (2, 2), f"2x2 matrix should have shape (2, 2), got {matrix_2x2._data.shape}"
assert matrix_3x2._data.shape == (3, 2), f"3x2 matrix should have shape (3, 2), got {matrix_3x2._data.shape}"
assert matrix_1x3._data.shape == (1, 3), f"1x3 matrix should have shape (1, 3), got {matrix_1x3._data.shape}"
print("✅ Matrix creation: 2x2, 3x2, and 1x3 matrices")
tests_passed += 1
except Exception as e:
print(f"❌ Matrix creation failed: {e}")
# Test 4: Data type handling
try:
int_tensor = Tensor([1, 2, 3])
float_tensor = Tensor([1.0, 2.0, 3.0])
mixed_tensor = Tensor([1, 2.5, 3]) # Should convert to float
# Check that data types are reasonable
assert int_tensor._data.dtype in [np.int32, np.int64], f"Int tensor has unexpected dtype: {int_tensor._data.dtype}"
assert float_tensor._data.dtype in [np.float32, np.float64], f"Float tensor has unexpected dtype: {float_tensor._data.dtype}"
assert mixed_tensor._data.dtype in [np.float32, np.float64], f"Mixed tensor should be float, got: {mixed_tensor._data.dtype}"
print("✅ Data type handling: integers, floats, and mixed types")
tests_passed += 1
except Exception as e:
print(f"❌ Data type handling failed: {e}")
# Test 5: NumPy array input
try:
np_array = np.array([1, 2, 3, 4])
tensor_from_np = Tensor(np_array)
assert tensor_from_np._data.shape == (4,), f"Tensor from NumPy should have shape (4,), got {tensor_from_np._data.shape}"
assert np.array_equal(tensor_from_np._data, np_array), "Tensor from NumPy should preserve data"
print("✅ NumPy array input: conversion works correctly")
tests_passed += 1
except Exception as e:
print(f"❌ NumPy array input failed: {e}")
# Test 6: Large tensor creation
try:
large_tensor = Tensor(list(range(1000)))
assert large_tensor._data.shape == (1000,), f"Large tensor should have shape (1000,), got {large_tensor._data.shape}"
assert large_tensor._data[0] == 0, "Large tensor should start with 0"
assert large_tensor._data[-1] == 999, "Large tensor should end with 999"
print("✅ Large tensor creation: 1000 elements")
tests_passed += 1
except Exception as e:
print(f"❌ Large tensor creation failed: {e}")
# Test 7: Negative numbers
try:
negative_tensor = Tensor([-1, -2, -3])
mixed_signs = Tensor([-1, 0, 1])
assert negative_tensor._data.shape == (3,), f"Negative tensor should have shape (3,), got {negative_tensor._data.shape}"
assert np.array_equal(negative_tensor._data, np.array([-1, -2, -3])), "Negative numbers should be preserved"
assert np.array_equal(mixed_signs._data, np.array([-1, 0, 1])), "Mixed signs should be preserved"
print("✅ Negative numbers: handled correctly")
tests_passed += 1
except Exception as e:
print(f"❌ Negative numbers failed: {e}")
# Test 8: Edge cases
try:
# Very large numbers
big_tensor = Tensor([1e6, 1e-6])
assert big_tensor._data.shape == (2,), "Big numbers tensor should have correct shape"
# Zero tensor
zero_tensor = Tensor([0, 0, 0])
assert np.all(zero_tensor._data == 0), "Zero tensor should contain all zeros"
print("✅ Edge cases: large numbers and zeros")
tests_passed += 1
except Exception as e:
print(f"❌ Edge cases failed: {e}")
# Results summary
print(f"\n📊 Tensor Creation Results: {tests_passed}/{total_tests} tests passed")
if tests_passed == total_tests:
print("🎉 All tensor creation tests passed! Your Tensor class can handle:")
print(" • Scalars, vectors, and matrices")
print(" • Different data types (int, float)")
print(" • NumPy arrays")
print(" • Large tensors and edge cases")
print("📈 Progress: Tensor Creation ✓")
return True
else:
print("⚠️ Some tensor creation tests failed. Common issues:")
print(" • Check your __init__ method implementation")
print(" • Make sure you're storing data in self._data")
print(" • Verify NumPy array conversion works correctly")
print(" • Test with different input types (int, float, list, np.array)")
return False
# Test properties on different tensor types
scalar = Tensor(5.0)
vector = Tensor([1, 2, 3])
matrix = Tensor([[1, 2], [3, 4]])
# Test shape property
try:
assert scalar.shape == (), f"Scalar shape should be (), got {scalar.shape}"
assert vector.shape == (3,), f"Vector shape should be (3,), got {vector.shape}"
assert matrix.shape == (2, 2), f"Matrix shape should be (2, 2), got {matrix.shape}"
print("✅ Shape property works correctly")
except Exception as e:
print(f"❌ Shape property failed: {e}")
raise
# Test size property
try:
assert scalar.size == 1, f"Scalar size should be 1, got {scalar.size}"
assert vector.size == 3, f"Vector size should be 3, got {vector.size}"
assert matrix.size == 4, f"Matrix size should be 4, got {matrix.size}"
print("✅ Size property works correctly")
except Exception as e:
print(f"❌ Size property failed: {e}")
raise
# Test data access
try:
assert scalar.data.item() == 5.0, f"Scalar data should be 5.0, got {scalar.data.item()}"
assert np.array_equal(vector.data, np.array([1, 2, 3])), "Vector data mismatch"
assert np.array_equal(matrix.data, np.array([[1, 2], [3, 4]])), "Matrix data mismatch"
print("✅ Data access works correctly")
except Exception as e:
print(f"❌ Data access failed: {e}")
raise
print("🎉 Tensor properties work! You can access shape, size, and data.")
print("📈 Progress: Tensor creation ✓, Properties ✓")
# Run the comprehensive test
success = test_tensor_creation_comprehensive()
# %% [markdown]
"""
### 🧪 Quick Test: Basic Arithmetic
### 🧪 Comprehensive Test: Tensor Properties
Let's test the basic arithmetic methods (add, multiply) before moving to operator overloading.
Now let's test all the properties your tensor should have. These properties are essential for ML operations.
"""
# %% nbgrader={"grade": true, "grade_id": "test-basic-arithmetic-immediate", "locked": true, "points": 10, "schema_version": 3, "solution": false, "task": false}
# Test basic arithmetic methods immediately after implementation
print("🔬 Testing basic arithmetic methods...")
# %% nbgrader={"grade": true, "grade_id": "test-tensor-properties-comprehensive", "locked": true, "points": 15, "schema_version": 3, "solution": false, "task": false}
def test_tensor_properties_comprehensive():
"""Comprehensive test of tensor properties (shape, size, dtype, data access)."""
print("🔬 Testing comprehensive tensor properties...")
tests_passed = 0
total_tests = 6
# Test 1: Shape property
try:
scalar = Tensor(5.0)
vector = Tensor([1, 2, 3])
matrix = Tensor([[1, 2], [3, 4]])
tensor_3d = Tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
assert scalar.shape == (), f"Scalar shape should be (), got {scalar.shape}"
assert vector.shape == (3,), f"Vector shape should be (3,), got {vector.shape}"
assert matrix.shape == (2, 2), f"Matrix shape should be (2, 2), got {matrix.shape}"
assert tensor_3d.shape == (2, 2, 2), f"3D tensor shape should be (2, 2, 2), got {tensor_3d.shape}"
print("✅ Shape property: scalar, vector, matrix, and 3D tensor")
tests_passed += 1
except Exception as e:
print(f"❌ Shape property failed: {e}")
# Test 2: Size property
try:
scalar = Tensor(5.0)
vector = Tensor([1, 2, 3])
matrix = Tensor([[1, 2], [3, 4]])
empty = Tensor([])
assert scalar.size == 1, f"Scalar size should be 1, got {scalar.size}"
assert vector.size == 3, f"Vector size should be 3, got {vector.size}"
assert matrix.size == 4, f"Matrix size should be 4, got {matrix.size}"
assert empty.size == 0, f"Empty tensor size should be 0, got {empty.size}"
print("✅ Size property: scalar, vector, matrix, and empty tensor")
tests_passed += 1
except Exception as e:
print(f"❌ Size property failed: {e}")
# Test 3: Data type property
try:
int_tensor = Tensor([1, 2, 3])
float_tensor = Tensor([1.0, 2.0, 3.0])
# Check that dtype is accessible and reasonable
assert hasattr(int_tensor, 'dtype'), "Tensor should have dtype property"
assert hasattr(float_tensor, 'dtype'), "Tensor should have dtype property"
# Data types should be NumPy dtypes
assert isinstance(int_tensor.dtype, np.dtype), f"dtype should be np.dtype, got {type(int_tensor.dtype)}"
assert isinstance(float_tensor.dtype, np.dtype), f"dtype should be np.dtype, got {type(float_tensor.dtype)}"
print(f"✅ Data type property: int tensor is {int_tensor.dtype}, float tensor is {float_tensor.dtype}")
tests_passed += 1
except Exception as e:
print(f"❌ Data type property failed: {e}")
# Test 4: Data access property
try:
scalar = Tensor(5.0)
vector = Tensor([1, 2, 3])
matrix = Tensor([[1, 2], [3, 4]])
# Test data access
assert hasattr(scalar, 'data'), "Tensor should have data property"
assert hasattr(vector, 'data'), "Tensor should have data property"
assert hasattr(matrix, 'data'), "Tensor should have data property"
# Test data content
assert scalar.data.item() == 5.0, f"Scalar data should be 5.0, got {scalar.data.item()}"
assert np.array_equal(vector.data, np.array([1, 2, 3])), "Vector data mismatch"
assert np.array_equal(matrix.data, np.array([[1, 2], [3, 4]])), "Matrix data mismatch"
print("✅ Data access: scalar, vector, and matrix data retrieval")
tests_passed += 1
except Exception as e:
print(f"❌ Data access failed: {e}")
# Test 5: String representation
try:
scalar = Tensor(5.0)
vector = Tensor([1, 2, 3])
# Test that __repr__ works
scalar_str = str(scalar)
vector_str = str(vector)
assert isinstance(scalar_str, str), "Tensor string representation should be a string"
assert isinstance(vector_str, str), "Tensor string representation should be a string"
assert len(scalar_str) > 0, "Tensor string representation should not be empty"
assert len(vector_str) > 0, "Tensor string representation should not be empty"
print(f"✅ String representation: scalar={scalar_str[:50]}{'...' if len(scalar_str) > 50 else ''}")
tests_passed += 1
except Exception as e:
print(f"❌ String representation failed: {e}")
# Test 6: Property consistency
try:
test_cases = [
Tensor(42),
Tensor([1, 2, 3, 4, 5]),
Tensor([[1, 2, 3], [4, 5, 6]]),
Tensor([])
]
for i, tensor in enumerate(test_cases):
# Size should equal product of shape
expected_size = np.prod(tensor.shape) if tensor.shape else 1
assert tensor.size == expected_size, f"Test case {i}: size {tensor.size} doesn't match shape {tensor.shape}"
# Data shape should match tensor shape
assert tensor.data.shape == tensor.shape, f"Test case {i}: data shape {tensor.data.shape} doesn't match tensor shape {tensor.shape}"
print("✅ Property consistency: size matches shape, data shape matches tensor shape")
tests_passed += 1
except Exception as e:
print(f"❌ Property consistency failed: {e}")
# Results summary
print(f"\n📊 Tensor Properties Results: {tests_passed}/{total_tests} tests passed")
if tests_passed == total_tests:
print("🎉 All tensor property tests passed! Your tensor has:")
print(" • Correct shape property for all dimensions")
print(" • Accurate size calculation")
print(" • Proper data type handling")
print(" • Working data access")
print(" • Good string representation")
print("📈 Progress: Tensor Creation ✓, Properties ✓")
return True
else:
print("⚠️ Some property tests failed. Common issues:")
print(" • Check your @property decorators")
print(" • Verify shape returns self._data.shape")
print(" • Make sure size returns self._data.size")
print(" • Ensure dtype returns self._data.dtype")
print(" • Test your __repr__ method")
return False
# Test addition method
try:
a = Tensor([1, 2, 3])
b = Tensor([4, 5, 6])
c = a.add(b)
expected = np.array([5, 7, 9])
assert np.array_equal(c.data, expected), f"Addition method failed: expected {expected}, got {c.data}"
print(f"✅ Addition method: {a.data} + {b.data} = {c.data}")
except Exception as e:
print(f"❌ Addition method failed: {e}")
raise
# Test multiplication method
try:
d = a.multiply(b)
expected = np.array([4, 10, 18])
assert np.array_equal(d.data, expected), f"Multiplication method failed: expected {expected}, got {d.data}"
print(f"✅ Multiplication method: {a.data} * {b.data} = {d.data}")
except Exception as e:
print(f"❌ Multiplication method failed: {e}")
raise
print("🎉 Basic arithmetic methods work! You can add and multiply tensors.")
print("📈 Progress: Tensor creation ✓, Properties ✓, Basic arithmetic ✓")
# Run the comprehensive test
success = test_tensor_properties_comprehensive() and success
# %% [markdown]
"""
### 🧪 Quick Test: Operator Overloading
### 🧪 Comprehensive Test: Tensor Arithmetic
Finally, let's test the Python operators (+, -, *, /) to make sure they work with natural syntax.
Let's test all arithmetic operations. These are the foundation of neural network computations!
"""
# %% nbgrader={"grade": true, "grade_id": "test-operators-immediate", "locked": true, "points": 10, "schema_version": 3, "solution": false, "task": false}
# Test operator overloading immediately after implementation
print("🔬 Testing operator overloading...")
# %% nbgrader={"grade": true, "grade_id": "test-tensor-arithmetic-comprehensive", "locked": true, "points": 20, "schema_version": 3, "solution": false, "task": false}
def test_tensor_arithmetic_comprehensive():
"""Comprehensive test of tensor arithmetic operations."""
print("🔬 Testing comprehensive tensor arithmetic...")
tests_passed = 0
total_tests = 8
# Test 1: Basic addition method
try:
a = Tensor([1, 2, 3])
b = Tensor([4, 5, 6])
c = a.add(b)
expected = np.array([5, 7, 9])
assert np.array_equal(c.data, expected), f"Addition method failed: expected {expected}, got {c.data}"
assert isinstance(c, Tensor), "Addition should return a Tensor"
print(f"✅ Addition method: {a.data} + {b.data} = {c.data}")
tests_passed += 1
except Exception as e:
print(f"❌ Addition method failed: {e}")
# Test 2: Basic multiplication method
try:
a = Tensor([1, 2, 3])
b = Tensor([4, 5, 6])
c = a.multiply(b)
expected = np.array([4, 10, 18])
assert np.array_equal(c.data, expected), f"Multiplication method failed: expected {expected}, got {c.data}"
assert isinstance(c, Tensor), "Multiplication should return a Tensor"
print(f"✅ Multiplication method: {a.data} * {b.data} = {c.data}")
tests_passed += 1
except Exception as e:
print(f"❌ Multiplication method failed: {e}")
# Test 3: Addition operator (+)
try:
a = Tensor([1, 2, 3])
b = Tensor([4, 5, 6])
c = a + b
expected = np.array([5, 7, 9])
assert np.array_equal(c.data, expected), f"+ operator failed: expected {expected}, got {c.data}"
assert isinstance(c, Tensor), "+ operator should return a Tensor"
print(f"✅ + operator: {a.data} + {b.data} = {c.data}")
tests_passed += 1
except Exception as e:
print(f"❌ + operator failed: {e}")
# Test 4: Multiplication operator (*)
try:
a = Tensor([1, 2, 3])
b = Tensor([4, 5, 6])
c = a * b
expected = np.array([4, 10, 18])
assert np.array_equal(c.data, expected), f"* operator failed: expected {expected}, got {c.data}"
assert isinstance(c, Tensor), "* operator should return a Tensor"
print(f"✅ * operator: {a.data} * {b.data} = {c.data}")
tests_passed += 1
except Exception as e:
print(f"❌ * operator failed: {e}")
# Test 5: Subtraction operator (-)
try:
a = Tensor([1, 2, 3])
b = Tensor([4, 5, 6])
c = b - a
expected = np.array([3, 3, 3])
assert np.array_equal(c.data, expected), f"- operator failed: expected {expected}, got {c.data}"
assert isinstance(c, Tensor), "- operator should return a Tensor"
print(f"✅ - operator: {b.data} - {a.data} = {c.data}")
tests_passed += 1
except Exception as e:
print(f"❌ - operator failed: {e}")
# Test 6: Division operator (/)
try:
a = Tensor([1, 2, 4])
b = Tensor([2, 4, 8])
c = b / a
expected = np.array([2.0, 2.0, 2.0])
assert np.allclose(c.data, expected), f"/ operator failed: expected {expected}, got {c.data}"
assert isinstance(c, Tensor), "/ operator should return a Tensor"
print(f"✅ / operator: {b.data} / {a.data} = {c.data}")
tests_passed += 1
except Exception as e:
print(f"❌ / operator failed: {e}")
# Test 7: Scalar operations
try:
a = Tensor([1, 2, 3])
# Addition with scalar
b = a + 10
expected_add = np.array([11, 12, 13])
assert np.array_equal(b.data, expected_add), f"Scalar addition failed: expected {expected_add}, got {b.data}"
# Multiplication with scalar
c = a * 2
expected_mul = np.array([2, 4, 6])
assert np.array_equal(c.data, expected_mul), f"Scalar multiplication failed: expected {expected_mul}, got {c.data}"
# Subtraction with scalar
d = a - 1
expected_sub = np.array([0, 1, 2])
assert np.array_equal(d.data, expected_sub), f"Scalar subtraction failed: expected {expected_sub}, got {d.data}"
# Division with scalar
e = a / 2
expected_div = np.array([0.5, 1.0, 1.5])
assert np.allclose(e.data, expected_div), f"Scalar division failed: expected {expected_div}, got {e.data}"
print(f"✅ Scalar operations: +10, *2, -1, /2 all work correctly")
tests_passed += 1
except Exception as e:
print(f"❌ Scalar operations failed: {e}")
# Test 8: Matrix operations
try:
matrix_a = Tensor([[1, 2], [3, 4]])
matrix_b = Tensor([[5, 6], [7, 8]])
# Matrix addition
c = matrix_a + matrix_b
expected = np.array([[6, 8], [10, 12]])
assert np.array_equal(c.data, expected), f"Matrix addition failed: expected {expected}, got {c.data}"
assert c.shape == (2, 2), f"Matrix addition should preserve shape, got {c.shape}"
# Matrix multiplication (element-wise)
d = matrix_a * matrix_b
expected_mul = np.array([[5, 12], [21, 32]])
assert np.array_equal(d.data, expected_mul), f"Matrix multiplication failed: expected {expected_mul}, got {d.data}"
print(f"✅ Matrix operations: 2x2 matrix addition and multiplication")
tests_passed += 1
except Exception as e:
print(f"❌ Matrix operations failed: {e}")
# Results summary
print(f"\n📊 Tensor Arithmetic Results: {tests_passed}/{total_tests} tests passed")
if tests_passed == total_tests:
print("🎉 All tensor arithmetic tests passed! Your tensor supports:")
print(" • Basic methods: add(), multiply()")
print(" • Python operators: +, -, *, /")
print(" • Scalar operations: tensor + number")
print(" • Matrix operations: element-wise operations")
print("📈 Progress: Tensor Creation ✓, Properties ✓, Arithmetic ✓")
return True
else:
print("⚠️ Some arithmetic tests failed. Common issues:")
print(" • Check your add() and multiply() methods")
print(" • Verify operator overloading (__add__, __mul__, __sub__, __truediv__)")
print(" • Make sure scalar operations work (convert scalar to Tensor)")
print(" • Test with different tensor shapes")
return False
a = Tensor([1, 2, 3])
b = Tensor([4, 5, 6])
# Run the comprehensive test
success = test_tensor_arithmetic_comprehensive() and success
# Test addition operator
try:
c = a + b
expected = np.array([5, 7, 9])
assert np.array_equal(c.data, expected), f"+ operator failed: expected {expected}, got {c.data}"
print(f"✅ + operator: {a.data} + {b.data} = {c.data}")
except Exception as e:
print(f"❌ + operator failed: {e}")
raise
# %% [markdown]
"""
### 🧪 Final Integration Test: Real ML Scenario
# Test multiplication operator
try:
d = a * b
expected = np.array([4, 10, 18])
assert np.array_equal(d.data, expected), f"* operator failed: expected {expected}, got {d.data}"
print(f"✅ * operator: {a.data} * {b.data} = {d.data}")
except Exception as e:
print(f"❌ * operator failed: {e}")
raise
Let's test your tensor with a realistic machine learning scenario to make sure everything works together.
"""
# Test subtraction operator
try:
e = b - a
expected = np.array([3, 3, 3])
assert np.array_equal(e.data, expected), f"- operator failed: expected {expected}, got {e.data}"
print(f"✅ - operator: {b.data} - {a.data} = {e.data}")
except Exception as e:
print(f"❌ - operator failed: {e}")
raise
# %% nbgrader={"grade": true, "grade_id": "test-tensor-integration", "locked": true, "points": 10, "schema_version": 3, "solution": false, "task": false}
def test_tensor_integration():
"""Integration test with realistic ML scenario."""
print("🔬 Testing tensor integration with ML scenario...")
try:
print("🧠 Simulating a simple neural network forward pass...")
# Simulate input data (batch of 2 samples, 3 features each)
X = Tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
print(f"📊 Input data shape: {X.shape}")
# Simulate weights (3 input features, 2 output neurons)
W = Tensor([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]])
print(f"🎯 Weights shape: {W.shape}")
# Simulate bias (2 output neurons)
b = Tensor([0.1, 0.2])
print(f"⚖️ Bias shape: {b.shape}")
# Simple linear transformation: y = X * W + b
# Note: This is a simplified version - real matrix multiplication would be different
# But we can test element-wise operations
# Test that we can do basic operations needed for ML
sample = Tensor([1.0, 2.0, 3.0]) # Single sample
weight_col = Tensor([0.1, 0.3, 0.5]) # First column of weights
# Compute dot product manually using element-wise operations
products = sample * weight_col # Element-wise multiplication
print(f"✅ Element-wise multiplication works: {products.data}")
# Test addition for bias
result = products + Tensor([0.1, 0.1, 0.1])
print(f"✅ Bias addition works: {result.data}")
# Test with different shapes
matrix_a = Tensor([[1, 2], [3, 4]])
matrix_b = Tensor([[0.1, 0.2], [0.3, 0.4]])
matrix_result = matrix_a * matrix_b
print(f"✅ Matrix operations work: {matrix_result.data}")
# Test scalar operations (common in ML)
scaled = sample * 0.5 # Learning rate scaling
print(f"✅ Scalar scaling works: {scaled.data}")
# Test normalization-like operations
mean_val = Tensor([2.0, 2.0, 2.0]) # Simulate mean
normalized = sample - mean_val
print(f"✅ Mean subtraction works: {normalized.data}")
print("\n🎉 Integration test passed! Your tensor class can handle:")
print(" • Multi-dimensional data (batches, features)")
print(" • Element-wise operations needed for ML")
print(" • Scalar operations (learning rates, normalization)")
print(" • Matrix operations (weights, transformations)")
print("📈 Progress: All tensor functionality ✓")
print("🚀 Ready for neural network layers!")
return True
except Exception as e:
print(f"❌ Integration test failed: {e}")
print("\n💡 This suggests an issue with:")
print(" • Basic tensor operations not working together")
print(" • Shape handling problems")
print(" • Arithmetic operation implementation")
print(" • Check your tensor creation and arithmetic methods")
return False
# Test division operator
try:
f = b / a
expected = np.array([4.0, 2.5, 2.0])
assert np.allclose(f.data, expected), f"/ operator failed: expected {expected}, got {f.data}"
print(f"✅ / operator: {b.data} / {a.data} = {f.data}")
except Exception as e:
print(f"❌ / operator failed: {e}")
raise
# Run the integration test
success = test_tensor_integration() and success
# Test scalar operations
try:
g = a + 10
expected = np.array([11, 12, 13])
assert np.array_equal(g.data, expected), f"Scalar + failed: expected {expected}, got {g.data}"
print(f"✅ Scalar operations: {a.data} + 10 = {g.data}")
except Exception as e:
print(f"❌ Scalar operations failed: {e}")
raise
# Print final summary
print(f"\n{'='*60}")
print("🎯 TENSOR MODULE TESTING COMPLETE")
print(f"{'='*60}")
print("🎉 All operators work! You can use +, -, *, / with natural Python syntax.")
print("📈 Progress: Tensor creation ✓, Properties ✓, Basic arithmetic ✓, Operators ✓")
print("🚀 Ready for the comprehensive tests!")
if success:
print("🎉 CONGRATULATIONS! All tensor tests passed!")
print("\n✅ Your Tensor class successfully implements:")
print(" • Comprehensive tensor creation (scalars, vectors, matrices)")
print(" • All essential properties (shape, size, dtype, data access)")
print(" • Complete arithmetic operations (methods and operators)")
print(" • Scalar and matrix operations")
print(" • Real ML scenario compatibility")
print("\n🚀 You're ready to move to the next module!")
print("📈 Final Progress: Tensor Module ✓ COMPLETE")
else:
print("⚠️ Some tests failed. Please review the error messages above.")
print("\n🔧 To fix issues:")
print(" 1. Check the specific test that failed")
print(" 2. Review the error message and hints")
print(" 3. Fix your implementation")
print(" 4. Re-run the notebook cells")
print("\n💪 Don't give up! Debugging is part of learning.")
# %% [markdown]
"""