Skip to content
This repository was archived by the owner on Apr 24, 2025. It is now read-only.

Commit 1b1f8e6

Browse files
Merge pull request #749 from ca20110820/computer-algebra
Feature: Computer Algebra
2 parents 4323330 + fc24c3c commit 1b1f8e6

File tree

5 files changed

+296
-0
lines changed

5 files changed

+296
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Newton CAS Python Wrapper and GUI
2+
3+
This project aims to provide a Python wrapper and GUI for the Newton API, a Computer Algebra
4+
System (CAS) that allows users to perform various mathematical computations. The GUI is built using
5+
[DearPyGui](https://github.com/hoffstadt/DearPyGui) and
6+
[Newton API](https://github.com/aunyks/newton-api).
7+
8+
## Features
9+
10+
- **User-Friendly Interface:** The GUI provides an intuitive interface for users to interact with the Newton API
11+
effortlessly.
12+
- **Multiple Mathematical Operations:** Users can perform a variety of mathematical operations such as simplification,
13+
factoring, differentiation, integration, finding zeroes, and more.
14+
- **Real-Time Evaluation:** Expressions are evaluated in real-time, providing instant feedback to users.
15+
16+
## Installation
17+
18+
1. Clone the repository:
19+
20+
```bash
21+
git clone https://github.com/Mrinank-Bhowmick/python-beginner-projects.git
22+
```
23+
24+
2. Navigate to the project directory:
25+
26+
```bash
27+
cd python-beginner-projects/projects/computer-algebra
28+
```
29+
30+
3. Install dependencies using pip:
31+
32+
```bash
33+
pip install -r requirements.txt
34+
```
35+
36+
## Usage
37+
38+
1. Run the main script `main.py`:
39+
40+
```bash
41+
python main.py
42+
```
43+
44+
2. The application window will appear, consisting of two sections:
45+
- **Input Section:** Enter the mathematical expression you want to evaluate.
46+
- **Output Section:** View the result of the evaluation.
47+
48+
3. Choose the desired mathematical operation from the radio buttons.
49+
4. Enter the expression in the input text box.
50+
- See valid syntax from [Newton API](https://github.com/aunyks/newton-api).
51+
5. Click the "Evaluate" button to perform the selected operation.
52+
6. The result will be displayed in the output section.
53+
54+
## Contact
55+
56+
[GitHub Profile](https://github.com/ca20110820)
57+
58+
## License
59+
60+
[![License](https://img.shields.io/static/v1?label=Licence&message=GPL-3-0&color=blue)](https://opensource.org/license/GPL-3-0)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from typing import Any
2+
from abc import abstractmethod, ABC
3+
from urllib.parse import quote
4+
5+
6+
class CmdBase(ABC):
7+
"""Base class for all the CAS (Computer Algebra System) API Commands."""
8+
9+
def __init__(self, operation: str, base_url: str):
10+
self.operation = operation
11+
self.base_url = base_url
12+
13+
@abstractmethod
14+
def command(self, expr: str) -> Any:
15+
"""
16+
Command for sending request to Newton CAS API with a given expression string and returns the result from
17+
the API response.
18+
"""
19+
pass
20+
21+
@staticmethod
22+
def url_encode(inp_str: str) -> str:
23+
"""Encode the input string to a URL-safe format."""
24+
return quote(inp_str)

projects/computer-algebra/main.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
from newton_command import NEWTON_CMDS_DICT
2+
3+
import dearpygui.dearpygui as dpg
4+
5+
6+
def selection_cb(sender, app_data, user_data):
7+
"""Callback function for button selections in the message box."""
8+
if user_data[1]:
9+
print("User selected 'Ok'")
10+
else:
11+
print("User selected 'Cancel'")
12+
13+
# delete window
14+
dpg.delete_item(user_data[0])
15+
16+
17+
def show_info(title, message, selection_callback):
18+
"""
19+
Display an information message box with title, message, and callback.
20+
21+
References:
22+
https://github.com/hoffstadt/DearPyGui/discussions/1002
23+
"""
24+
25+
# guarantee these commands happen in the same frame
26+
with dpg.mutex():
27+
viewport_width = dpg.get_viewport_client_width()
28+
viewport_height = dpg.get_viewport_client_height()
29+
30+
with dpg.window(tag='popup-window', label=title, modal=True, no_close=True) as modal_id:
31+
dpg.add_text(message)
32+
dpg.add_button(label="Ok", width=75, user_data=(modal_id, True), callback=selection_callback)
33+
dpg.add_same_line()
34+
dpg.add_button(label="Cancel", width=75, user_data=(modal_id, False), callback=selection_callback)
35+
36+
# guarantee these commands happen in another frame
37+
dpg.split_frame()
38+
width = dpg.get_item_width(modal_id)
39+
height = dpg.get_item_height(modal_id)
40+
dpg.set_item_pos(modal_id, [viewport_width // 2 - width // 2, viewport_height // 2 - height // 2])
41+
42+
43+
# Callbacks and Helpers
44+
def on_evaluate(sender, app_data, user_data):
45+
"""Callback function for the 'Evaluate' button."""
46+
# Get the Command
47+
cmd = dpg.get_value('radio-cmds')
48+
cmd_func = NEWTON_CMDS_DICT[cmd]
49+
50+
# Get the Expression
51+
expr = dpg.get_value('inp-expr')
52+
53+
if expr.strip() in ['']:
54+
show_info(
55+
'Error',
56+
'Please use valid mathematical expressions.',
57+
selection_cb
58+
)
59+
# Clear Expression
60+
dpg.set_value('inp-expr', '')
61+
return
62+
63+
# Evaluate
64+
response = cmd_func(expr)
65+
result = response.result
66+
67+
dpg.set_value('label-output', result)
68+
69+
70+
dpg.create_context()
71+
dpg.create_viewport(title='Computer Algebra', width=1300, height=750)
72+
73+
with dpg.window(tag='inp-window',
74+
label="Input",
75+
pos=[0, 0],
76+
autosize=True,
77+
# width=1150,
78+
# height=350,
79+
no_collapse=True,
80+
no_close=True,
81+
):
82+
# Radio Button for Commands
83+
dpg.add_radio_button(
84+
horizontal=True,
85+
tag='radio-cmds',
86+
items=[cmd for cmd in NEWTON_CMDS_DICT.keys()]
87+
)
88+
89+
# Text Area for Mathematical Expression
90+
dpg.add_input_text(
91+
tag='inp-expr',
92+
width=int(1150 * 0.8),
93+
)
94+
95+
# Button for Evaluating Command and Expression
96+
dpg.add_button(label="Evaluate", callback=on_evaluate)
97+
98+
with dpg.window(tag='out-window',
99+
pos=[0, 100],
100+
label="Output",
101+
# width=700,
102+
# height=350,
103+
autosize=True,
104+
no_collapse=True,
105+
no_close=True,
106+
):
107+
# Use Label for Output
108+
dpg.add_text(tag='label-output',
109+
label='Result',
110+
show_label=True,
111+
)
112+
113+
dpg.setup_dearpygui()
114+
dpg.show_viewport()
115+
dpg.start_dearpygui()
116+
dpg.destroy_context()
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
from dataclasses import dataclass
2+
3+
import requests
4+
from command import CmdBase
5+
6+
7+
@dataclass(frozen=True)
8+
class NewtonResponse:
9+
"""Newton API Response."""
10+
operation: str
11+
expression: str
12+
result: str
13+
14+
15+
class NewtonCmdException(Exception):
16+
"""Base class for Newton Command Exceptions."""
17+
18+
19+
class NewtonCommand(CmdBase):
20+
"""Base class for all the Newton API Commands."""
21+
22+
def __init__(self, operation: str):
23+
super().__init__(operation, 'https://newton.now.sh/api/v2')
24+
25+
def command(self, expr: str) -> NewtonResponse:
26+
"""
27+
Command method for NewtonCommand class.
28+
29+
Args:
30+
expr (str): Mathematical expression to be evaluated.
31+
32+
Returns:
33+
NewtonResponse: Object containing the operation, expression, and result of the evaluated expression.
34+
35+
Raises:
36+
NewtonCmdException: If the HTTP request fails or returns a non-success status code, the exception is raised
37+
with the error message.
38+
"""
39+
# Construct the Request URL
40+
expr_encode = self.url_encode(expr) # URL Encode for Expression
41+
request_url = f"{self.base_url}/{self.operation}/{expr_encode}"
42+
43+
# Make the HTTP GET request
44+
response = requests.get(request_url)
45+
46+
# Check if the request was successful (status code 200)
47+
if response.status_code == 200:
48+
# Deserialize the JSON response into a dictionary
49+
response_data = response.json()
50+
51+
# Extract relevant data from the response
52+
operation = response_data['operation']
53+
expression = response_data['expression']
54+
result = response_data['result']
55+
56+
# Create and return a NewtonResponse object
57+
return NewtonResponse(operation=operation, expression=expression, result=result)
58+
else:
59+
raise NewtonCmdException(f'{response.text}')
60+
61+
62+
newton_simplify = NewtonCommand('simplify').command
63+
newton_factor = NewtonCommand('factor').command
64+
newton_derive = NewtonCommand('derive').command
65+
newton_integrate = NewtonCommand('integrate').command
66+
newton_zeroes = NewtonCommand('zeroes').command
67+
newton_tangent = NewtonCommand('tangent').command
68+
newton_area = NewtonCommand('area').command
69+
newton_cos = NewtonCommand('cos').command
70+
newton_sin = NewtonCommand('sin').command
71+
newton_tan = NewtonCommand('tan').command
72+
newton_arc_cos = NewtonCommand('arccos').command
73+
newton_arc_sin = NewtonCommand('arcsin').command
74+
newton_arc_tan = NewtonCommand('arctan').command
75+
newton_abs = NewtonCommand('abs').command
76+
newton_log = NewtonCommand('log').command
77+
78+
NEWTON_CMDS_DICT = {
79+
'simplify': newton_simplify,
80+
'factor': newton_factor,
81+
'derive': newton_derive,
82+
'integrate': newton_integrate,
83+
'zeroes': newton_zeroes,
84+
'tangent': newton_tangent,
85+
'area': newton_area,
86+
'cos': newton_cos,
87+
'sin': newton_sin,
88+
'tan': newton_tan,
89+
'arccos': newton_arc_cos,
90+
'arcsin': newton_arc_sin,
91+
'arctan': newton_arc_tan,
92+
'abs': newton_abs,
93+
'log': newton_log
94+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
requests==2.31.0
2+
dearpygui==1.11.1

0 commit comments

Comments
 (0)