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.5-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | af7281625ca5330e6500555830556f94e891c31ab8be4680ba8fb750920788a3 |
|
MD5 | e144152239b66ba625bcca569ae1054e |
|
BLAKE2b-256 | a2d9fbee8825067c6d8466dc53042587f97877b01ecbb9b7bf524b82ee4502d1 |
Hashes for rust_poly-0.1.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 66e0e036bdcc89abce563a61ec5393d9e4f9208cd7a81fa1891022ec64a79927 |
|
MD5 | b799ad62618b543163d56179a77147e3 |
|
BLAKE2b-256 | 501e7f687d155f3ba56149bbc17d96f539f7bdb9e8b60480dadfd3011de92b46 |
Hashes for rust_poly-0.1.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2cd316523643f53ac1593f74467d223bc0611a010eeeb75ef43f120da917d6c9 |
|
MD5 | 99d0175a2fbd4ee8637ce95af51b3ffe |
|
BLAKE2b-256 | 7f9ba333b4a9f6b0ac704e308909063d213e441c8be1a3469a6ed9c89f133d21 |
Hashes for rust_poly-0.1.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c4df8caf0c0fcec94e35e81ba01879317082616fe7240b0cec17b9800985ae3e |
|
MD5 | 705d009847a9c89337dfad0dc3660321 |
|
BLAKE2b-256 | b260378f862c09c58eea18066dfb9329a7daad85b2b4a067ea1b895e3c9d459c |
Hashes for rust_poly-0.1.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0bb50edb575e01ef36f4b2b2b4172a5e63a18558f11e4aec191adb625b1845f3 |
|
MD5 | f25fc38c1eb2a210e1f403a8a1e7a86b |
|
BLAKE2b-256 | 19a9db5a040ae27a6d6be2ff88651d583795323b57d727906e04165925c900ad |
Hashes for rust_poly-0.1.5-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6f128b66a64a8982343959b602a8a3ce6f44cb6e90ce526ab3b27b57399f3f9e |
|
MD5 | b67f785e1cbe0e9215761e478589eaa5 |
|
BLAKE2b-256 | e6e0f43f604beb8b3d3c79dddf5fc87661f1cf8c1d2b08737a54168f935da9eb |