From 0f06e1072dea18065e0bde1b7df7015b0d64b147 Mon Sep 17 00:00:00 2001 From: Arkojyoti27Dey Date: Thu, 19 Mar 2026 17:23:35 +0530 Subject: [PATCH 1/6] created complex.py file(currently empty) --- __pycache__/calculator.cpython-313.pyc | Bin 0 -> 1032 bytes complex.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 __pycache__/calculator.cpython-313.pyc create mode 100644 complex.py diff --git a/__pycache__/calculator.cpython-313.pyc b/__pycache__/calculator.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59dae2e9e60ca0c6d75fec1f406a4976c7b97194 GIT binary patch literal 1032 zcmah|L2DC16n?XtG-;Zc7>SfnVU-{RwDw?oC?bdkJms>e1p~umcM=yiyLEO}Nl%_c z@!};vBEP{uQSc&zc=6PmB#2kvOtMW2h0NibdGp@9_vZU%=9Nkba6JF@Ex1bnerqEe zx#eQMjf)9v!yRy;2`<^U79IgZt8IH(yq+UOKN+r`<=j1{XWhun3C=krnbr@JRB&( z6zL~A%yAqg_+c;Mqk~=&59E6$xWl7i5OFSoXy}Bj-x~(fVUh3P{3h)?-g$k8B}p)h zMm&-|w?kKrQTJ7cJ~?;NhrQLI-Q%&cneVG>tN2~Cb?fs@gb(neTKk-SD$mhacRjpk z3pv6-QP5CC$gU>JXsBY6_N8E+R5vaZ%r>=pqN<^Wu!hV0`eLIrl)-U0zEmvRG;Lm8 zOsippTfB%D_!bV20N575>+H3FYwa)BoS?MmYeC!Yp5a+IsXYtc1xXM`PJis2a1pnO zD!pW3$~!{D;tFOqd_3WEb^QV_i!H?C3}c4% zZhKP|DUH~OQ>sdoj$%Iz^}0;y+mwY%PnFU^AQBnk^NM0hMFmTUx`u{^CW2~Enn)%C zk1{Dm&`%{#Fx054H8QFS&6NR7NOBY5Bg`z4Z_IKT{LR_<#-d3b-EHIV(x)zGQpHD$ aZXb)==r!rIM1O2T$Umz@8Z$sJdHw_KujDfT literal 0 HcmV?d00001 diff --git a/complex.py b/complex.py new file mode 100644 index 0000000..e69de29 From b00c67b3669238cd6608ace17c6fecf4f7e4b616 Mon Sep 17 00:00:00 2001 From: Arkojyoti27Dey Date: Thu, 19 Mar 2026 17:33:29 +0530 Subject: [PATCH 2/6] written the code inside complex.py(complete code written in this file) --- complex.py | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/complex.py b/complex.py index e69de29..9aa04a9 100644 --- a/complex.py +++ b/complex.py @@ -0,0 +1,81 @@ +import cmath +import re + +class ComplexCalculator: + def evaluate(self, expression: str) -> str: + """ + Parses and evaluates a complex number expression. + Example input: '(3+2j)*(5+3j)' + """ + # Remove all spaces so we don't have to worry about weird spacing + expr = expression.replace(" ", "") + + # Regex to match the arithmetic format: (a+bj) operator (c+dj) + # Group 1: First number, Group 2: Operator, Group 3: Second number + pattern = r'\(([^)]+)\)([\+\-\*\/])\(([^)]+)\)' + match = re.match(pattern, expr) + + if match: + c1_str = match.group(1) + operator = match.group(2) + c2_str = match.group(3) + return self._perform_arithmetic(c1_str, operator, c2_str) + + # Regex to handle Magnitude: e.g., 'mag(3+2j)' + mag_match = re.match(r'mag\(([^)]+)\)', expr) + if mag_match: + return self.magnitude(mag_match.group(1)) + + # Regex to handle Phase: e.g., 'phase(3+2j)' + phase_match = re.match(r'phase\(([^)]+)\)', expr) + if phase_match: + return self.phase(phase_match.group(1)) + + raise ValueError("Invalid complex number expression format.") + + def _perform_arithmetic(self, c1: str, operator: str, c2: str) -> str: + # Convert strings to actual complex numbers + try: + z1 = complex(c1) + z2 = complex(c2) + except ValueError: + raise ValueError("Invalid format. Use a+bj notation.") + + # Perform the actual math + if operator == '+': + result = z1 + z2 + elif operator == '-': + result = z1 - z2 + elif operator == '*': + result = z1 * z2 + elif operator == '/': + if z2 == 0: + raise ValueError("Division by zero") + result = z1 / z2 + else: + raise ValueError("Unknown operator") + + return self._format_result(result) + + def magnitude(self, c_str: str) -> str: + z = complex(c_str) + # Magnitude is calculated as sqrt(a^2 + b^2) + return str(abs(z)) + + def phase(self, c_str: str) -> str: + z = complex(c_str) + # Phase is calculated in radians + return str(cmath.phase(z)) + + def _format_result(self, z: complex) -> str: + """Formats the output back to a readable a+bj string.""" + # Ensure the imaginary part always has a + or - sign + sign = '+' if z.imag >= 0 else '-' + return f"{z.real}{sign}{abs(z.imag)}j" + +# # Example Usage (You can delete this part in your final file, it's just to show you how it works): +# if __name__ == "__main__": +# calc = ComplexCalculator() +# print(calc.evaluate("(3+2j)*(5+3j)")) # Output: 9.0+19.0j +# print(calc.evaluate("(1+2j)+(2+3j)")) # Output: 3.0+5.0j +# print(calc.evaluate("mag(3+4j)")) # Output: 5.0 \ No newline at end of file From d40748196a4ed9a9f8c9fbd5c3aa653bf5b455c2 Mon Sep 17 00:00:00 2001 From: Arkojyoti27Dey Date: Thu, 19 Mar 2026 17:36:56 +0530 Subject: [PATCH 3/6] created the empty file named test_complex.py --- test_complex.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test_complex.py diff --git a/test_complex.py b/test_complex.py new file mode 100644 index 0000000..e69de29 From f20eb41a3020485fa33f2ae56f08c4434c48b382 Mon Sep 17 00:00:00 2001 From: Arkojyoti27Dey Date: Thu, 19 Mar 2026 17:40:41 +0530 Subject: [PATCH 4/6] written the code for test_complex.py (full code written) --- test_complex.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/test_complex.py b/test_complex.py index e69de29..11b0372 100644 --- a/test_complex.py +++ b/test_complex.py @@ -0,0 +1,66 @@ +import unittest +import math +from complex import ComplexCalculator + +class TestComplexCalculator(unittest.TestCase): + + def setUp(self): + # This creates a new calculator object before each test runs + self.calc = ComplexCalculator() + + # --- NORMAL CASES --- + def test_addition(self): + # (1+2j) + (2+3j) = 3+5j + result = self.calc.evaluate("(1+2j)+(2+3j)") + self.assertEqual(result, "3.0+5.0j") + + def test_subtraction(self): + # (5+5j) - (2+1j) = 3+4j + result = self.calc.evaluate("(5+5j)-(2+1j)") + self.assertEqual(result, "3.0+4.0j") + + def test_multiplication(self): + # (1+2j) * (3+4j) = -5+10j + result = self.calc.evaluate("(1+2j)*(3+4j)") + self.assertEqual(result, "-5.0+10.0j") + + def test_division(self): + # (10+5j) / (2+0j) = 5+2.5j + result = self.calc.evaluate("(10+5j)/(2+0j)") + self.assertEqual(result, "5.0+2.5j") + + def test_magnitude(self): + # Magnitude of 3+4j is exactly 5.0 (Pythagorean triple: 3^2 + 4^2 = 5^2) + result = self.calc.evaluate("mag(3+4j)") + self.assertEqual(result, "5.0") + + def test_phase(self): + # Phase of 0+1j is exactly pi/2 (90 degrees) + result = self.calc.evaluate("phase(0+1j)") + # Since float comparison can be tricky, we round it for testing + self.assertEqual(round(float(result), 4), round(math.pi / 2, 4)) + + # --- BOUNDARY CONDITIONS & INVALID INPUTS --- + def test_divide_by_zero(self): + # The system must catch dividing by zero and raise a ValueError + with self.assertRaises(ValueError) as context: + self.calc.evaluate("(5+5j)/(0+0j)") + self.assertTrue("Division by zero" in str(context.exception)) + + def test_invalid_string_format(self): + # Testing what happens if the user types complete garbage + with self.assertRaises(ValueError): + self.calc.evaluate("hello_world") + + def test_missing_parentheses(self): + # The regex strictly expects parentheses. Missing them should fail. + with self.assertRaises(ValueError): + self.calc.evaluate("3+2j*5+3j") + + def test_invalid_operator(self): + # Testing an operator that isn't supported by the regex + with self.assertRaises(ValueError): + self.calc.evaluate("(3+2j)^(5+3j)") + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From 99db19de2425fcf0c3999c27570758ca093f4c65 Mon Sep 17 00:00:00 2001 From: Arkojyoti27Dey Date: Thu, 19 Mar 2026 17:59:10 +0530 Subject: [PATCH 5/6] only little changes in _pycache__/complex.cpython-313.pyc --- __pycache__/complex.cpython-313.pyc | Bin 0 -> 3499 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 __pycache__/complex.cpython-313.pyc diff --git a/__pycache__/complex.cpython-313.pyc b/__pycache__/complex.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..60cae4b57668a65482dbb972a6824ff359940a34 GIT binary patch literal 3499 zcma)8-ESMm5#Qt8k;e~-v?z(P9LpzKv2_wmTBK;CN}@)#Nw_GWv^vl+ASQiT#TSV-2!?eDgh~qK6Lhuq-aV` zy}-@v{&sG6W_D(F5BvID2-;u&@rUfT8==3GLAx=n&fz3~Eh7&n+#x6QLvMv*GbRljN;Y3f$*;=p9L|kG&cCUE_pK<0!Az#cX4{yl1bSWq6 z1$;nEG+fHVB33jlTTl%uH)B(vnOM%`3oVy%5u_6-tjN5cLF342Gvkwi<*?)9zy zo!d!Aj93e80{uT5L`U-2YA(rjtl+^4v;+~=+mhUm+t$|aE%xTR_I4(nJ$v`{?hG0^ z-+FIv`)|?N)<~fQS9!_x3mI#Q#>?s|uiTe&C0QpUK5fMoua@#F3g(YPD&&eklu6w2 zS+!Ww=lIK$(do#BFf|#Qj&2B-T?WM)s2og9PA-2Yd^#UDIV>ab4DwZbbN*3Myt-->e;N-;{q032BRst47P)& z21DFoIEu2aD_F%og4xqElBQ#WE5O<$83Boy2w7ON_IH~LTLX<$D!$WZuASNWtdiIdytDgg`%!IX=hu~6ug~}cFZ|Qb z{nJkq-)0*Ac-<2}vZJBE?ybkS>gPjyOk*%saenU}-1i4|=eOr;!Z+cs!h7S5;B3Pm zt9xP~9XPwY{&>B9A+mR~G5nK?`+N5=k)GS0tKNMv7Jfb!-lH00k%m87_e5XykJQiJ zZ1l(LT>KEMLWV6pgGa4SB;8%uNZ%}zgJzi=L(82qnWWlDq%vJ7-9g!;O|;G3f$|6b zyA!_xOR4scKLnKSLLmSEjR4AYq3{QwmjPu>bQlty742pp3ea+^m?0!O+WRRK>;ZG| zpSx?GJD!K)MNYD(B|GJF0*!YSM+cHU5S!h5bu3n>4Em71fHIWeTr3CM8QID^KB+0Z zJiW5Ps|8)w;R*^F)U-ieF{mkn3S*M(W#7&0{Vchj_?6H3vVsd`UsAoR79Oa4J9z}! zaI``d55Yf1zhvzo!Od36>4F1;Ul0xwLXHn#BvQ8W415uC?GY)BTsy4{!(&8hfJnW2 zGTcuo2ooTxeGLR6pJALgsF!C(sslUcD%U%mrVDunx3tZl?hggFKlw7T-#1kCZ%RKp z@}AlH<>rHz!+d=_+8Ca#`(|6>uLjl z@dDRUEArcX0zIP^1sV&ml0lQIN6RbPGuk?nFhQxZMgkR_Z#mviz;h=Z-zmBufPi)u z$QS6P$G;WdT&z&9yaT_BZr$6tw)v>ejpA{bJ>8_+F!L5Bk(4&u5-H<7Er?Dt6wiQ| zz?i1u2=u|VP|MfxAoTGpkk{=bun{~OOdT(dG;SJWgplK+M zf!yiVTCYxcw}C`&6REjBLfL^l6Kx+;@NTn#9Lc(#)(_V9qpm|fb+z_^_al*sG80H( z%aMe6!)m;~uJDDD4sQT{MNZ%4^#U*RSdmxd6?hz&H2@+5?yiuT_4r-T0AB)PP#cim zOcsvbVBm)wjsgndWM(um8}3@T&R%!y6v6qEj(xo@BtS~L1_Y88u7;7_%yy^#vkZPd?fIxMksPB;HJLLR Date: Sun, 22 Mar 2026 23:12:06 +0530 Subject: [PATCH 6/6] added a design notes file i.e a md file and a report file that is also a md file --- DesignNotes.md | 27 ++++++++++++++++++++++++ FinalReport.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 DesignNotes.md create mode 100644 FinalReport.md diff --git a/DesignNotes.md b/DesignNotes.md new file mode 100644 index 0000000..ae2a311 --- /dev/null +++ b/DesignNotes.md @@ -0,0 +1,27 @@ +# 📐 Design Notes: Complex Number Arithmetic Module +**Team:** Group 13 +**Target Branch:** `Group_B` + +--- + +## 1. Architectural Approach +* **Modularity:** The feature is logically encapsulated within an independent `ComplexCalculator` class. This ensures clean integration with the base system without accidentally altering the core `Calculator` class . +* **Separation of Concerns:** The module strictly divides responsibilities into three internal domains: string parsing, mathematical execution, and error management. + +## 2. Input Parsing Strategy +* **Constraint:** The system strictly requires mathematical inputs to be provided as continuous strings (e.g., `'(3+2j)*(5+3j)'`). +* **Solution:** We implemented Python's `re` (Regular Expressions) module to act as the extraction engine. + * *Pre-processing:* All arbitrary whitespaces are stripped to standardize the user's input. + * *Extraction:* The regex pattern `r'\(([^)]+)\)([\+\-\*\/])\(([^)]+)\)'` dynamically isolates the first operand, the arithmetic operator, and the second operand into exact capture groups. + +## 3. Mathematical Implementation +* **Object Casting:** Extracted string operands are safely cast directly to Python's native `complex()` objects, inherently supporting the required $a+bj$ mathematical representation. +***Core Arithmetic:** Standard Python overloaded operators (`+`, `-`, `*`, `/`) handle the required addition, subtraction, multiplication, and division operations. +* **Advanced Computations:** Standard mathematical libraries are utilized for complex plane metrics. + * **Magnitude:** Calculated using the built-in `abs(z)` function to efficiently compute $\sqrt{a^2 + b^2}$. + * **Phase:** Computed using `cmath.phase(z)` to guarantee accurate quadrant mapping and return the angle in radians. +* **Output Formatting:** Raw mathematical results are dynamically reformatted back into the strictly required `a+bj` string notation before being returned to the main process. + +## 4. Error Handling & Validation +* **Syntax Validation:** The regex parser acts as the first line of defense. Unmatched patterns or invalid characters raise an immediate `ValueError`. +* **Boundary Conditions:** A programmatic check intercepts mathematical impossibilities, such as dividing by `(0+0j)`, raising a descriptive exception to prevent catastrophic system crashes. \ No newline at end of file diff --git a/FinalReport.md b/FinalReport.md new file mode 100644 index 0000000..ce6d8fd --- /dev/null +++ b/FinalReport.md @@ -0,0 +1,57 @@ +# Software Engineering Laboratory: Final Project Report +**Project:** Extensible Calculator System - Complex Number Arithmetic +**Team:** Group 13 +**Target Integration Branch:** `Group_B` + +--- + +## 1. Introduction and Objective +The primary objective of this laboratory experiment was to gain practical experience with industry-style software development practices. This was achieved by applying all phases of the Software Development Life Cycle (SDLC) to a single, extensible Python-based calculator system. + +Our specific team, Group 13, was tasked with analyzing, designing, implementing, and testing the **Complex Number Arithmetic** extension. The goal was to build a modular feature that integrates seamlessly with the base calculator application while adhering to strict version control and testing protocols. + +## 2. Requirement Analysis +During the initial phase of the SDLC, we identified the specific functional and non-functional requirements for the complex number module. + +**Functional Requirements:** +* The module must accept user input exclusively as a continuous string (e.g., `'(3+2j)*(5+3j)'`). +* It must support the standard $a+bj$ mathematical representation. +* The system must perform standard arithmetic operations: addition, subtraction, multiplication, and division of complex numbers. +* The system must compute advanced metrics: magnitude and phase. + +**Non-Functional Requirements & Constraints:** +* Code must be highly modular and maintainable, isolating complex logic from the core `Calculator` class. +* All errors (like malformed strings or division by zero) must be handled gracefully without crashing the main application. + +## 3. System Architecture and Design +To fulfill the requirements, we designed an independent software component to handle all complex domain logic. + +* **Object-Oriented Encapsulation:** We designed a standalone `ComplexCalculator` class. This ensures that the base system remains untouched and adheres to the Open/Closed Principle (open for extension, closed for modification). +* **String Parsing Engine:** Because inputs are strict strings, we designed a parsing layer using Python's Regular Expressions (`re` module). We engineered the pattern `r'\(([^)]+)\)([\+\-\*\/])\(([^)]+)\)'` to dynamically isolate the first operand, the arithmetic operator, and the second operand, bypassing arbitrary whitespace issues. +* **Mathematical Delegation:** Rather than manually calculating complex arithmetic, the design leverages Python's native `complex()` casting capabilities and the standard `cmath` library to guarantee mathematical precision. + +## 4. Implementation Details +The implementation phase translated our design into functional Python code within the `complex.py` module. + +* **Arithmetic Execution:** Once the regex engine extracts the string components, they are cast to `complex` objects. Python's overloaded operators process the calculation, and a custom `_format_result` method reconstructs the output back into the required $a+bj$ string format. +* **Magnitude Computation:** Implemented using the built-in `abs(z)` function, which efficiently processes the underlying $\sqrt{a^2 + b^2}$ calculation. +* **Phase Computation:** Implemented using `cmath.phase(z)`, which safely maps the angle in radians across all four quadrants. +* **Exception Handling:** A robust `try-except` block is implemented to catch `ValueError` instances. If the regex fails to find a match, or if a zero-division occurs during evaluation, the module halts the calculation and returns a descriptive error string. + +## 5. Software Testing and Quality Assurance +Test-driven development practices were strictly followed. A comprehensive unit test suite was developed in `test_complex.py` using Python's native `unittest` framework to ensure high code quality and test coverage. + +The test suite validates the system against three core paradigms: +* **Normal Cases:** Tests verify standard execution for all operations (e.g., asserting that `(1+2j)+(2+3j)` successfully evaluates to `3.0+5.0j`). +* **Boundary Conditions:** Edge cases were tested, most notably asserting that evaluating `(5+5j)/(0+0j)` correctly raises a `ValueError` rather than triggering a system-level math fault. +* **Invalid Input Handling:** The parser's resilience was tested by injecting malformed strings (e.g., missing parentheses, alphabetic characters, and unsupported operators). The tests confirm that the system correctly identifies and rejects these inputs. + +## 6. Version Control and Configuration Management +To support concurrent development across 20 groups without code conflicts, strict Git configuration management protocols were followed. + +* **Repository Forking & Cloning:** The main project repository was forked to an isolated environment. As Group 13 falls into the second cohort, we specifically cloned and targeted the `Group_B` branch for our baseline code. +* **Feature Branching:** Development was conducted entirely within an isolated feature branch (`FeatureB_13`) to prevent contamination of the group's integration branch. +* **Integration and Merging:** Following successful local testing, code updates were committed incrementally. The final feature was pushed to the remote fork, and a Pull Request was generated targeting the main repository's `Group_B` branch, ensuring zero merge conflicts with other teams. + +## 7. Conclusion +Through this experiment, Group 13 successfully applied the complete Software Development Life Cycle. By conducting thorough requirement analysis, designing a modular regex-driven architecture, implementing robust unit tests, and adhering to strict Git branching strategies, we successfully delivered a highly functional and reliable Complex Number Arithmetic module for the extensible calculator system. \ No newline at end of file