Skip to main content

A fast Python package specialised on solving banded linear systems

Project description

🧮 pybandee ⚡️

A Python package specialised in factorising and solving banded matrices. Currently, the package supports the following functionalities:

  • pentadiagonal factorisation and solving
  • computation of the log-determinant and inverse elements of a pentadiagonal matrix

⚠ Important Note ⚠

This package is currently only an experimental alpha version that is missing

  • Python interfaces with input validation
  • documentation
  • tests that cover all possible edge cases
  • citation of the original papers

☁️➡️📦 Installation

While this package can be installed and run without the optional dependency numba as

pip install pybandee

It is recommended to install the package together with numba because the low-level style code will be significantly faster. This can be done with

pip install pybandee["fast"]

5️⃣ Pentadiagonal Matrices

⚠ Currently, only the Numba low-level implementation is available ⚠
Please install the package with pip install pybandee["fast"] to get the performance benefits

For a well-conditioned pentadiagonal matrix consisting of

  • 2 sub-diagonals,
  • 1 main diagonal, and
  • 2 super-diagonals

a simple $\mathbf{L}\mathbf{U}$ factorisation can be computed using the PTRANS-I algorithm. This can be solved efficiently and allows for the computation of additional properties such as the log-determinant and inverse elements.

For the numba low-level implementations, the pentadiagonal matrix

$$ \mathbf{A} = \begin{bmatrix} c_{0} & d_{0} & e_{0} & 0 & 0 & 0 & 0 & 0 \ b_{1} & c_{1} & d_{1} & e_{1} & 0 & 0 & 0 & 0 \ a_{2} & b_{2} & c_{2} & d_{2} & e_{2} & 0 & 0 & 0 \ 0 & a_{3} & b_{3} & c_{3} & d_{3} & e_{3} & 0 & 0 \ 0 & 0 & a_{4} & b_{4} & c_{4} & d_{4} & e_{4} & 0 \ 0 & 0 & 0 & a_{5} & b_{5} & c_{5} & d_{5} & e_{5} \ 0 & 0 & 0 & 0 & a_{6} & b_{6} & c_{6} & d_{6} \ 0 & 0 & 0 & 0 & 0 & a_{7} & b_{7} & c_{7} \ \end{bmatrix} $$

needs to be stored in the row-major banded storage format as

a = np.array(
    [   #  sub2   sub1   main   sup1   sup2
        [     *,     *,    c0,    d0,    e0     ],
        [     *,    b1,    c1,    d1,    e1     ],
        [    a2,    b2,    c2,    d2,    e2     ],
        [    a3,    b3,    c3,    d3,    e3     ],
        [    a4,    b4,    c4,    d4,    e4     ],
        [    a5,    b5,    c5,    d5,    e5     ],
        [    a6,    b6,    c6,    d6,     *     ],
        [    a7,    b7,    c7,     *,     *     ],
    ],
    order="C",  # ← this is important
)

where the entries marked with * are not used and can be any value.

A linear system can be solved like

 === Imports ===

import numpy as np

from pybandee.penta import numba as jit_penta

# === Setup ===

np.random.seed(0)

# a symmetric positive definite pentadiagonal matrix is created in row-major banded
# storage format
lhs_matrix = np.zeros(shape=(50, 5), dtype=np.float64)
column = np.random.rand(lhs_matrix.shape[0] - 2)
lhs_matrix[2:, 0] = column.copy()
lhs_matrix[0:-2, 4] = column.copy()
column = np.random.rand(lhs_matrix.shape[0] - 1)
lhs_matrix[1:, 1] = column.copy()
lhs_matrix[0:-1, 3] = column.copy()
column = np.random.rand(lhs_matrix.shape[0])
lhs_matrix[:, 2] = column.copy() + 2.0  # to ensure positive definiteness
lhs_matrix_original = lhs_matrix.copy()

rhs_vector = np.random.rand(lhs_matrix.shape[0])  # ← will be overwritten by the solve
rhs_vector_original = rhs_vector.copy()

# === Factorisation and Solve ===

info = jit_penta.ptrans1_factorize(matrix=lhs_matrix)
assert info == 0  # ← factorization successful

jit_penta.ptrans1_solve_single_rhs(
    factorization=lhs_matrix,  # ← is now the factorization
    rhs=rhs_vector,  # ← will become the solution
)

# === Comparison against Numpy ===

lhs_matrix_dense = np.zeros(
    shape=(lhs_matrix_original.shape[0], lhs_matrix_original.shape[0]),
    dtype=np.float64,
)
lhs_matrix_dense += np.diag(lhs_matrix_original[2::, 0], k=-2)
lhs_matrix_dense += np.diag(lhs_matrix_original[1::, 1], k=-1)
lhs_matrix_dense += np.diag(lhs_matrix_original[:, 2])
lhs_matrix_dense += np.diag(lhs_matrix_original[:-1, 3], k=1)
lhs_matrix_dense += np.diag(lhs_matrix_original[:-2, 4], k=2)

assert np.allclose(
    np.linalg.solve(lhs_matrix_dense, rhs_vector_original),
    rhs_vector,
)

Further properties can be computed such as

  • the log-determinant of the matrix
# === Log-Determinant ===

sign, logabsdet = jit_penta.ptrans1_slogdet(factorization=lhs_matrix)
numpy_sign, numpy_logabsdet = np.linalg.slogdet(lhs_matrix_dense)

assert np.isclose(sign, numpy_sign)
assert np.isclose(logabsdet, numpy_logabsdet)
  • the central pentadiagonal band of the inverse in the same layout as the original matrix (symmetric matrices only)
# === Central pentadiagonal band of the inverse ===

inverse_band = jit_penta.ptrans1_symmetric_inverse_central_penta_bands(
    factorization=lhs_matrix
)

numpy_inverse = np.linalg.inv(lhs_matrix_dense)
numpy_inverse_band = np.zeros_like(inverse_band)

numpy_inverse_band[2::, 0] = np.diag(numpy_inverse, k=-2)
numpy_inverse_band[1::, 1] = np.diag(numpy_inverse, k=-1)
numpy_inverse_band[:, 2] = np.diag(numpy_inverse)
numpy_inverse_band[:-1, 3] = np.diag(numpy_inverse, k=1)
numpy_inverse_band[:-2, 4] = np.diag(numpy_inverse, k=2)

assert np.allclose(inverse_band, numpy_inverse_band)

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

pybandee-0.0a1.tar.gz (14.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pybandee-0.0a1-py3-none-any.whl (12.5 kB view details)

Uploaded Python 3

File details

Details for the file pybandee-0.0a1.tar.gz.

File metadata

  • Download URL: pybandee-0.0a1.tar.gz
  • Upload date:
  • Size: 14.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.13

File hashes

Hashes for pybandee-0.0a1.tar.gz
Algorithm Hash digest
SHA256 c1a26896e191b87f2236e8ca0cdae5698b5f2cabaac36e21ff7379e4b31fcff0
MD5 6a844d49d7a14bfcd5328cbc54bcbe84
BLAKE2b-256 977937094492efd582a81b52c3e17664444b917070b74986a0b4cd19e003cae0

See more details on using hashes here.

File details

Details for the file pybandee-0.0a1-py3-none-any.whl.

File metadata

  • Download URL: pybandee-0.0a1-py3-none-any.whl
  • Upload date:
  • Size: 12.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.13

File hashes

Hashes for pybandee-0.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 f472a0ba4436134be2b6caa0e43b79ade83e545b38339bb8b217fa4fb8ff80d6
MD5 f6e746a01c93eadb6ce9d655142f9da9
BLAKE2b-256 cdfe16369ad2571191dbfa4e25830482dea5ccea6e69919a71014af272db2e70

See more details on using hashes here.

Supported by

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