spagestic commited on
Commit
6c13437
ยท
1 Parent(s): aa584c9

changed routing from education level to topics in maths

Browse files
Files changed (39) hide show
  1. README.md +51 -137
  2. app.py +86 -68
  3. letter_counter.py +0 -0
  4. maths/__init__.py +0 -3
  5. maths/{middleschool โ†’ algebra}/algebra.py +0 -0
  6. maths/{middleschool โ†’ algebra}/algebra_interface.py +1 -1
  7. maths/{elementary โ†’ arithmetic}/arithmetic.py +0 -0
  8. maths/{elementary โ†’ arithmetic}/arithmetic_interface.py +1 -1
  9. maths/{university โ†’ calculus}/calculus.py +0 -0
  10. maths/{university โ†’ calculus}/calculus_interface.py +1 -1
  11. maths/{university โ†’ differential_equations}/differential_equations.py +0 -0
  12. maths/{university โ†’ differential_equations}/differential_equations_interface.py +1 -1
  13. maths/elementary/__init__.py +0 -3
  14. maths/{highschool โ†’ geometry}/trigonometry.py +0 -0
  15. maths/{highschool โ†’ geometry}/trigonometry_interface.py +1 -1
  16. maths/highschool/__init__.py +0 -3
  17. maths/matrices/matrices.py +40 -0
  18. maths/{university/linear_algebra_interface.py โ†’ matrices/matrices_interface.py} +11 -110
  19. maths/middleschool/__init__.py +0 -3
  20. maths/{university/operations_research โ†’ operations_research}/BranchAndBoundSolver.py +0 -0
  21. maths/{university/operations_research โ†’ operations_research}/DualSimplexSolver.py +0 -0
  22. maths/{university/operations_research โ†’ operations_research}/bnb.ipynb +0 -0
  23. maths/{university/operations_research โ†’ operations_research}/dual.ipynb +0 -0
  24. maths/{university/operations_research โ†’ operations_research}/get_user_input.py +0 -0
  25. maths/{university/operations_research โ†’ operations_research}/operations_research_interface.py +0 -0
  26. maths/{university/operations_research โ†’ operations_research}/simplex_solver_with_steps.py +0 -0
  27. maths/{university/operations_research โ†’ operations_research}/solve_lp_via_dual.py +0 -0
  28. maths/{university/operations_research โ†’ operations_research}/solve_primal_directly.py +0 -0
  29. maths/university/__init__.py +0 -9
  30. maths/university/linear_algebra.py +0 -249
  31. maths/university/tests/__init__.py +0 -2
  32. maths/university/tests/test_differential_equations.py +0 -133
  33. maths/university/tests/test_linear_algebra.py +0 -132
  34. maths/university/tests/test_operations_research_interface.py +0 -134
  35. maths/vectors/vectors.py +35 -0
  36. maths/vectors/vectors_interface.py +83 -0
  37. utils/__init__.py +0 -3
  38. utils/text_utils.py +0 -7
  39. utils/text_utils_interface.py +0 -11
README.md CHANGED
@@ -1,146 +1,60 @@
1
- ---
2
- title: Math Tools
3
- emoji: ๐Ÿงฎ
4
- colorFrom: blue
5
- colorTo: purple
6
- sdk: gradio
7
- sdk_version: 5.32.1
8
- app_file: app.py
9
- pinned: false
10
- license: mit
11
- short_description: Mathematics tools for different educational levels
12
- ---
13
 
14
- # Math Education Tools
15
 
16
- This web application provides a comprehensive suite of mathematical tools and interactive calculators, categorized by educational levels from elementary school through university. Built with Python and featuring user-friendly Gradio interfaces, it aims to assist with learning and performing a wide array of mathematical operations.
17
 
18
  ## Features
19
 
20
- ### Text Utils
21
-
22
- - Letter Counter: Count occurrences of a specific letter in a word
23
-
24
- ### Elementary School Math
25
-
26
- - Addition: Add two numbers
27
- - Subtraction: Subtract one number from another
28
- - Multiplication: Multiply two numbers
29
- - Division: Divide one number by another
30
- - Greatest Common Divisor (GCD): Find the GCD of two integers.
31
- - Least Common Multiple (LCM): Find the LCM of two integers.
32
- - Prime Number Checker: Check if a number is prime.
33
- - Array Calculation: Perform basic operations on a list of numbers.
34
- - Array Calculation with Visualization: Array calculation with a number line plot.
35
-
36
- ### Middle School Math
37
-
38
- - Linear Equation Solver: Solve equations of the form ax = b.
39
- - Quadratic Expression Evaluator: Calculate the value of axยฒ + bx + c for a given x.
40
- - Quadratic Equation Solver: Find roots of axยฒ + bx + c = 0.
41
- - Radical Simplifier: Simplify square roots (e.g., โˆš12 to 2โˆš3).
42
- - Polynomial Operations: Add, subtract, and multiply polynomials.
43
-
44
- ### High School Math
45
-
46
- - Trigonometry Calculator: Calculate sine, cosine, and tangent values for angles in degrees.
47
- - Inverse Trigonometric Functions: Calculate asin, acos, atan in degrees.
48
- - Trigonometric Equation Solver: Solve basic trigonometric equations.
49
- - Trigonometric Identities: Demonstrate common identities like sinยฒ(x) + cosยฒ(x) = 1.
50
-
51
- ### University Math
52
-
53
- #### Calculus
54
-
55
- - Polynomial Derivative: Find the derivative of a polynomial function.
56
- - Polynomial Integration: Find the indefinite integral of a polynomial function.
57
- - Limits: Calculate the limit of an expression as a variable approaches a point.
58
- - Series Expansion: Compute Taylor series for functions. Includes examples for Fourier series.
59
- - Partial Derivatives: Compute partial derivatives of multi-variable expressions.
60
- - Multiple Integrals: Evaluate definite multiple integrals.
61
-
62
- #### Linear Algebra
63
-
64
- - Matrix Operations: Addition, subtraction, multiplication.
65
- - Matrix Analysis: Determinant and inverse of matrices.
66
- - Vector Operations: Addition, subtraction, dot product, and cross product (for 3D vectors).
67
- - System Solver: Solve systems of linear equations (Ax = B).
68
-
69
- #### Differential Equations
70
-
71
- - First-Order ODEs: Solve single or systems of first-order ordinary differential equations with initial conditions.
72
- - Second-Order ODEs: Solve second-order ordinary differential equations by converting to a system.
73
- - Solution Plotting: Visualize solutions for ODEs.
74
 
75
  ## Project Structure
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  ```
78
- โ”œโ”€โ”€ app.py # Main Gradio application file
79
- โ”œโ”€โ”€ requirements.txt # Python package dependencies
80
- โ”œโ”€โ”€ maths/ # Core mathematics modules
81
- โ”‚ โ”œโ”€โ”€ __init__.py
82
- โ”‚ โ”œโ”€โ”€ elementary/ # Elementary school level functions and interfaces
83
- โ”‚ โ”‚ โ”œโ”€โ”€ __init__.py
84
- โ”‚ โ”‚ โ”œโ”€โ”€ arithmetic.py # Logic for basic arithmetic, GCD, LCM, primes
85
- โ”‚ โ”‚ โ””โ”€โ”€ arithmetic_interface.py # Gradio interfaces for arithmetic
86
- โ”‚ โ”œโ”€โ”€ middleschool/ # Middle school level functions and interfaces
87
- โ”‚ โ”‚ โ”œโ”€โ”€ __init__.py
88
- โ”‚ โ”‚ โ”œโ”€โ”€ algebra.py # Logic for linear/quadratic equations, polynomials
89
- โ”‚ โ”‚ โ””โ”€โ”€ algebra_interface.py # Gradio interfaces for algebra
90
- โ”‚ โ”œโ”€โ”€ highschool/ # High school level functions and interfaces
91
- โ”‚ โ”‚ โ”œโ”€โ”€ __init__.py
92
- โ”‚ โ”‚ โ”œโ”€โ”€ trigonometry.py # Logic for trigonometric functions and equations
93
- โ”‚ โ”‚ โ””โ”€โ”€ trigonometry_interface.py # Gradio interfaces for trigonometry
94
- โ”‚ โ””โ”€โ”€ university/ # University level functions and interfaces
95
- โ”‚ โ”œโ”€โ”€ __init__.py
96
- โ”‚ โ”œโ”€โ”€ calculus.py # Logic for calculus (limits, derivatives, integrals, series)
97
- โ”‚ โ”œโ”€โ”€ calculus_interface.py # Gradio interfaces for calculus
98
- โ”‚ โ”œโ”€โ”€ linear_algebra.py # Logic for matrix/vector operations, linear systems
99
- โ”‚ โ”œโ”€โ”€ linear_algebra_interface.py # Gradio interfaces for linear algebra
100
- โ”‚ โ”œโ”€โ”€ differential_equations.py # Logic for solving ODEs
101
- โ”‚ โ”œโ”€โ”€ differential_equations_interface.py # Gradio interfaces for ODEs
102
- โ”‚ โ””โ”€โ”€ tests/ # Unit tests for university level modules
103
- โ”‚ โ”œโ”€โ”€ __init__.py
104
- โ”‚ โ”œโ”€โ”€ test_linear_algebra.py
105
- โ”‚ โ””โ”€โ”€ test_differential_equations.py
106
- โ””โ”€โ”€ utils/ # Utility functions and interfaces
107
- โ”œโ”€โ”€ __init__.py
108
- โ”œโ”€โ”€ text_utils.py # Logic for text processing utilities
109
- โ””โ”€โ”€ text_utils_interface.py # Gradio interface for text utils
110
- ```
111
-
112
- ## Getting Started
113
-
114
- 1. Install the required packages:
115
-
116
- ```bash
117
- pip install -r requirements.txt
118
- ```
119
-
120
- 2. Run the application:
121
-
122
- ```
123
- python app.py
124
- ```
125
-
126
- 3. Open your browser and navigate to the displayed URL (typically http://127.0.0.1:7860)
127
-
128
- ## Extending the Project
129
-
130
- To add new mathematical functions or tools:
131
-
132
- 1. **Create Logic**: Add your mathematical function/logic to an existing Python file in the appropriate `maths/<level>/` directory or create a new `.py` file for it. Ensure your functions have clear inputs, outputs, and docstrings.
133
- 2. **Create Interface**: In the corresponding `maths/<level>/` directory (or a subdirectory like `interfaces` if preferred), create a `_interface.py` file (e.g., `newfeature_interface.py`) or add to an existing one. In this file, import your function(s) and create a Gradio interface for each. Define clear input and output components (e.g., `gr.Textbox()`, `gr.Number()`, `gr.Plot()`, `gr.Image()`).
134
- 3. **Add Tests**: For more complex logic, especially at the university level, add unit tests in a corresponding `maths/<level>/tests/` directory (e.g., `test_newfeature.py`). Use the `unittest` module or `pytest`.
135
- 4. **Update Main App**: Import your new Gradio interface object(s) in the main `app.py` file. Add the interface object(s) to the list of interfaces for the relevant educational level tab (e.g., `university_interfaces_list`) and provide a corresponding name in the tab names list (e.g., `university_tab_names`).
136
- 5. **Update `__init__.py` Files**: Ensure your new modules and interface modules are importable by updating the `__init__.py` files in their respective directories if necessary (e.g., `from . import newfeature`, `from . import newfeature_interface`).
137
- 6. **Update `requirements.txt`**: If your new feature introduces new external dependencies, add them to `requirements.txt`. It's good practice to pin versions (e.g., `new_package==1.2.3`).
138
- 7. **Update README**: Document your new feature in the "Features" section and update the "Project Structure" if you added new files/directories.
139
-
140
- ## License
141
-
142
- MIT
143
-
144
- ---
145
-
146
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ # Math Tools
 
 
 
 
 
 
 
 
 
 
 
2
 
3
+ ## Overview
4
 
5
+ This application provides a suite of mathematical tools organized by topic (e.g., Algebra, Calculus, Differential Equations) rather than by education level. It's built with Python and Gradio to offer interactive calculators for various mathematical domains.
6
 
7
  ## Features
8
 
9
+ - **Arithmetic**: Addition, Subtraction, Multiplication, Division, Array Calculations (with visualization)
10
+ - **Number Theory**: GCD, LCM, Prime Checker
11
+ - **Algebra**: Expression Evaluation, Radical Simplification, Polynomial Operations
12
+ - **Equations**: Solvers for Linear, Quadratic, Trigonometric, and Linear Systems
13
+ - **Geometry**: Trigonometric Functions, Inverse Trigonometry, Identities
14
+ - **Calculus**: Derivatives, Integrals, Limits, Taylor & Fourier Series, Partial Derivatives, Multiple Integrals
15
+ - **Differential Equations**: First- and Second-Order ODE Solvers
16
+ - **Matrices**: Addition, Subtraction, Multiplication, Determinant, Inverse
17
+ - **Vectors**: Addition, Subtraction, Dot Product, Cross Product
18
+ - **Operations Research**: Branch & Bound, Dual Simplex, Simplex Solver Steps
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  ## Project Structure
21
 
22
+ ```text
23
+ counting/
24
+ โ”œโ”€โ”€ app.py # Main Gradio application with topic-based tabs
25
+ โ”œโ”€โ”€ requirements.txt # Python dependencies
26
+ โ”œโ”€โ”€ README.md # Project documentation (this file)
27
+ โ””โ”€โ”€ maths/ # Mathematical modules organized by topic
28
+ โ”œโ”€โ”€ arithmetic/ # Arithmetic logic & interfaces
29
+ โ”‚ โ”œโ”€โ”€ arithmetic.py
30
+ โ”‚ โ””โ”€โ”€ arithmetic_interface.py
31
+ โ”œโ”€โ”€ number_theory/ # Number theory logic & interfaces
32
+ โ”‚ โ”œโ”€โ”€ number_theory.py
33
+ โ”‚ โ””โ”€โ”€ number_theory_interface.py
34
+ โ”œโ”€โ”€ algebra/ # Algebra logic & interfaces
35
+ โ”‚ โ”œโ”€โ”€ algebra.py
36
+ โ”‚ โ””โ”€โ”€ algebra_interface.py
37
+ โ”œโ”€โ”€ equations/ # Equation solvers & interfaces
38
+ ๏ฟฝ๏ฟฝ๏ฟฝ โ”œโ”€โ”€ equations.py
39
+ โ”‚ โ””โ”€โ”€ equations_interface.py
40
+ โ”œโ”€โ”€ geometry/ # Trigonometry & geometry logic & interfaces
41
+ โ”‚ โ”œโ”€โ”€ geometry.py
42
+ โ”‚ โ””โ”€โ”€ geometry_interface.py
43
+ โ”œโ”€โ”€ calculus/ # Calculus logic & interfaces
44
+ โ”‚ โ”œโ”€โ”€ calculus.py
45
+ โ”‚ โ””โ”€โ”€ calculus_interface.py
46
+ โ”œโ”€โ”€ differential_equations/ # ODE solvers & interfaces
47
+ โ”‚ โ”œโ”€โ”€ differential_equations.py
48
+ โ”‚ โ””โ”€โ”€ differential_equations_interface.py
49
+ โ”œโ”€โ”€ matrices/ # Matrix operations logic & interfaces
50
+ โ”‚ โ”œโ”€โ”€ matrices.py
51
+ โ”‚ โ””โ”€โ”€ matrices_interface.py
52
+ โ”œโ”€โ”€ vectors/ # Vector operations logic & interfaces
53
+ โ”‚ โ”œโ”€โ”€ vectors.py
54
+ โ”‚ โ””โ”€โ”€ vectors_interface.py
55
+ โ””โ”€โ”€ operations_research/ # Operations research solvers & interfaces
56
+ โ”œโ”€โ”€ operations_research_interface.py
57
+ โ”œโ”€โ”€ BranchAndBoundSolver.py
58
+ โ”œโ”€โ”€ DualSimplexSolver.py
59
+ โ””โ”€โ”€ simplex_solver_with_steps.py
60
  ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -1,109 +1,127 @@
1
  import gradio as gr
2
- from utils.text_utils_interface import letter_counter_interface
3
- from maths.elementary.arithmetic_interface import (
4
  add_interface, subtract_interface, multiply_interface, divide_interface,
5
  array_calc_interface, array_calc_vis_interface,
6
  gcd_interface, lcm_interface, is_prime_interface # Assuming these were added earlier from a subtask
7
  )
8
- from maths.middleschool.algebra_interface import (
9
  solve_linear_equation_interface, evaluate_expression_interface,
10
  solve_quadratic_interface, simplify_radical_interface, polynomial_interface # Assuming these
11
  )
12
- from maths.highschool.trigonometry_interface import (
13
  trig_interface, inverse_trig_interface, solve_trig_equations_interface, trig_identities_interface # Assuming these
14
  )
15
- from maths.university.calculus_interface import (
16
  derivative_interface, integral_interface,
17
  limit_interface, taylor_series_interface, fourier_series_interface, # Assuming these
18
  partial_derivative_interface, multiple_integral_interface # Assuming these
19
  )
20
- from maths.university.linear_algebra_interface import (
 
21
  matrix_add_interface, matrix_subtract_interface, matrix_multiply_interface,
22
- matrix_determinant_interface, matrix_inverse_interface,
23
- vector_add_interface, vector_subtract_interface, vector_dot_product_interface,
24
- vector_cross_product_interface, solve_linear_system_interface
 
 
 
25
  )
26
- from maths.university.differential_equations_interface import (
 
27
  first_order_ode_interface, second_order_ode_interface
28
  )
29
- from maths.university.operations_research.operations_research_interface import (
30
  branch_and_bound_interface, dual_simplex_interface, simplex_solver_interface
31
  )
32
 
33
- # Group interfaces by education level
34
- # Note: I'm assuming previous subtasks correctly added GCD, LCM, Polynomial, Quadratic, etc. interfaces to their respective files.
35
- # If not, this app.py will have import errors for those. I'm focusing on the current task's imports.
36
- elementary_interfaces_list = [
37
- add_interface, subtract_interface, multiply_interface, divide_interface,
38
- gcd_interface, lcm_interface, is_prime_interface, # Added from subtask 1
39
- array_calc_interface, array_calc_vis_interface
40
  ]
41
- elementary_tab_names = [
42
  "Addition", "Subtraction", "Multiplication", "Division",
43
- "GCD", "LCM", "Prime Check", # Added from subtask 1
44
- "Array Calculation", "Array Calc Viz"
45
  ]
46
 
47
- middleschool_interfaces_list = [
48
- solve_linear_equation_interface, evaluate_expression_interface,
49
- solve_quadratic_interface, simplify_radical_interface, polynomial_interface # Added from subtask 2
 
 
 
 
 
 
50
  ]
51
- middleschool_tab_names = [
52
- "Linear Equations", "Evaluate Expressions",
53
- "Quadratic Solver", "Radical Simplifier", "Polynomial Ops" # Added from subtask 2
54
  ]
55
 
56
- highschool_interfaces_list = [
57
- trig_interface, inverse_trig_interface,
58
- solve_trig_equations_interface, trig_identities_interface # Added from subtask 3
 
 
 
 
59
  ]
60
- highschool_tab_names = [
61
- "Trig Functions", "Inverse Trig",
62
- "Solve Trig Eqs", "Trig Identities" # Added from subtask 3
 
63
  ]
64
 
65
- university_interfaces_list = [
66
- derivative_interface, integral_interface,
67
- limit_interface, taylor_series_interface, fourier_series_interface, # Added from subtask 4
68
- partial_derivative_interface, multiple_integral_interface, # Added from subtask 4
69
- matrix_add_interface, matrix_subtract_interface, matrix_multiply_interface,
70
- matrix_determinant_interface, matrix_inverse_interface,
71
- vector_add_interface, vector_subtract_interface, vector_dot_product_interface,
72
- vector_cross_product_interface, solve_linear_system_interface,
73
- first_order_ode_interface, second_order_ode_interface
74
- # OR Tab will be added below
75
  ]
76
- university_tab_names = [
77
- "Poly Derivatives", "Poly Integrals",
78
- "Limits", "Taylor Series", "Fourier Series", # Added from subtask 4
79
- "Partial Derivatives", "Multiple Integrals", # Added from subtask 4
80
- "Matrix Add", "Matrix Subtract", "Matrix Multiply",
81
- "Matrix Determinant", "Matrix Inverse",
82
- "Vector Add", "Vector Subtract", "Vector Dot Product",
83
- "Vector Cross Product", "Solve Linear System",
84
- "1st Order ODE", "2nd Order ODE"
85
- # "Operations Research" will be added below
86
  ]
87
 
88
- # Operations Research Tab
89
- or_interfaces_list = [branch_and_bound_interface, dual_simplex_interface, simplex_solver_interface]
90
- or_tab_names = ["Branch & Bound", "Dual Simplex", "Simplex (Steps)"]
91
- or_tab = gr.TabbedInterface(or_interfaces_list, or_tab_names, title="Operations Research Solvers")
92
-
93
- # Add OR tab to University interfaces
94
- university_interfaces_list.append(or_tab)
95
- university_tab_names.append("Operations Research")
96
 
 
 
 
 
97
 
98
- elementary_tab = gr.TabbedInterface(elementary_interfaces_list, elementary_tab_names, title="Elementary School Math")
99
- middleschool_tab = gr.TabbedInterface(middleschool_interfaces_list, middleschool_tab_names, title="Middle School Math")
100
- highschool_tab = gr.TabbedInterface(highschool_interfaces_list, highschool_tab_names, title="High School Math")
101
- university_tab = gr.TabbedInterface(university_interfaces_list, university_tab_names, title="University Math")
 
 
 
 
 
 
 
102
 
103
- # Main demo with tabs for each education level
104
  demo = gr.TabbedInterface(
105
- [letter_counter_interface, elementary_tab, middleschool_tab, highschool_tab, university_tab],
106
- ["Text Utils", "Elementary", "Middle School", "High School", "University"]
 
 
 
 
 
 
 
 
107
  )
108
 
109
  # Launch the Gradio app
 
1
  import gradio as gr
2
+ from maths.arithmetic.arithmetic_interface import (
 
3
  add_interface, subtract_interface, multiply_interface, divide_interface,
4
  array_calc_interface, array_calc_vis_interface,
5
  gcd_interface, lcm_interface, is_prime_interface # Assuming these were added earlier from a subtask
6
  )
7
+ from maths.algebra.algebra_interface import (
8
  solve_linear_equation_interface, evaluate_expression_interface,
9
  solve_quadratic_interface, simplify_radical_interface, polynomial_interface # Assuming these
10
  )
11
+ from maths.geometry.trigonometry_interface import (
12
  trig_interface, inverse_trig_interface, solve_trig_equations_interface, trig_identities_interface # Assuming these
13
  )
14
+ from maths.calculus.calculus_interface import (
15
  derivative_interface, integral_interface,
16
  limit_interface, taylor_series_interface, fourier_series_interface, # Assuming these
17
  partial_derivative_interface, multiple_integral_interface # Assuming these
18
  )
19
+
20
+ from maths.matrices.matrices_interface import (
21
  matrix_add_interface, matrix_subtract_interface, matrix_multiply_interface,
22
+ matrix_determinant_interface, matrix_inverse_interface
23
+ )
24
+
25
+ from maths.vectors.vectors_interface import (
26
+ vector_add_interface, vector_subtract_interface,
27
+ vector_dot_product_interface, vector_cross_product_interface
28
  )
29
+
30
+ from maths.differential_equations.differential_equations_interface import (
31
  first_order_ode_interface, second_order_ode_interface
32
  )
33
+ from maths.operations_research.operations_research_interface import (
34
  branch_and_bound_interface, dual_simplex_interface, simplex_solver_interface
35
  )
36
 
37
+ # Categorize interfaces by topics
38
+
39
+ arithmetic_interfaces_list = [
40
+ add_interface, subtract_interface, multiply_interface,
41
+ divide_interface, array_calc_interface, array_calc_vis_interface
 
 
42
  ]
43
+ arithmetic_tab_names = [
44
  "Addition", "Subtraction", "Multiplication", "Division",
45
+ "Array Calculation", "Array Calculation Viz"
 
46
  ]
47
 
48
+ number_theory_interfaces_list = [gcd_interface, lcm_interface, is_prime_interface]
49
+ number_theory_tab_names = ["GCD", "LCM", "Prime Check"]
50
+
51
+ algebra_interfaces_list = [evaluate_expression_interface, simplify_radical_interface, polynomial_interface]
52
+ algebra_tab_names = ["Evaluate Expressions", "Radical Simplifier", "Polynomial Ops"]
53
+
54
+ equations_interfaces_list = [
55
+ solve_linear_equation_interface, solve_quadratic_interface,
56
+ solve_trig_equations_interface
57
  ]
58
+ equations_tab_names = [
59
+ "Linear Equation Solver", "Quadratic Solver",
60
+ "Trigonometric Equation Solver"
61
  ]
62
 
63
+ geometry_interfaces_list = [trig_interface, inverse_trig_interface, trig_identities_interface]
64
+ geometry_tab_names = ["Trig Functions", "Inverse Trig", "Trig Identities"]
65
+
66
+ calculus_interfaces_list = [
67
+ derivative_interface, integral_interface, limit_interface,
68
+ taylor_series_interface, fourier_series_interface,
69
+ partial_derivative_interface, multiple_integral_interface
70
  ]
71
+ calculus_tab_names = [
72
+ "Derivative", "Integral", "Limits",
73
+ "Taylor Series", "Fourier Series",
74
+ "Partial Derivatives", "Multiple Integrals"
75
  ]
76
 
77
+ differential_equations_interfaces_list = [first_order_ode_interface, second_order_ode_interface]
78
+ differential_equations_tab_names = ["First Order ODE", "Second Order ODE"]
79
+
80
+ matrices_interfaces_list = [
81
+ matrix_add_interface, matrix_subtract_interface,
82
+ matrix_multiply_interface, matrix_determinant_interface,
83
+ matrix_inverse_interface
 
 
 
84
  ]
85
+ matrices_tab_names = [
86
+ "Matrix Addition", "Matrix Subtraction", "Matrix Multiplication",
87
+ "Matrix Determinant", "Matrix Inverse"
 
 
 
 
 
 
 
88
  ]
89
 
90
+ vectors_interfaces_list = [
91
+ vector_add_interface, vector_subtract_interface,
92
+ vector_dot_product_interface, vector_cross_product_interface
93
+ ]
94
+ vectors_tab_names = ["Vector Addition", "Vector Subtraction", "Dot Product", "Cross Product"]
 
 
 
95
 
96
+ operations_research_interfaces_list = [
97
+ branch_and_bound_interface, dual_simplex_interface, simplex_solver_interface
98
+ ]
99
+ operations_research_tab_names = ["Branch & Bound", "Dual Simplex", "Simplex Steps"]
100
 
101
+ # Create topic-based tabbed interfaces
102
+ arithmetic_tab = gr.TabbedInterface(arithmetic_interfaces_list, arithmetic_tab_names, title="Arithmetic")
103
+ number_theory_tab = gr.TabbedInterface(number_theory_interfaces_list, number_theory_tab_names, title="Number Theory")
104
+ algebra_tab = gr.TabbedInterface(algebra_interfaces_list, algebra_tab_names, title="Algebra")
105
+ equations_tab = gr.TabbedInterface(equations_interfaces_list, equations_tab_names, title="Equations")
106
+ geometry_tab = gr.TabbedInterface(geometry_interfaces_list, geometry_tab_names, title="Geometry")
107
+ calculus_tab = gr.TabbedInterface(calculus_interfaces_list, calculus_tab_names, title="Calculus")
108
+ differential_equations_tab = gr.TabbedInterface(differential_equations_interfaces_list, differential_equations_tab_names, title="Differential Equations")
109
+ matrices_tab = gr.TabbedInterface(matrices_interfaces_list, matrices_tab_names, title="Matrices")
110
+ vectors_tab = gr.TabbedInterface(vectors_interfaces_list, vectors_tab_names, title="Vectors")
111
+ operations_research_tab = gr.TabbedInterface(operations_research_interfaces_list, operations_research_tab_names, title="Operations Research")
112
 
113
+ # Main demo with topic tabs
114
  demo = gr.TabbedInterface(
115
+ [
116
+ arithmetic_tab, number_theory_tab, algebra_tab,
117
+ equations_tab, geometry_tab, calculus_tab, differential_equations_tab,
118
+ matrices_tab, vectors_tab, operations_research_tab
119
+ ],
120
+ [
121
+ "Arithmetic", "Number Theory", "Algebra",
122
+ "Equations", "Geometry", "Calculus", "Differential Equations",
123
+ "Matrices", "Vectors", "Operations Research"
124
+ ]
125
  )
126
 
127
  # Launch the Gradio app
letter_counter.py DELETED
File without changes
maths/__init__.py DELETED
@@ -1,3 +0,0 @@
1
- """
2
- Mathematics tools organized by educational levels.
3
- """
 
 
 
 
maths/{middleschool โ†’ algebra}/algebra.py RENAMED
File without changes
maths/{middleschool โ†’ algebra}/algebra_interface.py RENAMED
@@ -1,5 +1,5 @@
1
  import gradio as gr
2
- from maths.middleschool.algebra import (
3
  solve_linear_equation, evaluate_expression, solve_quadratic,
4
  simplify_radical, polynomial_operations
5
  )
 
1
  import gradio as gr
2
+ from maths.algebra.algebra import (
3
  solve_linear_equation, evaluate_expression, solve_quadratic,
4
  simplify_radical, polynomial_operations
5
  )
maths/{elementary โ†’ arithmetic}/arithmetic.py RENAMED
File without changes
maths/{elementary โ†’ arithmetic}/arithmetic_interface.py RENAMED
@@ -1,5 +1,5 @@
1
  import gradio as gr
2
- from maths.elementary.arithmetic import add, subtract, multiply, divide, calculate_array, calculate_array_with_visualization, gcd, lcm, is_prime
3
 
4
  # Elementary Math Tab
5
  add_interface = gr.Interface(
 
1
  import gradio as gr
2
+ from maths.arithmetic.arithmetic import add, subtract, multiply, divide, calculate_array, calculate_array_with_visualization, gcd, lcm, is_prime
3
 
4
  # Elementary Math Tab
5
  add_interface = gr.Interface(
maths/{university โ†’ calculus}/calculus.py RENAMED
File without changes
maths/{university โ†’ calculus}/calculus_interface.py RENAMED
@@ -1,5 +1,5 @@
1
  import gradio as gr
2
- from maths.university.calculus import (
3
  derivative_polynomial, integral_polynomial,
4
  calculate_limit, taylor_series_expansion, fourier_series_example,
5
  partial_derivative, multiple_integral
 
1
  import gradio as gr
2
+ from maths.calculus.calculus import (
3
  derivative_polynomial, integral_polynomial,
4
  calculate_limit, taylor_series_expansion, fourier_series_example,
5
  partial_derivative, multiple_integral
maths/{university โ†’ differential_equations}/differential_equations.py RENAMED
File without changes
maths/{university โ†’ differential_equations}/differential_equations_interface.py RENAMED
@@ -14,7 +14,7 @@ import ast # For safer string literal evaluation if needed for parameters
14
  import math # To make math functions available in eval scope for ODEs
15
 
16
  # Import the solver functions
17
- from maths.university.differential_equations import solve_first_order_ode, solve_second_order_ode
18
 
19
  # --- Helper Functions ---
20
 
 
14
  import math # To make math functions available in eval scope for ODEs
15
 
16
  # Import the solver functions
17
+ from maths.differential_equations.differential_equations import solve_first_order_ode, solve_second_order_ode
18
 
19
  # --- Helper Functions ---
20
 
maths/elementary/__init__.py DELETED
@@ -1,3 +0,0 @@
1
- """
2
- Elementary school level mathematics tools.
3
- """
 
 
 
 
maths/{highschool โ†’ geometry}/trigonometry.py RENAMED
File without changes
maths/{highschool โ†’ geometry}/trigonometry_interface.py RENAMED
@@ -1,5 +1,5 @@
1
  import gradio as gr
2
- from maths.highschool.trigonometry import sin_degrees, cos_degrees, tan_degrees, inverse_trig_functions, solve_trig_equations, trig_identities
3
 
4
  # High School Math Tab
5
  trig_interface = gr.Interface(
 
1
  import gradio as gr
2
+ from maths.geometry.trigonometry import sin_degrees, cos_degrees, tan_degrees, inverse_trig_functions, solve_trig_equations, trig_identities
3
 
4
  # High School Math Tab
5
  trig_interface = gr.Interface(
maths/highschool/__init__.py DELETED
@@ -1,3 +0,0 @@
1
- """
2
- Highschool level mathematics tools.
3
- """
 
 
 
 
maths/matrices/matrices.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Matrix operations for university level, using NumPy.
3
+ """
4
+ import numpy as np
5
+ from typing import List, Union
6
+
7
+ Matrix = Union[List[List[float]], np.ndarray]
8
+
9
+ def matrix_add(matrix1: Matrix, matrix2: Matrix) -> np.ndarray:
10
+ m1 = np.array(matrix1)
11
+ m2 = np.array(matrix2)
12
+ if m1.shape != m2.shape:
13
+ raise ValueError("Matrices must have the same dimensions for addition.")
14
+ return np.add(m1, m2)
15
+
16
+ def matrix_subtract(matrix1: Matrix, matrix2: Matrix) -> np.ndarray:
17
+ m1 = np.array(matrix1)
18
+ m2 = np.array(matrix2)
19
+ if m1.shape != m2.shape:
20
+ raise ValueError("Matrices must have the same dimensions for subtraction.")
21
+ return np.subtract(m1, m2)
22
+
23
+ def matrix_multiply(matrix1: Matrix, matrix2: Matrix) -> np.ndarray:
24
+ m1 = np.array(matrix1)
25
+ m2 = np.array(matrix2)
26
+ if m1.shape[1] != m2.shape[0]:
27
+ raise ValueError("Number of columns in the first matrix must equal number of rows in the second for multiplication.")
28
+ return np.dot(m1, m2)
29
+
30
+ def matrix_determinant(matrix: Matrix) -> float:
31
+ m = np.array(matrix)
32
+ if m.shape[0] != m.shape[1]:
33
+ raise ValueError("Matrix must be square to compute determinant.")
34
+ return np.linalg.det(m)
35
+
36
+ def matrix_inverse(matrix: Matrix) -> np.ndarray:
37
+ m = np.array(matrix)
38
+ if m.shape[0] != m.shape[1]:
39
+ raise ValueError("Matrix must be square to compute inverse.")
40
+ return np.linalg.inv(m)
maths/{university/linear_algebra_interface.py โ†’ matrices/matrices_interface.py} RENAMED
@@ -1,92 +1,53 @@
1
  """
2
- Gradio Interface for Linear Algebra operations.
3
  """
4
  import gradio as gr
5
  import numpy as np
6
- import json # For parsing matrices and vectors easily
7
  from typing import Union
8
-
9
- from maths.university.linear_algebra import (
10
  matrix_add, matrix_subtract, matrix_multiply,
11
- matrix_determinant, matrix_inverse,
12
- vector_add, vector_subtract, vector_dot_product,
13
- vector_cross_product, solve_linear_system
14
  )
15
 
16
- # Helper functions to parse inputs
17
  def parse_matrix(matrix_str: str, allow_empty_rows_cols=False) -> np.ndarray:
18
- """Parses a string representation of a matrix (JSON format or comma/semicolon separated) into a NumPy array."""
19
  try:
20
- # Try JSON parsing first for structure like [[1,2],[3,4]]
21
  m = json.loads(matrix_str)
22
  arr = np.array(m, dtype=float)
23
  if not allow_empty_rows_cols and (arr.shape[0] == 0 or (arr.ndim > 1 and arr.shape[1] == 0)):
24
  raise ValueError("Matrix cannot have zero rows or columns.")
25
- if arr.ndim == 1 and arr.shape[0] > 0: # Handles single row matrix like "[1,2,3]"
26
- arr = arr.reshape(1, -1)
27
- elif arr.ndim == 0 and not allow_empty_rows_cols : # Handles scalar input like "5" if not allowed
28
  raise ValueError("Input is a scalar, not a matrix.")
29
  return arr
30
  except (json.JSONDecodeError, TypeError, ValueError) as e_json:
31
- # Fallback for simpler comma/semicolon separated format, e.g. "1,2;3,4"
32
  try:
33
  rows = [list(map(float, row.split(','))) for row in matrix_str.split(';') if row.strip()]
34
  if not rows and not allow_empty_rows_cols:
35
  raise ValueError("Matrix input is empty.")
36
- if not rows and allow_empty_rows_cols: # e.g. for an empty matrix if needed
37
  return np.array([])
38
-
39
- # Check for consistent row lengths
40
  if len(rows) > 1:
41
  first_row_len = len(rows[0])
42
  if not all(len(r) == first_row_len for r in rows):
43
  raise ValueError("All rows must have the same number of columns.")
44
-
45
  arr = np.array(rows, dtype=float)
46
  if not allow_empty_rows_cols and (arr.shape[0] == 0 or (arr.ndim > 1 and arr.shape[1] == 0)):
47
- raise ValueError("Matrix cannot have zero rows or columns after parsing.")
48
  return arr
49
-
50
  except ValueError as e_csv:
51
  raise gr.Error(f"Invalid matrix format. Use JSON (e.g., [[1,2],[3,4]]) or comma/semicolon (e.g., 1,2;3,4). Error: {e_csv} (Original JSON error: {e_json})")
52
- except Exception as e_gen: # Catch any other parsing errors
53
- raise gr.Error(f"General error parsing matrix: {e_gen}")
54
-
55
-
56
- def parse_vector(vector_str: str) -> np.ndarray:
57
- """Parses a string representation of a vector (JSON or comma-separated) into a NumPy array."""
58
- try:
59
- # Try JSON parsing for lists like [1,2,3]
60
- v = json.loads(vector_str)
61
- arr = np.array(v, dtype=float)
62
- if arr.ndim != 1:
63
- raise ValueError("Vector must be 1-dimensional.")
64
- if arr.shape[0] == 0:
65
- raise ValueError("Vector cannot be empty.")
66
- return arr
67
- except (json.JSONDecodeError, TypeError, ValueError) as e_json:
68
- # Fallback for simpler comma-separated format e.g. "1,2,3"
69
- try:
70
- if not vector_str.strip():
71
- raise ValueError("Vector input is empty.")
72
- arr = np.array([float(x.strip()) for x in vector_str.split(',') if x.strip()], dtype=float)
73
- if arr.shape[0] == 0: # case like "," or " , "
74
- raise ValueError("Vector cannot be empty after parsing.")
75
- return arr
76
- except ValueError as e_csv:
77
- raise gr.Error(f"Invalid vector format. Use JSON (e.g., [1,2,3]) or comma-separated (e.g., 1,2,3). Error: {e_csv} (Original JSON error: {e_json})")
78
  except Exception as e_gen:
79
- raise gr.Error(f"General error parsing vector: {e_gen}")
80
 
81
  def format_output(data: Union[np.ndarray, float, str]) -> str:
82
- """Formats NumPy array or float for display, handling errors."""
83
  if isinstance(data, np.ndarray):
84
- return str(data.tolist()) # Convert to list for cleaner display
85
  elif isinstance(data, (float, int, str)):
86
  return str(data)
87
  return "Output type not recognized."
88
 
89
- # --- Matrix Interfaces ---
90
  matrix_add_interface = gr.Interface(
91
  fn=lambda m1_str, m2_str: format_output(matrix_add(parse_matrix(m1_str), parse_matrix(m2_str))),
92
  inputs=[
@@ -135,63 +96,3 @@ matrix_inverse_interface = gr.Interface(
135
  title="Matrix Inverse",
136
  description="Calculates the inverse of a square matrix. Matrix must be invertible (non-singular)."
137
  )
138
-
139
- # --- Vector Interfaces ---
140
- vector_add_interface = gr.Interface(
141
- fn=lambda v1_str, v2_str: format_output(vector_add(parse_vector(v1_str), parse_vector(v2_str))),
142
- inputs=[
143
- gr.Textbox(label="Vector 1 (JSON or CSV format)", placeholder="e.g., [1,2,3] or 1,2,3"),
144
- gr.Textbox(label="Vector 2 (JSON or CSV format)", placeholder="e.g., [4,5,6] or 4,5,6")
145
- ],
146
- outputs=gr.Textbox(label="Resulting Vector"),
147
- title="Vector Addition",
148
- description="Adds two vectors. Ensure they have the same dimensions."
149
- )
150
-
151
- vector_subtract_interface = gr.Interface(
152
- fn=lambda v1_str, v2_str: format_output(vector_subtract(parse_vector(v1_str), parse_vector(v2_str))),
153
- inputs=[
154
- gr.Textbox(label="Vector 1 (Minuend)", placeholder="e.g., [4,5,6]"),
155
- gr.Textbox(label="Vector 2 (Subtrahend)", placeholder="e.g., [1,2,3]")
156
- ],
157
- outputs=gr.Textbox(label="Resulting Vector"),
158
- title="Vector Subtraction",
159
- description="Subtracts the second vector from the first. Ensure they have the same dimensions."
160
- )
161
-
162
- vector_dot_product_interface = gr.Interface(
163
- fn=lambda v1_str, v2_str: format_output(vector_dot_product(parse_vector(v1_str), parse_vector(v2_str))),
164
- inputs=[
165
- gr.Textbox(label="Vector 1", placeholder="e.g., [1,2,3]"),
166
- gr.Textbox(label="Vector 2", placeholder="e.g., [4,5,6]")
167
- ],
168
- outputs=gr.Textbox(label="Dot Product (Scalar)"),
169
- title="Vector Dot Product",
170
- description="Calculates the dot product of two vectors. Ensure they have the same dimensions."
171
- )
172
-
173
- vector_cross_product_interface = gr.Interface(
174
- fn=lambda v1_str, v2_str: format_output(vector_cross_product(parse_vector(v1_str), parse_vector(v2_str))),
175
- inputs=[
176
- gr.Textbox(label="Vector 1 (3D)", placeholder="e.g., [1,2,3]"),
177
- gr.Textbox(label="Vector 2 (3D)", placeholder="e.g., [4,5,6]")
178
- ],
179
- outputs=gr.Textbox(label="Resulting Vector (3D)"),
180
- title="Vector Cross Product",
181
- description="Calculates the cross product of two 3D vectors."
182
- )
183
-
184
- # --- Solve Linear System Interface ---
185
- solve_linear_system_interface = gr.Interface(
186
- fn=lambda A_str, B_str: format_output(solve_linear_system(parse_matrix(A_str), parse_vector(B_str))),
187
- inputs=[
188
- gr.Textbox(label="Coefficients Matrix (A)", placeholder="For Ax=B. e.g., [[2,1],[1,1]] for 2x+y, x+y"),
189
- gr.Textbox(label="Constants Vector (B)", placeholder="For Ax=B. e.g., [1,1] for =1, =1")
190
- ],
191
- outputs=gr.Textbox(label="Solution Vector (x)"),
192
- title="Linear System Solver (Ax = B)",
193
- description="Solves a system of linear equations Ax = B. Matrix A must be square and invertible."
194
- )
195
-
196
- # It might be useful to group these interfaces in a Gradio TabbedInterface or Blocks layout in a main app file.
197
- # For now, this file just defines the individual interfaces.
 
1
  """
2
+ Gradio Interface for Matrix operations.
3
  """
4
  import gradio as gr
5
  import numpy as np
6
+ import json
7
  from typing import Union
8
+ from maths.matrices.matrices import (
 
9
  matrix_add, matrix_subtract, matrix_multiply,
10
+ matrix_determinant, matrix_inverse
 
 
11
  )
12
 
 
13
  def parse_matrix(matrix_str: str, allow_empty_rows_cols=False) -> np.ndarray:
 
14
  try:
 
15
  m = json.loads(matrix_str)
16
  arr = np.array(m, dtype=float)
17
  if not allow_empty_rows_cols and (arr.shape[0] == 0 or (arr.ndim > 1 and arr.shape[1] == 0)):
18
  raise ValueError("Matrix cannot have zero rows or columns.")
19
+ if arr.ndim == 1 and arr.shape[0] > 0:
20
+ arr = arr.reshape(1, -1)
21
+ elif arr.ndim == 0 and not allow_empty_rows_cols:
22
  raise ValueError("Input is a scalar, not a matrix.")
23
  return arr
24
  except (json.JSONDecodeError, TypeError, ValueError) as e_json:
 
25
  try:
26
  rows = [list(map(float, row.split(','))) for row in matrix_str.split(';') if row.strip()]
27
  if not rows and not allow_empty_rows_cols:
28
  raise ValueError("Matrix input is empty.")
29
+ if not rows and allow_empty_rows_cols:
30
  return np.array([])
 
 
31
  if len(rows) > 1:
32
  first_row_len = len(rows[0])
33
  if not all(len(r) == first_row_len for r in rows):
34
  raise ValueError("All rows must have the same number of columns.")
 
35
  arr = np.array(rows, dtype=float)
36
  if not allow_empty_rows_cols and (arr.shape[0] == 0 or (arr.ndim > 1 and arr.shape[1] == 0)):
37
+ raise ValueError("Matrix cannot have zero rows or columns after parsing.")
38
  return arr
 
39
  except ValueError as e_csv:
40
  raise gr.Error(f"Invalid matrix format. Use JSON (e.g., [[1,2],[3,4]]) or comma/semicolon (e.g., 1,2;3,4). Error: {e_csv} (Original JSON error: {e_json})")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  except Exception as e_gen:
42
+ raise gr.Error(f"General error parsing matrix: {e_gen}")
43
 
44
  def format_output(data: Union[np.ndarray, float, str]) -> str:
 
45
  if isinstance(data, np.ndarray):
46
+ return str(data.tolist())
47
  elif isinstance(data, (float, int, str)):
48
  return str(data)
49
  return "Output type not recognized."
50
 
 
51
  matrix_add_interface = gr.Interface(
52
  fn=lambda m1_str, m2_str: format_output(matrix_add(parse_matrix(m1_str), parse_matrix(m2_str))),
53
  inputs=[
 
96
  title="Matrix Inverse",
97
  description="Calculates the inverse of a square matrix. Matrix must be invertible (non-singular)."
98
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
maths/middleschool/__init__.py DELETED
@@ -1,3 +0,0 @@
1
- """
2
- Middle school level mathematics tools.
3
- """
 
 
 
 
maths/{university/operations_research โ†’ operations_research}/BranchAndBoundSolver.py RENAMED
File without changes
maths/{university/operations_research โ†’ operations_research}/DualSimplexSolver.py RENAMED
File without changes
maths/{university/operations_research โ†’ operations_research}/bnb.ipynb RENAMED
File without changes
maths/{university/operations_research โ†’ operations_research}/dual.ipynb RENAMED
File without changes
maths/{university/operations_research โ†’ operations_research}/get_user_input.py RENAMED
File without changes
maths/{university/operations_research โ†’ operations_research}/operations_research_interface.py RENAMED
File without changes
maths/{university/operations_research โ†’ operations_research}/simplex_solver_with_steps.py RENAMED
File without changes
maths/{university/operations_research โ†’ operations_research}/solve_lp_via_dual.py RENAMED
File without changes
maths/{university/operations_research โ†’ operations_research}/solve_primal_directly.py RENAMED
File without changes
maths/university/__init__.py DELETED
@@ -1,9 +0,0 @@
1
- """
2
- University level mathematics tools.
3
- """
4
-
5
- from . import calculus
6
- from . import linear_algebra
7
- from . import linear_algebra_interface
8
- from . import differential_equations
9
- from . import differential_equations_interface
 
 
 
 
 
 
 
 
 
 
maths/university/linear_algebra.py DELETED
@@ -1,249 +0,0 @@
1
- """
2
- Linear Algebra operations for university level, using NumPy.
3
- """
4
- import numpy as np
5
- from typing import List, Union, Tuple
6
-
7
- Matrix = Union[List[List[float]], np.ndarray]
8
- Vector = Union[List[float], np.ndarray]
9
-
10
- def matrix_add(matrix1: Matrix, matrix2: Matrix) -> np.ndarray:
11
- """
12
- Adds two matrices.
13
-
14
- Args:
15
- matrix1: The first matrix.
16
- matrix2: The second matrix.
17
-
18
- Returns:
19
- The resulting matrix as a NumPy array.
20
- Raises:
21
- ValueError: If matrices have incompatible shapes.
22
- """
23
- m1 = np.array(matrix1)
24
- m2 = np.array(matrix2)
25
- if m1.shape != m2.shape:
26
- raise ValueError("Matrices must have the same dimensions for addition.")
27
- return np.add(m1, m2)
28
-
29
- def matrix_subtract(matrix1: Matrix, matrix2: Matrix) -> np.ndarray:
30
- """
31
- Subtracts the second matrix from the first.
32
-
33
- Args:
34
- matrix1: The first matrix.
35
- matrix2: The second matrix.
36
-
37
- Returns:
38
- The resulting matrix as a NumPy array.
39
- Raises:
40
- ValueError: If matrices have incompatible shapes.
41
- """
42
- m1 = np.array(matrix1)
43
- m2 = np.array(matrix2)
44
- if m1.shape != m2.shape:
45
- raise ValueError("Matrices must have the same dimensions for subtraction.")
46
- return np.subtract(m1, m2)
47
-
48
- def matrix_multiply(matrix1: Matrix, matrix2: Matrix) -> np.ndarray:
49
- """
50
- Multiplies two matrices.
51
-
52
- Args:
53
- matrix1: The first matrix.
54
- matrix2: The second matrix.
55
-
56
- Returns:
57
- The resulting matrix as a NumPy array.
58
- Raises:
59
- ValueError: If matrices have incompatible shapes for multiplication.
60
- """
61
- m1 = np.array(matrix1)
62
- m2 = np.array(matrix2)
63
- if m1.shape[1] != m2.shape[0]:
64
- raise ValueError("Number of columns in the first matrix must equal number of rows in the second for multiplication.")
65
- return np.dot(m1, m2)
66
-
67
- def matrix_determinant(matrix: Matrix) -> float:
68
- """
69
- Calculates the determinant of a square matrix.
70
-
71
- Args:
72
- matrix: The matrix (must be square).
73
-
74
- Returns:
75
- The determinant of the matrix.
76
- Raises:
77
- ValueError: If the matrix is not square.
78
- """
79
- m = np.array(matrix)
80
- if m.shape[0] != m.shape[1]:
81
- raise ValueError("Matrix must be square to calculate its determinant.")
82
- return np.linalg.det(m)
83
-
84
- def matrix_inverse(matrix: Matrix) -> np.ndarray:
85
- """
86
- Calculates the inverse of a square matrix.
87
-
88
- Args:
89
- matrix: The matrix (must be square and invertible).
90
-
91
- Returns:
92
- The inverse of the matrix as a NumPy array.
93
- Raises:
94
- ValueError: If the matrix is not square.
95
- np.linalg.LinAlgError: If the matrix is singular (not invertible).
96
- """
97
- m = np.array(matrix)
98
- if m.shape[0] != m.shape[1]:
99
- raise ValueError("Matrix must be square to calculate its inverse.")
100
- return np.linalg.inv(m)
101
-
102
- def vector_add(vector1: Vector, vector2: Vector) -> np.ndarray:
103
- """
104
- Adds two vectors.
105
-
106
- Args:
107
- vector1: The first vector.
108
- vector2: The second vector.
109
-
110
- Returns:
111
- The resulting vector as a NumPy array.
112
- Raises:
113
- ValueError: If vectors have incompatible shapes.
114
- """
115
- v1 = np.array(vector1)
116
- v2 = np.array(vector2)
117
- if v1.shape != v2.shape:
118
- raise ValueError("Vectors must have the same dimensions for addition.")
119
- return np.add(v1, v2)
120
-
121
- def vector_subtract(vector1: Vector, vector2: Vector) -> np.ndarray:
122
- """
123
- Subtracts the second vector from the first.
124
-
125
- Args:
126
- vector1: The first vector.
127
- vector2: The second vector.
128
-
129
- Returns:
130
- The resulting vector as a NumPy array.
131
- Raises:
132
- ValueError: If vectors have incompatible shapes.
133
- """
134
- v1 = np.array(vector1)
135
- v2 = np.array(vector2)
136
- if v1.shape != v2.shape:
137
- raise ValueError("Vectors must have the same dimensions for subtraction.")
138
- return np.subtract(v1, v2)
139
-
140
- def vector_dot_product(vector1: Vector, vector2: Vector) -> float:
141
- """
142
- Calculates the dot product of two vectors.
143
-
144
- Args:
145
- vector1: The first vector.
146
- vector2: The second vector.
147
-
148
- Returns:
149
- The dot product of the vectors.
150
- Raises:
151
- ValueError: If vectors have incompatible shapes.
152
- """
153
- v1 = np.array(vector1)
154
- v2 = np.array(vector2)
155
- if v1.shape != v2.shape:
156
- raise ValueError("Vectors must have the same dimensions for dot product.")
157
- return np.dot(v1, v2)
158
-
159
- def vector_cross_product(vector1: Vector, vector2: Vector) -> np.ndarray:
160
- """
161
- Calculates the cross product of two 3D vectors.
162
-
163
- Args:
164
- vector1: The first 3D vector.
165
- vector2: The second 3D vector.
166
-
167
- Returns:
168
- The resulting 3D vector as a NumPy array.
169
- Raises:
170
- ValueError: If vectors are not 3-dimensional.
171
- """
172
- v1 = np.array(vector1)
173
- v2 = np.array(vector2)
174
- if v1.shape != (3,) or v2.shape != (3,):
175
- raise ValueError("Cross product is only defined for 3-dimensional vectors.")
176
- return np.cross(v1, v2)
177
-
178
- def solve_linear_system(coefficients_matrix: Matrix, constants_vector: Vector) -> np.ndarray:
179
- """
180
- Solves a system of linear equations Ax = B.
181
-
182
- Args:
183
- coefficients_matrix (A): The matrix of coefficients.
184
- constants_vector (B): The vector of constants.
185
-
186
- Returns:
187
- The solution vector (x) as a NumPy array.
188
- Raises:
189
- ValueError: If the coefficient matrix is not square or dimensions are incompatible.
190
- np.linalg.LinAlgError: If the system has no unique solution (e.g., singular matrix).
191
- """
192
- A = np.array(coefficients_matrix)
193
- B = np.array(constants_vector)
194
-
195
- if A.shape[0] != A.shape[1]:
196
- raise ValueError("Coefficient matrix must be square.")
197
- if A.shape[0] != B.shape[0]:
198
- raise ValueError("Number of rows in coefficient matrix must match number of elements in constants vector.")
199
-
200
- return np.linalg.solve(A, B)
201
-
202
- # Example Usage (can be removed or commented out for production)
203
- if __name__ == '__main__':
204
- # Matrix examples
205
- m_a = [[1, 2], [3, 4]]
206
- m_b = [[5, 6], [7, 8]]
207
- print("Matrix A+B:", matrix_add(m_a, m_b))
208
- print("Matrix A*B:", matrix_multiply(m_a, m_b))
209
- m_c = [[1,2,3],[4,5,6],[7,8,9]] # Singular
210
- m_d = [[1,2,3],[0,1,4],[5,6,0]]
211
- print("Determinant of D:", matrix_determinant(m_d))
212
- try:
213
- print("Inverse of D:", matrix_inverse(m_d))
214
- except np.linalg.LinAlgError as e:
215
- print("Error inverting D:", e)
216
- try:
217
- print("Inverse of C (singular):", matrix_inverse(m_c)) # Should raise error
218
- except np.linalg.LinAlgError as e:
219
- print("Error inverting C:", e)
220
-
221
-
222
- # Vector examples
223
- v_a = [1, 2, 3]
224
- v_b = [4, 5, 6]
225
- print("Vector A+B:", vector_add(v_a, v_b))
226
- print("Vector A.B (dot):", vector_dot_product(v_a, v_b))
227
- print("Vector AxB (cross):", vector_cross_product(v_a, v_b))
228
-
229
- v_c = [1,2]
230
- v_d = [3,4]
231
- try:
232
- print(vector_cross_product(v_c,v_d)) # Should error
233
- except ValueError as e:
234
- print("Error cross product:", e)
235
-
236
- # Solve linear system example
237
- # 2x + y = 1
238
- # x + y = 1
239
- coeffs = [[2, 1], [1, 1]]
240
- consts = [1, 1]
241
- print("Solution to 2x+y=1, x+y=1 is:", solve_linear_system(coeffs, consts)) # Expected: [0, 1]
242
-
243
- # Singular system
244
- coeffs_singular = [[1, 1], [1, 1]]
245
- consts_singular = [1, 2] # No solution
246
- try:
247
- print("Solution to singular system:", solve_linear_system(coeffs_singular, consts_singular))
248
- except np.linalg.LinAlgError as e:
249
- print("Error solving singular system:", e)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
maths/university/tests/__init__.py DELETED
@@ -1,2 +0,0 @@
1
- # This file makes 'tests' a Python package.
2
- # It can be empty.
 
 
 
maths/university/tests/test_differential_equations.py DELETED
@@ -1,133 +0,0 @@
1
- import unittest
2
- import numpy as np
3
- import math
4
- from numpy.testing import assert_array_almost_equal
5
-
6
- # Adjust import path as necessary
7
- from maths.university.differential_equations import solve_first_order_ode, solve_second_order_ode
8
-
9
- class TestDifferentialEquations(unittest.TestCase):
10
-
11
- def test_solve_simple_first_order_ode_constant_rate(self):
12
- """Test dy/dt = k, e.g., dy/dt = 2 with y(0)=1. Solution y(t) = 2t + 1."""
13
- k = 2.0
14
- y_initial = 1.0
15
-
16
- def ode_func(t, y):
17
- # For a system, y is an array. Here, it's a single equation, so y[0]
18
- # solve_ivp always passes y as at least a 1-element array.
19
- return k
20
-
21
- t_span = (0, 5)
22
- t_eval_count = 50
23
- y0 = [y_initial] # Initial condition must be a list or 1D array for solve_ivp
24
-
25
- result = solve_first_order_ode(ode_func, t_span, y0, t_eval_count=t_eval_count)
26
-
27
- self.assertTrue(result['success'], msg=f"Solver failed: {result['message']}")
28
- self.assertIsInstance(result['t'], np.ndarray)
29
- self.assertIsInstance(result['y'], np.ndarray)
30
-
31
- self.assertEqual(result['t'].shape, (t_eval_count,))
32
- # solve_ivp returns y with shape (n_equations, n_timepoints)
33
- self.assertEqual(result['y'].shape, (1, t_eval_count))
34
-
35
- # Check analytical solution: y(t) = k*t + y0
36
- expected_y = k * result['t'] + y_initial
37
- assert_array_almost_equal(result['y'][0], expected_y, decimal=5,
38
- err_msg="Numerical solution does not match analytical solution for dy/dt=k.")
39
-
40
- def test_solve_simple_first_order_ode_exponential_decay(self):
41
- """Test dy/dt = -k*y, e.g., dy/dt = -0.5*y with y(0)=10. Solution y(t) = 10*exp(-0.5t)."""
42
- k = 0.5
43
- y_initial = 10.0
44
-
45
- def ode_func(t, y):
46
- return -k * y[0] # y is [y_val]
47
-
48
- t_span = (0, 3)
49
- t_eval_count = 30
50
- y0 = [y_initial]
51
-
52
- result = solve_first_order_ode(ode_func, t_span, y0, t_eval_count=t_eval_count)
53
-
54
- self.assertTrue(result['success'], msg=f"Solver failed for exponential decay: {result['message']}")
55
- self.assertEqual(result['t'].shape, (t_eval_count,))
56
- self.assertEqual(result['y'].shape, (1, t_eval_count))
57
-
58
- # Check analytical solution: y(t) = y0 * exp(-k*t)
59
- expected_y = y_initial * np.exp(-k * result['t'])
60
- assert_array_almost_equal(result['y'][0], expected_y, decimal=5,
61
- err_msg="Numerical solution does not match analytical for exponential decay.")
62
-
63
-
64
- def test_solve_simple_second_order_ode_constant_acceleration(self):
65
- """Test dยฒy/dtยฒ = a, e.g., dยฒy/dtยฒ = 2 with y(0)=1, y'(0)=0.5.
66
- Solution y'(t) = a*t + y'(0) => y'(t) = 2t + 0.5
67
- Solution y(t) = 0.5*a*tยฒ + y'(0)*t + y(0) => y(t) = tยฒ + 0.5t + 1
68
- """
69
- accel = 2.0
70
- y_initial = 1.0
71
- dy_dt_initial = 0.5
72
-
73
- def ode_func_second_order(t, y_val, dy_dt_val):
74
- return accel # dยฒy/dtยฒ = constant
75
-
76
- t_span = (0, 4)
77
- t_eval_count = 40
78
-
79
- result = solve_second_order_ode(
80
- ode_func_second_order, t_span, y_initial, dy_dt_initial, t_eval_count=t_eval_count
81
- )
82
-
83
- self.assertTrue(result['success'], msg=f"Solver failed for 2nd order const accel: {result['message']}")
84
- self.assertIsInstance(result['t'], np.ndarray)
85
- self.assertIsInstance(result['y'], np.ndarray)
86
- self.assertIsInstance(result['dy_dt'], np.ndarray)
87
-
88
- self.assertEqual(result['t'].shape, (t_eval_count,))
89
- self.assertEqual(result['y'].shape, (t_eval_count,)) # Output y is 1D array
90
- self.assertEqual(result['dy_dt'].shape, (t_eval_count,)) # Output dy_dt is 1D array
91
-
92
- # Check analytical solution for y(t)
93
- expected_y = 0.5 * accel * result['t']**2 + dy_dt_initial * result['t'] + y_initial
94
- assert_array_almost_equal(result['y'], expected_y, decimal=5,
95
- err_msg="Numerical y(t) does not match analytical for const accel.")
96
-
97
- # Check analytical solution for dy/dt(t)
98
- expected_dy_dt = accel * result['t'] + dy_dt_initial
99
- assert_array_almost_equal(result['dy_dt'], expected_dy_dt, decimal=5,
100
- err_msg="Numerical dy/dt(t) does not match analytical for const accel.")
101
-
102
- def test_solve_damped_oscillator_second_order(self):
103
- """Test dยฒy/dtยฒ = -b*(dy/dt) - k*y (damped harmonic oscillator).
104
- This is more complex and won't have a trivial analytical solution form for all parameters,
105
- so we mainly check if it runs and produces output of the correct shape.
106
- """
107
- damping_b = 0.5 # Damping coefficient
108
- spring_k = 2.0 # Spring constant (normalized for m=1)
109
- y_initial = 1.0
110
- dy_dt_initial = 0.0
111
-
112
- def damped_oscillator_func(t, y, dy_dt):
113
- return -damping_b * dy_dt - spring_k * y
114
-
115
- t_span = (0, 10)
116
- t_eval_count = 100
117
-
118
- result = solve_second_order_ode(
119
- damped_oscillator_func, t_span, y_initial, dy_dt_initial, t_eval_count=t_eval_count
120
- )
121
-
122
- self.assertTrue(result['success'], msg=f"Solver failed for damped oscillator: {result['message']}")
123
- self.assertEqual(result['t'].shape, (t_eval_count,))
124
- self.assertEqual(result['y'].shape, (t_eval_count,))
125
- self.assertEqual(result['dy_dt'].shape, (t_eval_count,))
126
- # For a damped oscillator starting from rest at y=1, y should decrease initially (or oscillate around 0)
127
- # This is just a sanity check, not a strict assertion of values.
128
- if len(result['y']) > 1:
129
- self.assertTrue(result['y'][0] > result['y'][-1] or result['y'][0] < result['y'][-1] or result['y'][0] != result['y'][1])
130
-
131
-
132
- if __name__ == '__main__':
133
- unittest.main(argv=['first-arg-is-ignored'], exit=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
maths/university/tests/test_linear_algebra.py DELETED
@@ -1,132 +0,0 @@
1
- import unittest
2
- import numpy as np
3
- from numpy.testing import assert_array_almost_equal, assert_raises
4
-
5
- # Adjust the import path based on your project structure if necessary
6
- # Assuming 'maths' is a top-level directory in PYTHONPATH or current working directory
7
- from maths.university.linear_algebra import (
8
- matrix_add, matrix_subtract, matrix_multiply,
9
- matrix_determinant, matrix_inverse,
10
- vector_add, vector_subtract, vector_dot_product,
11
- vector_cross_product, solve_linear_system
12
- )
13
-
14
- class TestLinearAlgebra(unittest.TestCase):
15
-
16
- def test_matrix_add(self):
17
- m1 = np.array([[1, 2], [3, 4]])
18
- m2 = np.array([[5, 6], [7, 8]])
19
- expected = np.array([[6, 8], [10, 12]])
20
- assert_array_almost_equal(matrix_add(m1, m2), expected)
21
- assert_array_almost_equal(matrix_add([[1,2],[3,4]], [[5,6],[7,8]]), expected)
22
-
23
- def test_matrix_multiply(self):
24
- m1 = np.array([[1, 2], [3, 4]])
25
- m2 = np.array([[5, 6], [7, 8]]) # 2x2
26
- expected = np.array([[19, 22], [43, 50]]) # (1*5+2*7), (1*6+2*8) etc.
27
- assert_array_almost_equal(matrix_multiply(m1, m2), expected)
28
-
29
- m3 = np.array([[1,2,3],[4,5,6]]) # 2x3
30
- m4 = np.array([[7,8],[9,10],[11,12]]) # 3x2
31
- expected2 = np.array([[58,64],[139,154]])
32
- assert_array_almost_equal(matrix_multiply(m3,m4),expected2)
33
-
34
- # Test incompatible shapes
35
- with assert_raises(ValueError):
36
- matrix_multiply(m1, m3) # 2x2 and 2x3 not compatible like this
37
-
38
- def test_matrix_determinant(self):
39
- m1 = np.array([[1, 2], [3, 4]]) # det = 1*4 - 2*3 = 4 - 6 = -2
40
- self.assertAlmostEqual(matrix_determinant(m1), -2.0)
41
-
42
- m2 = np.array([[3, 1, 0], [2, 0, 1], [0, 2, 4]])
43
- # Det = 3(0-2) - 1(8-0) + 0 = -6 - 8 = -14
44
- self.assertAlmostEqual(matrix_determinant(m2), -14.0)
45
-
46
- m_singular = np.array([[1,2],[2,4]]) # det = 0
47
- self.assertAlmostEqual(matrix_determinant(m_singular), 0.0)
48
-
49
- def test_matrix_inverse(self):
50
- m1 = np.array([[1, 2], [3, 7]]) # det = 7-6 = 1
51
- # inv = 1/1 * [[7, -2], [-3, 1]]
52
- expected_inv1 = np.array([[7, -2], [-3, 1]])
53
- assert_array_almost_equal(matrix_inverse(m1), expected_inv1)
54
-
55
- m_non_square = np.array([[1,2,3],[4,5,6]])
56
- with assert_raises(ValueError): # Specific to our implementation if it checks before numpy
57
- matrix_inverse(m_non_square)
58
-
59
- m_singular = np.array([[1, 2], [2, 4]]) # Determinant is 0
60
- with assert_raises(np.linalg.LinAlgError): # Numpy's error for singular matrix
61
- matrix_inverse(m_singular)
62
-
63
- def test_vector_dot_product(self):
64
- v1 = np.array([1, 2, 3])
65
- v2 = np.array([4, 5, 6])
66
- # 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32
67
- self.assertAlmostEqual(vector_dot_product(v1, v2), 32.0)
68
- self.assertAlmostEqual(vector_dot_product([1,0,-1], [1,1,1]), 0.0) # Orthogonal
69
-
70
- def test_vector_cross_product(self):
71
- v1 = np.array([1, 0, 0]) # i
72
- v2 = np.array([0, 1, 0]) # j
73
- expected_ij = np.array([0, 0, 1]) # k
74
- assert_array_almost_equal(vector_cross_product(v1, v2), expected_ij)
75
-
76
- v3 = np.array([1, 2, 3])
77
- v4 = np.array([4, 5, 6])
78
- # (2*6 - 3*5, 3*4 - 1*6, 1*5 - 2*4)
79
- # (12 - 15, 12 - 6, 5 - 8)
80
- # (-3, 6, -3)
81
- expected_v3v4 = np.array([-3, 6, -3])
82
- assert_array_almost_equal(vector_cross_product(v3, v4), expected_v3v4)
83
-
84
- # Test non-3D vectors
85
- v_2d_1 = [1,2]
86
- v_2d_2 = [3,4]
87
- with assert_raises(ValueError):
88
- vector_cross_product(v_2d_1, v_2d_2)
89
- with assert_raises(ValueError):
90
- vector_cross_product(v1, v_2d_1) # One 3D, one 2D
91
-
92
- def test_solve_linear_system(self):
93
- # System 1:
94
- # 2x + y = 5
95
- # x - y = 1
96
- # Solution: x=2, y=1
97
- A1 = np.array([[2, 1], [1, -1]])
98
- B1 = np.array([5, 1])
99
- expected_X1 = np.array([2, 1])
100
- assert_array_almost_equal(solve_linear_system(A1, B1), expected_X1, decimal=6)
101
-
102
- # System 2:
103
- # x + y + z = 6
104
- # 2y + 5z = -4
105
- # 2x + 5y - z = 27
106
- # Solution: x=5, y=3, z=-2 (from online calculator)
107
- A2 = np.array([[1, 1, 1], [0, 2, 5], [2, 5, -1]])
108
- B2 = np.array([6, -4, 27])
109
- expected_X2 = np.array([5, 3, -2])
110
- assert_array_almost_equal(solve_linear_system(A2, B2), expected_X2, decimal=6)
111
-
112
- # Singular system (no unique solution)
113
- A_singular = np.array([[1, 1], [2, 2]])
114
- B_singular = np.array([1, 3]) # Inconsistent
115
- with assert_raises(np.linalg.LinAlgError):
116
- solve_linear_system(A_singular, B_singular)
117
-
118
- # Non-square coefficient matrix
119
- A_non_square = np.array([[1,1,1],[0,2,5]])
120
- B_non_square = np.array([6,-4])
121
- with assert_raises(ValueError):
122
- solve_linear_system(A_non_square, B_non_square)
123
-
124
- # Incompatible dimensions B vector
125
- A_valid = np.array([[1,1],[0,2]])
126
- B_invalid_dim = np.array([1,2,3])
127
- with assert_raises(ValueError): # Or LinAlgError depending on numpy's internal checks order
128
- solve_linear_system(A_valid, B_invalid_dim)
129
-
130
-
131
- if __name__ == '__main__':
132
- unittest.main(argv=['first-arg-is-ignored'], exit=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
maths/university/tests/test_operations_research_interface.py DELETED
@@ -1,134 +0,0 @@
1
- import pytest
2
- import numpy as np
3
- import gradio as gr # Import for gr.Error if used in parsing
4
-
5
- # Assuming parsing functions and interface wrappers are in the following module
6
- from maths.university.operations_research.operations_research_interface import (
7
- parse_vector, parse_matrix, parse_relations, parse_bounds, # Import parsing functions if you want to test them directly too
8
- solve_branch_and_bound_interface,
9
- solve_dual_simplex_interface,
10
- run_simplex_solver_interface
11
- )
12
-
13
- # Test for Branch and Bound Interface
14
- def test_bnb_interface_valid_input():
15
- # Example from its own interface definition
16
- c_str = "5,4"
17
- A_str = "1,1;2,0;0,1"
18
- b_str = "5,6,3"
19
- integer_vars_str = "0,1" # Both vars are integer
20
- binary_vars_str = "" # No specific binary vars beyond integer_vars
21
- maximize_bool = True
22
-
23
- solution_str, objective_str, log_str, fig = solve_branch_and_bound_interface(
24
- c_str, A_str, b_str, integer_vars_str, binary_vars_str, maximize_bool
25
- )
26
-
27
- # Expected solution for this problem is x0=2, x1=3, objective=22
28
- assert "2.000, 3.000" in solution_str or "2, 3" in solution_str # Allow for formatting variations
29
- assert "22.000" in objective_str or "22.0" in objective_str
30
- assert fig is not None # Check that a figure object is returned
31
- assert "Branch and bound completed!" in log_str
32
- assert "Optimal objective: 22.0" in log_str # More specific check
33
-
34
- def test_bnb_interface_parsing_error():
35
- # Invalid matrix string (row length mismatch)
36
- solution_str, objective_str, log_str, fig = solve_branch_and_bound_interface(
37
- "1,2", "1,2;3", "10,12", "", "", True # b_str needs two elements if A has two rows
38
- )
39
- # The error message comes from parse_matrix via gr.Warning, which is then caught by the wrapper.
40
- # The wrapper appends to its own log_messages.
41
- assert "Error parsing matrix" in log_str or "Could not parse matrix" in log_str
42
- assert fig is None
43
-
44
- # Test for Dual Simplex Interface
45
- def test_dual_simplex_interface_valid_input():
46
- # Example from its own interface definition, but made consistent for Dual Simplex properties
47
- # Max Z = -2x1 -x2 (originally Min 2x1+x2)
48
- # s.t. -x1 -x2 <= -5 (originally x1+x2 >= 5)
49
- # -2x1 -x2 <= -6 (originally 2x1+x2 >= 6)
50
- obj_type = "max"
51
- c_str = "-2,-1"
52
- A_str = "-1,-1;-2,-1"
53
- relations_str = "<=,<=" # Correct for typical dual simplex tableau setup
54
- b_str = "-5,-6"
55
-
56
- solution_str, objective_str, log_str = solve_dual_simplex_interface(
57
- obj_type, c_str, A_str, relations_str, b_str
58
- )
59
-
60
- # For Z' = -2x1 -x2 s.t. -x1-x2<=-5, -2x1-x2<=-6. Optimal is x1=1, x2=4, Z'=-6. (Min Z = 6)
61
- # The solution string format depends on the solver's _print_results
62
- assert "x1: 1.000" in solution_str or "x1=1.000" in solution_str
63
- assert "x2: 4.000" in solution_str or "x2=4.000" in solution_str
64
- assert "-6.000" in objective_str # Max -Z
65
- assert "Optimal Solution Found" in log_str or "Final Solution" in log_str
66
-
67
- def test_dual_simplex_interface_dim_mismatch():
68
- solution_str, objective_str, log_str = solve_dual_simplex_interface(
69
- "max", "1,2", "1,1;2,2", "<=", "10,12" # relations_str has 1 relation, A has 2 rows
70
- )
71
- assert "Dimension mismatch" in log_str # Check for error message
72
-
73
- # Test for Simplex Solver Interface
74
- def test_simplex_solver_interface_valid_input():
75
- # Example from its own interface definition
76
- c_str = "3,5"
77
- A_str = "1,0;0,2;3,2"
78
- b_str = "4,12,18"
79
- bounds_str = "0,None;0,None" # Non-negative
80
-
81
- solution_str, objective_str, steps_str = run_simplex_solver_interface(
82
- c_str, A_str, b_str, bounds_str
83
- )
84
-
85
- # Expected: x1=2, x2=6, Z=36
86
- assert "2.000, 6.000" in solution_str or "2, 6" in solution_str
87
- assert "36.000" in objective_str or "36.0" in objective_str
88
- assert "Simplex Method Complete" in steps_str
89
- assert "Initial tableau" in steps_str
90
-
91
- def test_simplex_solver_interface_invalid_bounds():
92
- solution_str, objective_str, steps_str = run_simplex_solver_interface(
93
- "1,2", "1,1;2,1", "10,12", "0,None;0" # Malformed bounds pair
94
- )
95
- assert "Error parsing var_bounds" in steps_str or "Could not parse bounds" in steps_str
96
-
97
-
98
- # Test parsing functions directly
99
- def test_parse_matrix_valid():
100
- assert np.array_equal(parse_matrix("1,2;3,4"), np.array([[1.0,2.0],[3.0,4.0]]))
101
-
102
- def test_parse_matrix_invalid_char():
103
- # parse_matrix issues a gr.Warning and returns an empty np.array([])
104
- # The test checks if the returned array is empty.
105
- # We cannot directly test gr.Warning without a more complex setup.
106
- result = parse_matrix("1,2;3,a")
107
- assert isinstance(result, np.ndarray)
108
- assert result.size == 0
109
-
110
- def test_parse_matrix_invalid_row_length():
111
- result = parse_matrix("1,2;3,4,5")
112
- assert isinstance(result, np.ndarray)
113
- assert result.size == 0
114
-
115
- def test_parse_vector_valid():
116
- assert parse_vector("1,2,3.5") == [1.0, 2.0, 3.5]
117
-
118
- def test_parse_vector_invalid():
119
- assert parse_vector("1,a,3") == []
120
-
121
- def test_parse_relations_valid():
122
- assert parse_relations("<=,>=,=") == ["<=", ">=", "="]
123
-
124
- def test_parse_relations_invalid():
125
- assert parse_relations("<=,>,=") == [] # '>' is invalid
126
-
127
- def test_parse_bounds_valid():
128
- assert parse_bounds("0,None;10,20.5;None,5") == [(0.0, None), (10.0, 20.5), (None, 5.0)]
129
-
130
- def test_parse_bounds_invalid_format():
131
- assert parse_bounds("0,None;10,20,30") == [] # middle pair has 3 parts
132
-
133
- def test_parse_bounds_invalid_order():
134
- assert parse_bounds("10,0") == [] # lower > upper
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
maths/vectors/vectors.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Vector operations for university level, using NumPy.
3
+ """
4
+ import numpy as np
5
+ from typing import List, Union
6
+
7
+ Vector = Union[List[float], np.ndarray]
8
+
9
+ def vector_add(vector1: Vector, vector2: Vector) -> np.ndarray:
10
+ v1 = np.array(vector1)
11
+ v2 = np.array(vector2)
12
+ if v1.shape != v2.shape:
13
+ raise ValueError("Vectors must have the same dimensions for addition.")
14
+ return np.add(v1, v2)
15
+
16
+ def vector_subtract(vector1: Vector, vector2: Vector) -> np.ndarray:
17
+ v1 = np.array(vector1)
18
+ v2 = np.array(vector2)
19
+ if v1.shape != v2.shape:
20
+ raise ValueError("Vectors must have the same dimensions for subtraction.")
21
+ return np.subtract(v1, v2)
22
+
23
+ def vector_dot_product(vector1: Vector, vector2: Vector) -> float:
24
+ v1 = np.array(vector1)
25
+ v2 = np.array(vector2)
26
+ if v1.shape != v2.shape:
27
+ raise ValueError("Vectors must have the same dimensions for dot product.")
28
+ return np.dot(v1, v2)
29
+
30
+ def vector_cross_product(vector1: Vector, vector2: Vector) -> np.ndarray:
31
+ v1 = np.array(vector1)
32
+ v2 = np.array(vector2)
33
+ if v1.shape != (3,) or v2.shape != (3,):
34
+ raise ValueError("Both vectors must be 3-dimensional for cross product.")
35
+ return np.cross(v1, v2)
maths/vectors/vectors_interface.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Gradio Interface for Vector operations.
3
+ """
4
+ import gradio as gr
5
+ import numpy as np
6
+ import json
7
+ from typing import Union
8
+ from maths.vectors.vectors import (
9
+ vector_add, vector_subtract, vector_dot_product, vector_cross_product
10
+ )
11
+
12
+ def parse_vector(vector_str: str) -> np.ndarray:
13
+ try:
14
+ v = json.loads(vector_str)
15
+ arr = np.array(v, dtype=float)
16
+ if arr.ndim != 1:
17
+ raise ValueError("Vector must be 1-dimensional.")
18
+ if arr.shape[0] == 0:
19
+ raise ValueError("Vector cannot be empty.")
20
+ return arr
21
+ except (json.JSONDecodeError, TypeError, ValueError) as e_json:
22
+ try:
23
+ if not vector_str.strip():
24
+ raise ValueError("Vector input is empty.")
25
+ arr = np.array([float(x.strip()) for x in vector_str.split(',') if x.strip()], dtype=float)
26
+ if arr.shape[0] == 0:
27
+ raise ValueError("Vector cannot be empty after parsing.")
28
+ return arr
29
+ except ValueError as e_csv:
30
+ raise gr.Error(f"Invalid vector format. Use JSON (e.g., [1,2,3]) or comma-separated (e.g., 1,2,3). Error: {e_csv} (Original JSON error: {e_json})")
31
+ except Exception as e_gen:
32
+ raise gr.Error(f"General error parsing vector: {e_gen}")
33
+
34
+ def format_output(data: Union[np.ndarray, float, str]) -> str:
35
+ if isinstance(data, np.ndarray):
36
+ return str(data.tolist())
37
+ elif isinstance(data, (float, int, str)):
38
+ return str(data)
39
+ return "Output type not recognized."
40
+
41
+ vector_add_interface = gr.Interface(
42
+ fn=lambda v1_str, v2_str: format_output(vector_add(parse_vector(v1_str), parse_vector(v2_str))),
43
+ inputs=[
44
+ gr.Textbox(label="Vector 1 (JSON or CSV format)", placeholder="e.g., [1,2,3] or 1,2,3"),
45
+ gr.Textbox(label="Vector 2 (JSON or CSV format)", placeholder="e.g., [4,5,6] or 4,5,6")
46
+ ],
47
+ outputs=gr.Textbox(label="Resulting Vector"),
48
+ title="Vector Addition",
49
+ description="Adds two vectors. Ensure they have the same dimensions."
50
+ )
51
+
52
+ vector_subtract_interface = gr.Interface(
53
+ fn=lambda v1_str, v2_str: format_output(vector_subtract(parse_vector(v1_str), parse_vector(v2_str))),
54
+ inputs=[
55
+ gr.Textbox(label="Vector 1 (Minuend)", placeholder="e.g., [4,5,6]"),
56
+ gr.Textbox(label="Vector 2 (Subtrahend)", placeholder="e.g., [1,2,3]")
57
+ ],
58
+ outputs=gr.Textbox(label="Resulting Vector"),
59
+ title="Vector Subtraction",
60
+ description="Subtracts the second vector from the first. Ensure they have the same dimensions."
61
+ )
62
+
63
+ vector_dot_product_interface = gr.Interface(
64
+ fn=lambda v1_str, v2_str: format_output(vector_dot_product(parse_vector(v1_str), parse_vector(v2_str))),
65
+ inputs=[
66
+ gr.Textbox(label="Vector 1", placeholder="e.g., [1,2,3]"),
67
+ gr.Textbox(label="Vector 2", placeholder="e.g., [4,5,6]")
68
+ ],
69
+ outputs=gr.Textbox(label="Dot Product (Scalar)"),
70
+ title="Vector Dot Product",
71
+ description="Calculates the dot product of two vectors. Ensure they have the same dimensions."
72
+ )
73
+
74
+ vector_cross_product_interface = gr.Interface(
75
+ fn=lambda v1_str, v2_str: format_output(vector_cross_product(parse_vector(v1_str), parse_vector(v2_str))),
76
+ inputs=[
77
+ gr.Textbox(label="Vector 1 (3D)", placeholder="e.g., [1,2,3]"),
78
+ gr.Textbox(label="Vector 2 (3D)", placeholder="e.g., [4,5,6]")
79
+ ],
80
+ outputs=gr.Textbox(label="Resulting Vector (3D)"),
81
+ title="Vector Cross Product",
82
+ description="Calculates the cross product of two 3D vectors."
83
+ )
utils/__init__.py DELETED
@@ -1,3 +0,0 @@
1
- """
2
- Utility functions for general purposes.
3
- """
 
 
 
 
utils/text_utils.py DELETED
@@ -1,7 +0,0 @@
1
- """
2
- Utility functions for text processing.
3
- """
4
-
5
- def letter_counter(word, letter):
6
- """Count the occurrences of a specific letter in a word."""
7
- return word.lower().count(letter.lower())
 
 
 
 
 
 
 
 
utils/text_utils_interface.py DELETED
@@ -1,11 +0,0 @@
1
- import gradio as gr
2
- from utils.text_utils import letter_counter
3
-
4
- # Text Utils Tab
5
- letter_counter_interface = gr.Interface(
6
- fn=letter_counter,
7
- inputs=["text", "text"],
8
- outputs="number",
9
- title="Letter Counter",
10
- description="Count how many times a letter appears in a word"
11
- )