Skip to main content

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

rust_poly-0.1.4.tar.gz (8.2 MB view details)

Uploaded Source

Built Distributions

rust_poly-0.1.4-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.whl (558.2 kB view details)

Uploaded PyPy manylinux: glibc 2.5+ x86-64

rust_poly-0.1.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl (557.6 kB view details)

Uploaded CPython 3.10 manylinux: glibc 2.5+ x86-64

rust_poly-0.1.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl (558.4 kB view details)

Uploaded CPython 3.9 manylinux: glibc 2.5+ x86-64

rust_poly-0.1.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl (557.8 kB view details)

Uploaded CPython 3.8 manylinux: glibc 2.5+ x86-64

rust_poly-0.1.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl (557.8 kB view details)

Uploaded CPython 3.7m manylinux: glibc 2.5+ x86-64

rust_poly-0.1.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl (557.9 kB view details)

Uploaded CPython 3.6m manylinux: glibc 2.5+ x86-64

File details

Details for the file rust_poly-0.1.4.tar.gz.

File metadata

  • Download URL: rust_poly-0.1.4.tar.gz
  • Upload date:
  • Size: 8.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.62.3 importlib-metadata/4.10.1 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.6

File hashes

Hashes for rust_poly-0.1.4.tar.gz
Algorithm Hash digest
SHA256 7ea0d717e5faf9cc3d1fc5c52fff5986ec631837709e4e39f0a0a427974d7c3f
MD5 9893e4a24f6045b84b122f65a95705dc
BLAKE2b-256 67a81092530132a5a637a865f974d269fe78b1f4e6f5e40b12c0e91079cfffe8

See more details on using hashes here.

File details

Details for the file rust_poly-0.1.4-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.whl.

File metadata

File hashes

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

See more details on using hashes here.

File details

Details for the file rust_poly-0.1.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl.

File metadata

File hashes

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

See more details on using hashes here.

File details

Details for the file rust_poly-0.1.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl.

File metadata

File hashes

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

See more details on using hashes here.

File details

Details for the file rust_poly-0.1.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl.

File metadata

File hashes

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

See more details on using hashes here.

File details

Details for the file rust_poly-0.1.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl.

File metadata

File hashes

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

See more details on using hashes here.

File details

Details for the file rust_poly-0.1.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl.

File metadata

File hashes

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

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page