Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
48b83fb
Add skeleton functions and test structure for complex numbers
MithunDu404 Mar 16, 2026
19b067d
Add skeleton functions and test structure for complex numbers
MithunDu404 Mar 16, 2026
f3b5edd
added test compute and magnitude
Mar 16, 2026
ca3b822
added test compute and magnitude.
Mar 16, 2026
3717a41
Added multiplication, division and test cases
Billionaire25 Mar 16, 2026
b9d2a28
Implement parsar and unit test
MithunDu404 Mar 18, 2026
80767fb
Added multiplication, division and test cases
Feluda2005 Mar 20, 2026
4fb8d3c
Merge pull request #1 from MithunDu404/parser
MithunDu404 Mar 21, 2026
d01230b
Merge branch 'FeatureA_3' into MyBranch
MithunDu404 Mar 21, 2026
7d72539
Merge pull request #2 from MithunDu404/MyBranch
MithunDu404 Mar 21, 2026
8554335
Fix variable type errors in complex.py and correct the math in test_c…
MithunDu404 Mar 21, 2026
c9d327e
Added complex evaluator
Ish-07 Mar 22, 2026
24b5cf6
Implemented complex addition and subtraction with unit tests
subhamsaha7676 Mar 28, 2026
020c970
Delete complex_add.py
subhamsaha7676 Mar 28, 2026
d2744ed
Delete complex_sub.py
subhamsaha7676 Mar 28, 2026
eac4b2d
Delete test_complex_add.py
subhamsaha7676 Mar 28, 2026
68d5bfb
Delete test_complex_sub.py
subhamsaha7676 Mar 28, 2026
e0c164e
Merge pull request #3 from MithunDu404/complex-evaluator
MithunDu404 Mar 29, 2026
4c6d57c
fixed the ttype mismach error
MithunDu404 Mar 29, 2026
6e4ca3a
Merge branch 'FeatureA_3' into prashant_featureA_3
prashantbatchu Mar 29, 2026
d154a1d
Removed redundant lines
MithunDu404 Mar 29, 2026
a6509fe
Merge pull request #5 from MithunDu404/prashant_featureA_3
MithunDu404 Mar 29, 2026
db3761f
Added addition and subtraction logic with unit tests.
subhamsaha7676 Mar 29, 2026
565f25c
Merge branch 'complex-addition' of https://github.com/MithunDu404/SE_…
subhamsaha7676 Mar 29, 2026
c6c137b
Merge pull request #6 from MithunDu404/complex-addition
MithunDu404 Mar 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added __pycache__/calculator.cpython-313.pyc
Binary file not shown.
Binary file added __pycache__/complex.cpython-313.pyc
Binary file not shown.
172 changes: 172 additions & 0 deletions complex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# complex.py
import cmath
from calculator import Calculator
import re


def _complex_str_to_tuple(c_str):
try:
c = complex(c_str)
except ValueError as exc:
raise ValueError(f"Invalid complex number: {c_str}") from exc
return (float(c.real), float(c.imag))

def _format_complex(c):
"""
Helper function to format a Python complex object back into a
clean 'a+bj' string without parentheses to match lab requirements.
"""
res = str(c).replace(' ', '')
if res.startswith('(') and res.endswith(')'):
res = res[1:-1]
return res

def parse_complex_string(expression):
"""
Parses an input string like '(3+2j) * (5+3j)'.
Extracts the two complex numbers and the mathematical operator.
"""
# Regex to capture everything inside the parentheses and the operator between them
pattern = r'\s*\(([^)]+)\)\s*([+\-*/])\s*\(([^)]+)\)\s*'
match = re.match(pattern, expression)

if not match:
raise ValueError("Invalid complex expression format. Expected: '(a+bj) op (c+dj)'")

c1_str, operator, c2_str = match.groups()

# Remove any internal spaces (e.g., '3 + 2j' becomes '3+2j')
return c1_str.replace(' ', ''), operator, c2_str.replace(' ', '')

def add_complex(c1, c2):
"""
Member 2: Handles the addition of two complex numbers[cite: 120].
"""

if not isinstance(c1, tuple) or not isinstance(c2, tuple):
raise TypeError("Inputs must be tuples")
if len(c1) != 2 or len(c2) != 2:
raise TypeError("Tuples must have exactly 2 elements")
if not (isinstance(c1[0], (int, float)) and isinstance(c1[1], (int, float)) and
isinstance(c2[0], (int, float)) and isinstance(c2[1], (int, float))):
raise TypeError("Tuple elements must be numeric")

calc = Calculator()
a, b = c1
c, d = c2

real_part = calc.add(a, c)
imag_part = calc.add(b, d)

return (real_part, imag_part)

def subtract_complex(c1, c2):
"""
Member 2: Handles the subtraction of c2 from c1[cite: 120].
"""
if not isinstance(c1, tuple) or not isinstance(c2, tuple):
raise TypeError("Inputs must be tuples")
if len(c1) != 2 or len(c2) != 2:
raise TypeError("Tuples must have exactly 2 elements")
if not (isinstance(c1[0], (int, float)) and isinstance(c1[1], (int, float)) and
isinstance(c2[0], (int, float)) and isinstance(c2[1], (int, float))):
raise TypeError("Tuple elements must be numeric")

calc = Calculator()
a, b = c1
c, d = c2

real_part = calc.subtract(a, c)
imag_part = calc.subtract(b, d)

return (real_part, imag_part)

def multiply_complex(c1, c2):
"""
Member 3: Handles the multiplication of two complex numbers[cite: 120].
"""
if not isinstance(c1, tuple) or not isinstance(c2, tuple):
raise TypeError("Inputs must be tuples")
if len(c1) != 2 or len(c2) != 2:
raise TypeError("Tuples must have exactly 2 elements")
if not (isinstance(c1[0], (int, float)) and isinstance(c1[1], (int, float)) and
isinstance(c2[0], (int, float)) and isinstance(c2[1], (int, float))):
raise TypeError("Tuple elements must be numeric")

calc = Calculator()
a, b = c1
c, d = c2

real_part = calc.subtract(calc.multiply(a, c), calc.multiply(b, d))
imag_part = calc.add(calc.multiply(a, d), calc.multiply(b, c))

return (real_part, imag_part)

def divide_complex(c1, c2):
"""
Member 3: Handles the division of c1 by c2[cite: 120].
Must include error handling for division by zero.
"""
if not isinstance(c1, tuple) or not isinstance(c2, tuple):
raise TypeError("Inputs must be tuples")
if len(c1) != 2 or len(c2) != 2:
raise TypeError("Tuples must have exactly 2 elements")
if not (isinstance(c1[0], (int, float)) and isinstance(c1[1], (int, float)) and
isinstance(c2[0], (int, float)) and isinstance(c2[1], (int, float))):
raise TypeError("Tuple elements must be numeric")

calc = Calculator()
a, b = c1
c, d = c2

denominator = calc.add(calc.multiply(c, c), calc.multiply(d, d))
if denominator == 0:
raise ValueError("Division by zero in complex division")

real_num = calc.add(calc.multiply(a, c), calc.multiply(b, d))
real_part = calc.divide(real_num, denominator)

imag_num = calc.subtract(calc.multiply(b, c), calc.multiply(a, d))
imag_part = calc.divide(imag_num, denominator)

return (real_part, imag_part)

def compute_magnitude(c):
"""
Member 4: Calculates the magnitude of a single complex number[cite: 122].
"""
z = complex(c.replace(" ", ""))
return abs(z)

def compute_phase(c):
"""
Member 4: Calculates the phase (angle) of a single complex number[cite: 122].
"""
z = complex(c.replace(" ", ""))
return cmath.phase(z)

def evaluate_complex_expression(expression):
"""
Evaluates a full complex expression string like:
'(1+2j) * (3+4j)'
"""

c1_str, op, c2_str = parse_complex_string(expression)
c1 = _complex_str_to_tuple(c1_str)
c2 = _complex_str_to_tuple(c2_str)

if op == '+':
return add_complex(c1, c2)

elif op == '-':
return subtract_complex(c1, c2)

elif op == '*':
return multiply_complex(c1, c2)

elif op == '/':
return divide_complex(c1, c2)

else:
raise ValueError("Unsupported operation")

143 changes: 143 additions & 0 deletions test_complex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# test_complex.py
import unittest
from complex import (
parse_complex_string, add_complex, subtract_complex,
multiply_complex, divide_complex, compute_magnitude,
compute_phase, evaluate_complex_expression
)
import math
class TestComplexArithmetic(unittest.TestCase):

# --- Parser Tests ---
def test_parse_complex_string_valid(self):
c1, op, c2 = parse_complex_string('(3 + 2j) * (5+ 3j)')
self.assertEqual(c1, '3+2j')
self.assertEqual(op, '*')
self.assertEqual(c2, '5+3j')

def test_parse_complex_string_invalid(self):
# Boundary Condition: Missing brackets should raise a ValueError
with self.assertRaises(ValueError):
parse_complex_string('3+2j * 5+3j')

# --- Member 2 Tests ---
def test_add_complex(self):
# Test normal addition and negative addition
self.assertEqual(add_complex((3, 2), (5, 3)), (8, 5))
self.assertEqual(add_complex((0, 0), (5, 3)), (5, 3))
self.assertEqual(add_complex((1, 0), (0, 1)), (1, 1))
self.assertEqual(add_complex((2, -3), (-1, 4)), (1, 1))

# Boundary cases
self.assertEqual(add_complex((0, 0), (0, 0)), (0, 0))
self.assertEqual(add_complex((999999, 0), (0, 999999)), (999999, 999999))
self.assertEqual(add_complex((-1, -1), (-1, -1)), (-2, -2))

# Invalid input handling
with self.assertRaises(TypeError):
add_complex((1,), (2, 3)) # Too few elements
with self.assertRaises(TypeError):
add_complex((1, 2, 3), (2, 3)) # Too many elements
with self.assertRaises(TypeError):
add_complex((1, 'a'), (2, 3)) # Non-numeric
with self.assertRaises(TypeError):
add_complex('not a tuple', (2, 3))

def test_subtract_complex(self):
# Test normal subtraction
self.assertEqual(subtract_complex((5, 3), (3, 2)), (2, 1))
self.assertEqual(subtract_complex((0, 0), (5, 3)), (-5, -3))
self.assertEqual(subtract_complex((1, 0), (0, 1)), (1, -1))
self.assertEqual(subtract_complex((2, -3), (-1, 4)), (3, -7))

# Boundary cases
self.assertEqual(subtract_complex((0, 0), (0, 0)), (0, 0))
self.assertEqual(subtract_complex((999999, 0), (0, 999999)), (999999, -999999))
self.assertEqual(subtract_complex((-1, -1), (-1, -1)), (0, 0))

# Invalid input handling
with self.assertRaises(TypeError):
subtract_complex((1,), (2, 3)) # Too few elements
with self.assertRaises(TypeError):
subtract_complex((1, 2, 3), (2, 3)) # Too many elements
with self.assertRaises(TypeError):
subtract_complex((1, 'a'), (2, 3)) # Non-numeric
with self.assertRaises(TypeError):
subtract_complex('not a tuple', (2, 3))


# --- Member 3 Tests ---

def test_multiply_complex(self):
# Normal cases
self.assertEqual(multiply_complex((3, 2), (5, 3)), (9, 19)) # (3+2j)*(5+3j) = (3*5-2*3, 3*3+2*5) = (15-6, 9+10) = (9, 19)
self.assertEqual(multiply_complex((0, 0), (5, 3)), (0, 0)) # Zero times anything
self.assertEqual(multiply_complex((1, 0), (0, 1)), (0, 1)) # (1+0j)*(0+1j) = (0, 1)
self.assertEqual(multiply_complex((2, -3), (-1, 4)), (10, 11)) # (2-3j)*(-1+4j) = (2*-1-(-3)*4, 2*4+(-3)*-1) = (-2+12, 8+3) = (10, 11)

# Boundary cases
self.assertEqual(multiply_complex((0, 0), (0, 0)), (0, 0)) # Both zero
self.assertEqual(multiply_complex((999999, 0), (0, 999999)), (0, 999999*999999))
self.assertEqual(multiply_complex((-1, -1), (-1, -1)), (0, 2))

# Invalid input handling
with self.assertRaises(TypeError):
multiply_complex((1,), (2, 3)) # Too few elements
with self.assertRaises(TypeError):
multiply_complex((1, 2, 3), (2, 3)) # Too many elements
with self.assertRaises(TypeError):
multiply_complex((1, 'a'), (2, 3)) # Non-numeric
with self.assertRaises(TypeError):
multiply_complex('not a tuple', (2, 3))


def test_divide_complex(self):
# Normal cases
self.assertEqual(divide_complex((3, 2), (5, 3)), (0.6176470588235294, 0.029411764705882353))
self.assertEqual(divide_complex((0, 0), (5, 3)), (0.0, 0.0))
self.assertEqual(divide_complex((1, 0), (1, 0)), (1.0, 0.0))
self.assertEqual(divide_complex((2, -3), (-1, 4)), (-0.8235294117647058, -0.29411764705882354))

# Boundary cases
self.assertEqual(divide_complex((0, 0), (0, 1)), (0.0, 0.0))
self.assertEqual(divide_complex((999999, 0), (0, 999999)), (0.0, -1.0))
self.assertEqual(divide_complex((-1, -1), (-1, -1)), (1.0, 0.0))

# Invalid input handling
with self.assertRaises(TypeError):
divide_complex((1,), (2, 3)) # Too few elements
with self.assertRaises(TypeError):
divide_complex((1, 2, 3), (2, 3)) # Too many elements
with self.assertRaises(TypeError):
divide_complex((1, 'a'), (2, 3)) # Non-numeric
with self.assertRaises(TypeError):
divide_complex('not a tuple', (2, 3))


def test_divide_complex_by_zero(self):
# Test division by zero exception handling
with self.assertRaises(ValueError):
divide_complex((1, 2), (0, 0))

# --- Member 4 Tests ---
def test_compute_magnitude(self):
# Test magnitude calculations
self.assertAlmostEqual(compute_magnitude('3+4j'), 5.0)
self.assertAlmostEqual(compute_magnitude('1+0j'), 1.0)
self.assertAlmostEqual(compute_magnitude('0+2j'), 2.0)


def test_compute_phase(self):
# Test phase calculations (check against known angles)
self.assertAlmostEqual(compute_phase('1+0j'), 0.0)
self.assertAlmostEqual(compute_phase('0+1j'), math.pi/2)
self.assertAlmostEqual(compute_phase('-1+0j'), math.pi)


# --- Member 5 Tests (Integration) ---
def test_evaluate_complex_expression(self):
# Test the full pipeline from raw string to final output
pass

if __name__ == "__main__":
unittest.main()