Metadata-Version: 2.1
Name: mexpress
Version: 0.1.2
Requires-Dist: numpy
Summary: Math parser and evaluator capable of computing gradients and Hessians.
License: MIT License

	

	Copyright (c) 2021 Behrang Shafei

	

	Permission is hereby granted, free of charge, to any person obtaining a copy

	of this software and associated documentation files (the "Software"), to deal

	in the Software without restriction, including without limitation the rights

	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

	copies of the Software, and to permit persons to whom the Software is

	furnished to do so, subject to the following conditions:

	

	The above copyright notice and this permission notice shall be included in all

	copies or substantial portions of the Software.

	

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

	SOFTWARE.

	
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

# Mexpress
Math parser and evaluator capable of computing gradients and Hessians. Mexpress uses the Rust crate Exmex.
## Installation 

```
pip install mexpress
```
## Usage

```python
import mexpress
import numpy as np

# parse function
f = mexpress.parse("(x - 1) ** 2 - y * x + 3 * y ** 2")

# evaluate function at (2, 4)
y = f(2, 4)
assert abs(y + 3) < 1e-12

# evaluate gradient at (2, 4)
grad_2_4 = f.grad(2, 4)
assert np.linalg.norm(grad_2_4 - [-2, 22]) < 1e-12

# evaluate Hessian at (2, 4)
hess_2_4 = f.hess(2, 4)
assert np.linalg.norm(hess_2_4 - [[2, -1], [-1, 6]]) < 1e-12
```

Besides `**` you can also use `^` for exponentiation. Currently, a list of supported mathematical operators can only be found in the [Rust code](https://docs.rs/exmex/0.11.2/src/exmex/operators.rs.html#204-206).

## Optimization Example

With gradients and Hessians one can at least locally optimize differentiable functions passed as strings, e.g., with `scipy.optimize`.
```Python
from scipy.optimize import minimize
import mexpress

func_str = f"({a}-x) ** 2 + {b}*(y-x ** 2) ** 2 + (z - 7) ** 2 + (ρ + 5) ** 2"
f = mexpress.parse(func_str)
res = minimize(f, x0=[0.0, 0.0, 0.0, 0.0], method="trust-ncg", jac=f.grad, hess=f.hess)
```
We have played around with different optimizers on `func_str`, see the following output of [`py/demo.py`](https://github.com/bertiqwerty/mexpress/blob/main/py/demo.py). In the following table, `#fails` is the number of fails out of 100 attempts with random `x0`s. The iterations and elapsed seconds are medians.
```
CG             #fails   0   #it  44   0.0049996 sec   jac True    hess False
CG             #fails  23   #it  44   0.0179558 sec   jac False   hess False
Newton-CG      #fails   0   #it  38   0.0049839 sec   jac True    hess True
Newton-CG      #fails   5   #it  37   0.0059988 sec   jac True    hess False
trust-krylov   #fails   0   #it  31   0.0255845 sec   jac True    hess True
trust-ncg      #fails   0   #it  32   0.0030000 sec   jac True    hess True
trust-exact    #fails   0   #it  30   0.0060000 sec   jac True    hess True
BFGS           #fails   0   #it  72   0.0059998 sec   jac True    hess False
BFGS           #fails  21   #it  74   0.0169995 sec   jac False   hess False
L-BFGS-B       #fails   0   #it  43   0.0019979 sec   jac True    hess False
L-BFGS-B       #fails   0   #it  42   0.0069985 sec   jac False   hess False
Nelder-Mead    #fails   0   #it 441   0.0131288 sec   jac False   hess False
SLSQP          #fails   0   #it  34   0.0029492 sec   jac True    hess False
dogleg         #fails  17   #it  27   0.0027690 sec   jac True    hess True
TNC            #fails   0   #it  29   0.0029995 sec   jac True    hess False
TNC            #fails   0   #it  27   0.0110002 sec   jac False   hess False
COBYLA         #fails  46   #it  -1   0.0163412 sec   jac False   hess False
POWELL         #fails   0   #it  22   0.0139999 sec   jac False   hess False
```

