Skip to content

Commit

Permalink
Merge pull request #749 from ca20110820/computer-algebra
Browse files Browse the repository at this point in the history
Feature: Computer Algebra
  • Loading branch information
Mrinank-Bhowmick authored Jun 6, 2024
2 parents 4323330 + fc24c3c commit 1b1f8e6
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 0 deletions.
60 changes: 60 additions & 0 deletions projects/computer-algebra/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Newton CAS Python Wrapper and GUI

This project aims to provide a Python wrapper and GUI for the Newton API, a Computer Algebra
System (CAS) that allows users to perform various mathematical computations. The GUI is built using
[DearPyGui](https://github.com/hoffstadt/DearPyGui) and
[Newton API](https://github.com/aunyks/newton-api).

## Features

- **User-Friendly Interface:** The GUI provides an intuitive interface for users to interact with the Newton API
effortlessly.
- **Multiple Mathematical Operations:** Users can perform a variety of mathematical operations such as simplification,
factoring, differentiation, integration, finding zeroes, and more.
- **Real-Time Evaluation:** Expressions are evaluated in real-time, providing instant feedback to users.

## Installation

1. Clone the repository:

```bash
git clone https://github.com/Mrinank-Bhowmick/python-beginner-projects.git
```

2. Navigate to the project directory:

```bash
cd python-beginner-projects/projects/computer-algebra
```

3. Install dependencies using pip:

```bash
pip install -r requirements.txt
```

## Usage

1. Run the main script `main.py`:

```bash
python main.py
```

2. The application window will appear, consisting of two sections:
- **Input Section:** Enter the mathematical expression you want to evaluate.
- **Output Section:** View the result of the evaluation.

3. Choose the desired mathematical operation from the radio buttons.
4. Enter the expression in the input text box.
- See valid syntax from [Newton API](https://github.com/aunyks/newton-api).
5. Click the "Evaluate" button to perform the selected operation.
6. The result will be displayed in the output section.

## Contact

[GitHub Profile](https://github.com/ca20110820)

## License

[![License](https://img.shields.io/static/v1?label=Licence&message=GPL-3-0&color=blue)](https://opensource.org/license/GPL-3-0)
24 changes: 24 additions & 0 deletions projects/computer-algebra/command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from typing import Any
from abc import abstractmethod, ABC
from urllib.parse import quote


class CmdBase(ABC):
"""Base class for all the CAS (Computer Algebra System) API Commands."""

def __init__(self, operation: str, base_url: str):
self.operation = operation
self.base_url = base_url

@abstractmethod
def command(self, expr: str) -> Any:
"""
Command for sending request to Newton CAS API with a given expression string and returns the result from
the API response.
"""
pass

@staticmethod
def url_encode(inp_str: str) -> str:
"""Encode the input string to a URL-safe format."""
return quote(inp_str)
116 changes: 116 additions & 0 deletions projects/computer-algebra/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
from newton_command import NEWTON_CMDS_DICT

import dearpygui.dearpygui as dpg


def selection_cb(sender, app_data, user_data):
"""Callback function for button selections in the message box."""
if user_data[1]:
print("User selected 'Ok'")
else:
print("User selected 'Cancel'")

# delete window
dpg.delete_item(user_data[0])


def show_info(title, message, selection_callback):
"""
Display an information message box with title, message, and callback.
References:
https://github.com/hoffstadt/DearPyGui/discussions/1002
"""

# guarantee these commands happen in the same frame
with dpg.mutex():
viewport_width = dpg.get_viewport_client_width()
viewport_height = dpg.get_viewport_client_height()

with dpg.window(tag='popup-window', label=title, modal=True, no_close=True) as modal_id:
dpg.add_text(message)
dpg.add_button(label="Ok", width=75, user_data=(modal_id, True), callback=selection_callback)
dpg.add_same_line()
dpg.add_button(label="Cancel", width=75, user_data=(modal_id, False), callback=selection_callback)

# guarantee these commands happen in another frame
dpg.split_frame()
width = dpg.get_item_width(modal_id)
height = dpg.get_item_height(modal_id)
dpg.set_item_pos(modal_id, [viewport_width // 2 - width // 2, viewport_height // 2 - height // 2])


# Callbacks and Helpers
def on_evaluate(sender, app_data, user_data):
"""Callback function for the 'Evaluate' button."""
# Get the Command
cmd = dpg.get_value('radio-cmds')
cmd_func = NEWTON_CMDS_DICT[cmd]

# Get the Expression
expr = dpg.get_value('inp-expr')

if expr.strip() in ['']:
show_info(
'Error',
'Please use valid mathematical expressions.',
selection_cb
)
# Clear Expression
dpg.set_value('inp-expr', '')
return

# Evaluate
response = cmd_func(expr)
result = response.result

dpg.set_value('label-output', result)


dpg.create_context()
dpg.create_viewport(title='Computer Algebra', width=1300, height=750)

with dpg.window(tag='inp-window',
label="Input",
pos=[0, 0],
autosize=True,
# width=1150,
# height=350,
no_collapse=True,
no_close=True,
):
# Radio Button for Commands
dpg.add_radio_button(
horizontal=True,
tag='radio-cmds',
items=[cmd for cmd in NEWTON_CMDS_DICT.keys()]
)

# Text Area for Mathematical Expression
dpg.add_input_text(
tag='inp-expr',
width=int(1150 * 0.8),
)

# Button for Evaluating Command and Expression
dpg.add_button(label="Evaluate", callback=on_evaluate)

with dpg.window(tag='out-window',
pos=[0, 100],
label="Output",
# width=700,
# height=350,
autosize=True,
no_collapse=True,
no_close=True,
):
# Use Label for Output
dpg.add_text(tag='label-output',
label='Result',
show_label=True,
)

dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
94 changes: 94 additions & 0 deletions projects/computer-algebra/newton_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
from dataclasses import dataclass

import requests
from command import CmdBase


@dataclass(frozen=True)
class NewtonResponse:
"""Newton API Response."""
operation: str
expression: str
result: str


class NewtonCmdException(Exception):
"""Base class for Newton Command Exceptions."""


class NewtonCommand(CmdBase):
"""Base class for all the Newton API Commands."""

def __init__(self, operation: str):
super().__init__(operation, 'https://newton.now.sh/api/v2')

def command(self, expr: str) -> NewtonResponse:
"""
Command method for NewtonCommand class.
Args:
expr (str): Mathematical expression to be evaluated.
Returns:
NewtonResponse: Object containing the operation, expression, and result of the evaluated expression.
Raises:
NewtonCmdException: If the HTTP request fails or returns a non-success status code, the exception is raised
with the error message.
"""
# Construct the Request URL
expr_encode = self.url_encode(expr) # URL Encode for Expression
request_url = f"{self.base_url}/{self.operation}/{expr_encode}"

# Make the HTTP GET request
response = requests.get(request_url)

# Check if the request was successful (status code 200)
if response.status_code == 200:
# Deserialize the JSON response into a dictionary
response_data = response.json()

# Extract relevant data from the response
operation = response_data['operation']
expression = response_data['expression']
result = response_data['result']

# Create and return a NewtonResponse object
return NewtonResponse(operation=operation, expression=expression, result=result)
else:
raise NewtonCmdException(f'{response.text}')


newton_simplify = NewtonCommand('simplify').command
newton_factor = NewtonCommand('factor').command
newton_derive = NewtonCommand('derive').command
newton_integrate = NewtonCommand('integrate').command
newton_zeroes = NewtonCommand('zeroes').command
newton_tangent = NewtonCommand('tangent').command
newton_area = NewtonCommand('area').command
newton_cos = NewtonCommand('cos').command
newton_sin = NewtonCommand('sin').command
newton_tan = NewtonCommand('tan').command
newton_arc_cos = NewtonCommand('arccos').command
newton_arc_sin = NewtonCommand('arcsin').command
newton_arc_tan = NewtonCommand('arctan').command
newton_abs = NewtonCommand('abs').command
newton_log = NewtonCommand('log').command

NEWTON_CMDS_DICT = {
'simplify': newton_simplify,
'factor': newton_factor,
'derive': newton_derive,
'integrate': newton_integrate,
'zeroes': newton_zeroes,
'tangent': newton_tangent,
'area': newton_area,
'cos': newton_cos,
'sin': newton_sin,
'tan': newton_tan,
'arccos': newton_arc_cos,
'arcsin': newton_arc_sin,
'arctan': newton_arc_tan,
'abs': newton_abs,
'log': newton_log
}
2 changes: 2 additions & 0 deletions projects/computer-algebra/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
requests==2.31.0
dearpygui==1.11.1

0 comments on commit 1b1f8e6

Please sign in to comment.