Skip to content

EigenValues

Represents the eigenvalues of a square matrix.

Parameters

FieldTypeDescription
datanp.ndarray | list | tupleArray-like data of shape (N,), N >= 1, with a dtype in the allowlist below, converted to a NumPy array.

Raises

ExceptionCondition
TypeErrordata can't be converted into a uniform array (e.g. ragged nested lists)
ValueErrorThe resulting dtype is unsupported (see Supported Dtypes below), data isn't 1-D, data is empty (size == 0), or it contains a non-finite value (NaN/Inf)

Supported Dtypes

Inherited unchanged from Array:

CategoryDtypes
Booleanbool
Signed / unsigned integerint8int64, uint8uint64
Floating-pointfloat16, float32, float64
Complexcomplex64, complex128

object, structured, and datetime64 dtypes are not supported.

Attributes

AttributeTypeDescription
datanp.ndarrayThe wrapped 1-D array, shape (N,). Reading it returns a copy, so mutating the result doesn't affect the EigenValues. Note: assigning .data = ... re-validates only the dtype (inherited from Array) — it does not re-check the 1-D / non-empty / finite constraints enforced at construction, so it's possible to end up with a mutated instance that no longer satisfies them. Use the constructor, copy(), or coerce() when full re-validation matters.
shapetuple[int](N,).
ndimintAlways 1.
dtypenp.dtypeDtype of the array as constructed — not forced to float32.
sizeintN.

Methods

MethodDescription
to_numpy(copy=True)Returns the array as np.ndarray. Pass copy=False to get a reference to the internal array instead — faster for large data, but mutating it mutates the EigenValues too.
copy()Returns a new EigenValues with an independent copy of the data, re-validated through the constructor.
EigenValues.coerce(value)Returns value unchanged if it's already an EigenValues; otherwise wraps a np.ndarray/list/tuple into one via the constructor (full validation). Raises TypeError for any other input.
is_positive_semidefinite(atol=None)True if every eigenvalue is >= -atol. atol defaults to 100 * eps(dtype) (using float64 eps when the dtype isn't a floating-point kind).
is_positive_definite(atol=None)True if every eigenvalue is > atol, using the same default atol as is_positive_semidefinite.
condition_number (property)max|λ| / min|λ| over the stored eigenvalues. Raises ZeroDivisionError if any eigenvalue's magnitude is exactly 0 (singular matrix).

Operators

OperationBehavior
e1 == e2True only if other is also an EigenValues with the same dtype, shape, and values (NaN counts as equal to NaN here). False for anything else.
len(e)Number of stored eigenvalues, N.
np.asarray(e)Works directly — NumPy functions (e.g. np.sum, np.abs) accept an EigenValues in place of an np.ndarray. Always returns a copy; use to_numpy(copy=False) for a zero-copy view.
hash(e)Not supported — an EigenValues can't be used as a dict key or set member.

Visualization

datatypes.visualize(eigenvalues, entity_path=...) logs the values as text (rr.TextLog) — it shares this handler with Array, Mat2x2, Mat3x3, and Mat4x4. A bar chart was deliberately not used: with the handful of eigenvalues typical of these matrices, it would render as a couple of undifferentiated solid blocks and convey less than the printed array. No label handler is registered for EigenValues — passing label to visualize() has no effect for it.

Example

python
"""Demonstrates the Telekinesis EigenValues datatype."""

import time

import numpy as np
from loguru import logger
import rerun as rr

from telekinesis import datatypes

def eigenvalues_example():
    """Demonstrate creation, inspection, visualization, update, positive-definiteness checks, NumPy interop, and serialization."""

    # ======================= Create ============================================
    matrix = np.array([[2.0, 1.0], [1.0, 2.0]], dtype=np.float32)
    w, _ = np.linalg.eigh(matrix)
    eigenvalues = datatypes.EigenValues(w)

    logger.info(f"Input eigenvalues: {w}")
    logger.info(f"Original EigenValues: {eigenvalues}")

    # ======================= Inspect ===========================================
    data = eigenvalues.data
    shape = eigenvalues.shape
    size = eigenvalues.size
    dtype = eigenvalues.dtype
    ndim = eigenvalues.ndim
    numpy_array = eigenvalues.to_numpy()
    eigenvalues_copy = eigenvalues.copy()

    logger.info(
        f"shape={shape}, "
        f"size={size}, "
        f"ndim={ndim}, "
        f"dtype={dtype}"
    )
    logger.info(f"Data: {data}")
    logger.info(f"NumPy array: {numpy_array}")
    logger.info(f"Copied EigenValues: {eigenvalues_copy}")

    # ======================= Visualize =========================================
    rr.init("eigenvalues_example", spawn=True)
    datatypes.visualize(eigenvalues, entity_path="/EigenValues", label="Original EigenValues")

    # ======================= Update ============================================
    new_w, _ = np.linalg.eigh(np.array([[5.0, 2.0], [2.0, 5.0]], dtype=np.float32))
    eigenvalues.data = new_w
    logger.info(f"Updated EigenValues: {eigenvalues}")
    datatypes.visualize(
        eigenvalues, entity_path="/EigenValues/updated", label="Updated EigenValues"
    )

    # ======================= Checks ============================================
    positive_definite = eigenvalues.is_positive_definite()
    positive_semidefinite = eigenvalues.is_positive_semidefinite()
    condition_number = eigenvalues.condition_number

    logger.info(
        f"is_positive_definite={positive_definite}, "
        f"is_positive_semidefinite={positive_semidefinite}, "
        f"condition_number={condition_number}"
    )

    # ======================= NumPy Interop =====================================
    spectral_radius = np.max(np.abs(eigenvalues))
    logger.info(f"Spectral radius (max |eigenvalue|): {spectral_radius}")

    # ======================= Serialize / Deserialize ===========================
    start = time.perf_counter()
    serialized = datatypes.serialize(eigenvalues)
    serialization_ms = (time.perf_counter() - start) * 1000

    start = time.perf_counter()
    deserialized = datatypes.deserialize(serialized)["param_0"]
    deserialization_ms = (time.perf_counter() - start) * 1000

    logger.info(f"Deserialized EigenValues: {deserialized}")
    logger.info(f"Round-trip successful: {deserialized == eigenvalues}")
    logger.info(f"Serialization time: {serialization_ms:.3f} ms")
    logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")


if __name__ == "__main__":
    eigenvalues_example()

See also EigenVectors and Array.