Metadata-Version: 2.4
Name: parsimathious
Version: 0.3.0
Summary: A mathematical expression parser supporting arithmetic, functions, and complex numbers
Keywords: math,parser,expression,arithmetic,complex numbers
Author: Simone Sturniolo
Author-email: Simone Sturniolo <simonesturniolo@gmail.com>
License-Expression: MIT
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: MIT License
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Mathematics
Requires-Dist: parsimonious>=0.11.0
Requires-Dist: numpy>=1.24 ; extra == 'numpy'
Requires-Python: >=3.11
Project-URL: Homepage, https://github.com/stur86/parsimathious
Project-URL: Repository, https://github.com/stur86/parsimathious
Project-URL: Issues, https://github.com/stur86/parsimathious/issues
Provides-Extra: numpy
Description-Content-Type: text/markdown

# parsimathious

[![PyPI](https://img.shields.io/pypi/v/parsimathious)](https://pypi.org/project/parsimathious/)
[![Python](https://img.shields.io/pypi/pyversions/parsimathious)](https://pypi.org/project/parsimathious/)
[![Tests](https://github.com/stur86/parsimathious/actions/workflows/test.yml/badge.svg)](https://github.com/stur86/parsimathious/actions/workflows/test.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

`parsimathious` is a simple mathematical expression parser implemented with [`parsimonious`](https://github.com/erikrose/parsimonious). It supports basic arithmetic operations, parentheses, unary functions, constants, variables, and complex numbers.

## Installation

You can install `parsimathious` using pip:

```bash
pip install parsimathious
```

## Usage

Import the `ExpressionParser` and create an instance:

```python
from parsimathious import ExpressionParser

parser = ExpressionParser()
```

Then you can parse and evaluate expressions:

```python
result = parser("sin(pi / 2) + 1")
print(result)  # Output: 2.0
```

## Supported functions and constants


On top of basic arithmetic operations, `parsimathious` supports the following unary functions and constants by default:

| Name     | Description                        |
|----------|------------------------------------|
| `sin`    | Sine                               |
| `cos`    | Cosine                             |
| `tan`    | Tangent                            |
| `log`    | Natural logarithm (base e)         |
| `sqrt`   | Square root                        |
| `exp`    | Exponential (e^x)                  |
| `log10`  | Logarithm base 10                  |
| `abs`    | Absolute value                     |
| `floor`  | Floor (round down)                 |
| `ceil`   | Ceiling (round up)                 |
| `round`  | Round to nearest integer           |
| `sinh`   | Hyperbolic sine                    |
| `cosh`   | Hyperbolic cosine                  |
| `tanh`   | Hyperbolic tangent                 |
| `asin`   | Arc sine                           |
| `acos`   | Arc cosine                         |
| `atan`   | Arc tangent                        |
| `asinh`  | Inverse hyperbolic sine            |
| `acosh`  | Inverse hyperbolic cosine          |
| `atanh`  | Inverse hyperbolic tangent         |
| `sec`    | Secant                             |
| `csc`    | Cosecant                           |
| `cot`    | Cotangent                          |

These dispatch on the type of their argument: complex arguments are evaluated with
[`cmath`](https://docs.python.org/3/library/cmath.html), everything else with
[`math`](https://docs.python.org/3/library/math.html). A real argument therefore returns a
plain `float` and keeps `math`'s domain errors, while the complex branch is reached only
through a complex value:

```python
parser("sin(1)")        # 0.8414709848078965, a float
parser("sin(i)")        # 1.1752011936438014j
parser("sqrt(-1)")      # raises ValueError: math domain error
parser("sqrt(-1 + 0i)") # 1j
```

The default table is exported as `DEFAULT_UNARY_FUNCTIONS`, so you can build on it rather
than reaching for `math` directly, which would lose complex support for that entry.

### Constants

| Name | Value                | Description                |
|------|----------------------|----------------------------|
| `pi` | math.pi              | The mathematical constant π |
| `e`  | math.e               | The mathematical constant e |
| `i`  | 1j                   | The imaginary unit         |

## Custom Unary Functions

It's also possible to support custom unary functions by passing a dictionary of function names to their implementations when creating the `ExpressionParser`:

```python
import math
from parsimathious import ExpressionParser, UnaryFunctionMap

custom_functions: UnaryFunctionMap = {
    "log2": math.log2,  # Logarithm base 2
    "cube": lambda x: x ** 3,  # Cube function
}

parser = ExpressionParser(unary_functions=custom_functions)
result = parser("log2(8) + cube(3)")
print(result)  # Output: 30.0
```

As with constants, this **replaces** the default functions rather than extending them. Spread
`DEFAULT_UNARY_FUNCTIONS` if you want to keep them:

```python
from parsimathious import DEFAULT_UNARY_FUNCTIONS

parser = ExpressionParser(
    unary_functions={**DEFAULT_UNARY_FUNCTIONS, "log2": math.log2},
)
```

Functions you supply are called exactly as given — they are never wrapped or dispatched.

## Custom Constants

Custom constants can be passed via a dictionary of names to values when creating the `ExpressionParser`. This **replaces** the default constants (`pi`, `e`) rather than extending them, so include them again if you still need them:

```python
import math
from parsimathious import ExpressionParser, ConstantMap

custom_constants: ConstantMap = {
    "pi": math.pi,
    "tau": 2 * math.pi,
}

parser = ExpressionParser(constants=custom_constants)
result = parser("tau / pi")
print(result)  # Output: 2.0
```

Constant names cannot overlap with variable names (see below), and `i` is reserved for the imaginary unit and cannot be used as a constant name.

## Variables

Unlike constants, variables don't have a fixed value: their names are declared when creating the `ExpressionParser`, and their values are supplied at evaluation time, by passing a dictionary of names to values to the parser call (or to `eval_ast`):

```python
from parsimathious import ExpressionParser

parser = ExpressionParser(variable_names=["x", "y"])
result = parser("x + y * 2", variables={"x": 1.0, "y": 3.0})
print(result)  # Output: 7.0
```

Each call only uses the variable values passed to it; if an expression references a declared variable but no value is provided for it, a `ValueError` is raised. As with constants, `i` is reserved for the imaginary unit and cannot be used as a variable name, and variable names cannot overlap with constant names.

## NumPy arrays

Variable values are not restricted to scalars. Arithmetic works over numpy arrays out of the
box, because operators dispatch through numpy itself:

```python
import numpy as np
from parsimathious import ExpressionParser

parser = ExpressionParser(variable_names=["x"])
parser("2 * x + 1", variables={"x": np.array([0.0, 1.0, 2.0])})  # array([1., 3., 5.])
```

The default unary functions, however, are scalar-only and reject arrays. Use
`ExpressionParser.with_numpy` to get a parser whose functions are backed by numpy:

```python
parser = ExpressionParser.with_numpy(variable_names=["x"])
x = np.linspace(0, np.pi, 5)
parser("exp(-x) * sin(x)", variables={"x": x})  # elementwise, returns an array
```

Function names are identical either way, so expressions need no changes. NumPy is an optional
dependency:

```bash
pip install parsimathious[numpy]
```

To combine numpy functions with your own, build the map explicitly with
`numpy_unary_functions()` — `with_numpy` takes no `unary_functions` argument, since passing one
would replace the numpy table and make the constructor a no-op:

```python
from parsimathious import numpy_unary_functions

parser = ExpressionParser(
    unary_functions={**numpy_unary_functions(), "cube": lambda x: x ** 3},
    variable_names=["x"],
)
```

Note that the numpy-backed table carries numpy's semantics throughout: `sqrt(-1)` returns `nan`
with a warning rather than raising, and results are numpy scalars rather than plain floats.
