Fast polynomial and rational evaluation library
Project description
Rust Poly
Fast polynomial and rational evaluation for Python written in Rust.
Usage
Basics
>>> from rust_poly import ExpressionTree
We can construct a polynomial with the ExpressionTree
constructor.
>>> poly = ExpressionTree([1, 2, 3])
>>> print(poly)
1 + 2x₁¹ + 3x₁², dtype = i64
ExpressionTree
objects can be called on arrays and broadcast over the last dimension.
>>> poly([2])
array(17)
>>> poly([[1], [2], [3]])
array([ 6, 17, 34])
>>> poly([[[1], [2]], [[3], [4]]])
array([[ 6, 17],
[34, 57]])
The last dimension of the argument must equal the dimension of the expression.
>>> poly([1, 2, 3])
Traceback (most recent call last):
...
ValueError: Incompatible shape for evaluation
ExpressionTree
objects can be composed and are lazily evaluated.
>>> print(poly * poly)
(1 + 2x₁¹ + 3x₁²) * (1 + 2x₁¹ + 3x₁²), dtype = i64
>>> (poly * poly)([2])
array(289)
ExpressionTree
objects can be "expanded".
>>> print((poly * poly).expand())
1 + 4x₁¹ + 10x₁² + 12x₁³ + 9x₁⁴, dtype = i64
ExpressionTree
objects can be scaled, added, subtracted, divided, and multiplied lazily.
>>> p1 = ExpressionTree([1, 2])
>>> print(p1)
1 + 2x₁¹, dtype = i64
>>> p2 = ExpressionTree([3, 4, 5])
>>> print(p2)
3 + 4x₁¹ + 5x₁², dtype = i64
>>> print(5 * p1)
5 * (1 + 2x₁¹), dtype = i64
>>> print(p1 + p2)
(1 + 2x₁¹) + (3 + 4x₁¹ + 5x₁²), dtype = i64
>>> print(p1 - p2)
(1 + 2x₁¹) - (3 + 4x₁¹ + 5x₁²), dtype = i64
>>> print(p1 * p2)
(1 + 2x₁¹) * (3 + 4x₁¹ + 5x₁²), dtype = i64
>>> print(p1 / p2)
(1 + 2x₁¹) / (3 + 4x₁¹ + 5x₁²), dtype = i64
Different data types (float, int, and complex) can be handled.
>>> poly([2.0])
array(17.)
>>> poly([2.0 + 0j])
array(17.+0.j)
>>> floatpoly = ExpressionTree([1.0, 2.0])
>>> print((floatpoly + poly).expand())
2 + 4x₁¹ + 3x₁², dtype = f64
Higher-dimensional polynomials
Polynomials can be defined with many dimensions.
>>> p2d = ExpressionTree([[1, 2], [3, 4]])
>>> print(p2d)
1 + 2x₂¹ + 3x₁¹ + 4x₁¹x₂¹, dtype = i64
>>> p2d.dimension
2
When evaluating higher dimension arrays, the last dimension of the expression to be evaluated must match the dimension of the array.
>>> p2d([1, 2])
array(16)
>>> p2d([[1], [2]])
Traceback (most recent call last):
...
ValueError: Incompatible shape for evaluation
>>> p2d([[1, 2, 3], [2, 3, 4]])
Traceback (most recent call last):
...
ValueError: Incompatible shape for evaluation
Polynomial dimension must match for composition.
>>> p2d + p1
Traceback (most recent call last):
...
ValueError: Incompatible dimensions for composition
Other operations
Differentiation and integration are supported. Integer polynomials are automatically converted to floats with this method.
>>> print(p1.deriv([1]))
deriv(1 + 2x₁¹, [1]), dtype = f64
>>> print(p1.deriv([1]).expand())
2, dtype = f64
>>> print(p1.deriv([0]).expand())
1 + 2x₁¹, dtype = f64
>>> print(p2.deriv([1]))
deriv(3 + 4x₁¹ + 5x₁², [1]), dtype = f64
>>> print(p2.deriv([1]).expand())
4 + 10x₁¹, dtype = f64
>>> print(p1.integ([1]).expand())
1x₁¹ + 1x₁², dtype = f64
>>> print(p1.deriv([-1]).expand())
1x₁¹ + 1x₁², dtype = f64
The syntax for multi-dimensional derivatives and integrals is similar:
>>> print(p2d.deriv([1, 0]).expand())
3 + 4x₂¹, dtype = f64
>>> print(p2d.deriv([0, 1]).expand())
2 + 4x₁¹, dtype = f64
More complex example
Quick example of computing a stiffness matrix:
from rust_poly import ExpressionTree as Polynomial, from_terms
import numpy as np
terms = {"x1": 0, "x2": 1, "x1a": 2, "x2a": 3,
"x1b": 4, "x2b": 5, "x1c": 6, "x2c": 7,
"nu": 8, "none": None}
def get_term(term):
t = [0] * (len(terms) - 1)
if terms[term] is not None:
t[terms[term]] = 1
return tuple(t)
def get_term_array(term):
return np.array(get_term(term))
def get_poly(**kwargs):
return from_terms(
{get_term(key): val for key, val in kwargs.items()}
)
# Stiffness matrix interpolation functions
Na = (get_poly(x2=1, x2b=-1) *get_poly(x1c=1, x1b=-1)
-get_poly(x1=1, x1b=-1) *get_poly(x2c=1, x2b=-1)
) / (get_poly(x2a=1, x2b=-1) *get_poly(x1c=1, x1b=-1)
-get_poly(x1a=1, x1b=-1) *get_poly(x2c=1, x2b=-1))
Nb = (get_poly(x2=1, x2c=-1) *get_poly(x1a=1, x1c=-1)
-get_poly(x1=1, x1c=-1) *get_poly(x2a=1, x2c=-1)
) / (get_poly(x2b=1, x2c=-1) *get_poly(x1a=1, x1c=-1)
-get_poly(x1b=1, x1c=-1) *get_poly(x2a=1, x2c=-1))
Nc = (get_poly(x2=1, x2a=-1) *get_poly(x1b=1, x1a=-1)
-get_poly(x1=1, x1a=-1) *get_poly(x2b=1, x2a=-1)
) / (get_poly(x2c=1, x2a=-1) *get_poly(x1b=1, x1a=-1)
-get_poly(x1c=1, x1a=-1) *get_poly(x2b=1, x2a=-1))
# Strain-displacement matrix
B = np.full((3, 6), Polynomial.zero(len(terms) - 1) / Polynomial.one(len(terms) - 1))
B[0, 0] = Na.deriv(get_term_array('x1'))
B[0, 2] = Nb.deriv(get_term_array('x1'))
B[0, 4] = Nc.deriv(get_term_array('x1'))
B[1, 1] = Na.deriv(get_term_array('x2'))
B[1, 3] = Nb.deriv(get_term_array('x2'))
B[1, 5] = Nc.deriv(get_term_array('x2'))
B[2, 0] = Na.deriv(get_term_array('x2'))
B[2, 1] = Na.deriv(get_term_array('x1'))
B[2, 2] = Nb.deriv(get_term_array('x2'))
B[2, 3] = Nb.deriv(get_term_array('x1'))
B[2, 4] = Nc.deriv(get_term_array('x2'))
B[2, 5] = Nc.deriv(get_term_array('x1'))
# Material constitutive matrix (plane stress)
D = np.full(
(3, 3),
Polynomial.zero(len(terms) - 1) / Polynomial.one(len(terms) - 1)
)
D[0, 0] = D[1, 1] = get_poly(nu=0, none=1)
D[1, 0] = D[0, 1] = get_poly(nu=1)
D[2, 2] = get_poly(nu=-0.5, none=0.5)
D = D / (get_poly(none=1, nu=1) * get_poly(none=1, nu=-1))
# Coordinate Determinant
Det = (
get_poly(x1a=1) * get_poly(x2b=1, x2c=-1)
+ get_poly(x1b=1) * get_poly(x2c=1, x2a=-1)
+ get_poly(x1c=1) * get_poly(x2a=1, x2b=-1)
)
# Compute an abstract representation for the stiffness matrix of a constant
# strain triangular element
K = (B.T @ D @ B) / Det
# Specialize the stiffness matrix for a particular element
coords = np.array([0, -1, 2, 0, 0, 1, 0.25])
indices = np.array([2, 3, 4, 5, 6, 7, 8])
vfunc = np.vectorize(lambda a: a.partial(indices, coords).expand().to_constant())
K_special = vfunc(K)
expected = np.array([
[ 2.5 , 1.25 , -2. , -1.5 , -0.5 , 0.25 ],
[ 1.25 , 4.375, -1. , -0.75 , -0.25 , -3.625],
[-2. , -1. , 4. , 0. , -2. , 1. ],
[-1.5 , -0.75 , 0. , 1.5 , 1.5 , -0.75 ],
[-0.5 , -0.25 , -2. , 1.5 , 2.5 , -1.25 ],
[ 0.25 , -3.625, 1. , -0.75 , -1.25 , 4.375]
]) / (0.9375 * 64)
assert np.allclose(expected, K_special)
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for rust_poly-0.1.4-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | dfb08733cdffde50c94a03ae7d71a6ad08d133f3cfde1ff5492c8bfcb3302b31 |
|
MD5 | 22a186d13b0b4e31ff7df50d3526b146 |
|
BLAKE2b-256 | 19be0f714b51e7f0f38e33158ccb49b5127a4d7289f04f46eaa7b054ff09d3a1 |
Hashes for rust_poly-0.1.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 570ae6d5afe232052f532029f6b48b3ba364e3e2e33ebcaa3308cf9144e3a192 |
|
MD5 | 8fee4c402b5c70e73474bd438a43561f |
|
BLAKE2b-256 | 4a9bb1216f3e1238d1fb1b58e783d3b02ca97ddd689802f73c2c074f45aca50d |
Hashes for rust_poly-0.1.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4a13a1cdd44f8415a24e8c6077817f8bc8d288e50ab20834af7a9c3c0b02680e |
|
MD5 | ed0930899be4dd1c4f4c5a0f31c132d7 |
|
BLAKE2b-256 | 51d31ac6524346e1e284e2a1068a9455e473979707c86fa95996ddf7ddf9d83c |
Hashes for rust_poly-0.1.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 985d045ce8d9917f1edb6d4c825cb04e46d279121bdaa4b9bed0b2c753e37ec7 |
|
MD5 | 65c825c59657b1696edf3e01de1846aa |
|
BLAKE2b-256 | 5a9079a96f489b2a7e9fb92ef272e45811eaff3d5ade89bed82785ffc59b4a8a |
Hashes for rust_poly-0.1.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 00d266569e59a38d8fb89afa12c84e59e9134559119ea4782a8dc1aa59e42a23 |
|
MD5 | 8297278cde16471e9546bb33172d71a6 |
|
BLAKE2b-256 | 1b1ac4210038f526b0fbc27d17ad1e7cd220bc77caad4c477d6617b4fcb48ecf |
Hashes for rust_poly-0.1.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 90daff8513c03dd087e5ff2a543a1125b9c3b8569b5e78b7258f514be06943e5 |
|
MD5 | f1d948b9e028c2a7ef5cacfeb43065d5 |
|
BLAKE2b-256 | bfbb00f89f638b595b7fd6aaa4df2695adb60679cbff7ff2ea6e18be3023ac51 |