EigenVectors
Represents the eigenvectors of a square matrix, one per column.
Parameters
| Field | Type | Description |
|---|---|---|
data | np.ndarray | list | tuple | Array-like data of shape (N, N): square, non-empty, dtype in the allowlist below. Columns are the eigenvectors. |
atol | float | None | Keyword-only. Absolute tolerance for the orthonormality check (V^T V ≈ I, or V^H V ≈ I for complex dtypes). Defaults to 100 * eps(dtype) * sqrt(N). |
rtol | float | Keyword-only. Relative tolerance for the same check. Defaults to 0.0, since the reference matrix is the identity and rtol has no effect on its zero entries. |
Raises
| Exception | Condition |
|---|---|
TypeError | data can't be converted into a uniform array (e.g. ragged nested lists) |
ValueError | The resulting dtype is unsupported (see Supported Dtypes below), data isn't 2-D, isn't square, is empty (0x0), contains a non-finite value (NaN/Inf), or its columns aren't orthonormal within atol/rtol |
Supported Dtypes
Inherited unchanged from Array:
| Category | Dtypes |
|---|---|
| Boolean | bool |
| Signed / unsigned integer | int8…int64, uint8…uint64 |
| Floating-point | float16, float32, float64 |
| Complex | complex64, complex128 |
object, structured, and datetime64 dtypes are not supported.
Attributes
| Attribute | Type | Description |
|---|---|---|
data | np.ndarray | The wrapped (N, N) array; column k is the k-th eigenvector. Reading it returns a copy. Note: assigning .data = ... re-validates only the dtype (inherited from Array) — it does not re-check squareness, finiteness, or orthonormality, so it's possible to leave the instance holding non-orthonormal columns after such an assignment. Use the constructor, copy(), or coerce() when full re-validation matters. |
shape | tuple[int, int] | (N, N). |
ndim | int | Always 2. |
dtype | np.dtype | Dtype of the array as constructed — not forced to float32. |
size | int | N * N. |
Methods
| Method | Description |
|---|---|
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 EigenVectors too. |
copy() | Returns a new EigenVectors with an independent copy of the data, re-validated through the constructor using its default atol/rtol. |
EigenVectors.coerce(value) | Returns value unchanged if it's already an EigenVectors; otherwise wraps a np.ndarray/list/tuple into one via the constructor (full validation, default atol/rtol). Raises TypeError for any other input. |
check_orthonormality(data, atol=None, rtol=0.0) | Checks whether an arbitrary square (N, N) array's columns are orthonormal — not limited to self's own data. Raises ValueError if data isn't square 2-D or is empty. |
is_orthonormal(atol=None, rtol=0.0) | Checks this instance's own data for orthonormality within the given tolerance (delegates to check_orthonormality). |
Operators
| Operation | Behavior |
|---|---|
v1 == v2 | True only if other is also an EigenVectors with the same dtype, shape, and values (NaN counts as equal to NaN here). False for anything else. |
len(v) | N (number of rows, equal to the number of columns). |
np.asarray(v) | Works directly — NumPy functions accept an EigenVectors in place of an np.ndarray. Always returns a copy; use to_numpy(copy=False) for a zero-copy view. |
hash(v) | Not supported — an EigenVectors can't be used as a dict key or set member. |
Visualization
datatypes.visualize(eigenvectors, entity_path=...) has a dedicated handler: for N == 3 it logs the columns as 3D basis arrows (rr.Arrows3D) from the world origin, colored red/green/blue and labeled e0/e1/e2; for N == 2 it logs 2D basis arrows (rr.Arrows2D) the same way, colored red/green and labeled e0/e1. For any other N it falls back to text (rr.TextLog), since there's no spatial rendering for a higher-dimensional basis. No label handler is registered for user-supplied labels — passing label to visualize() has no effect for EigenVectors; the e0/e1/e2 axis labels are generated internally and always shown.
Example
"""Demonstrates the Telekinesis EigenVectors datatype."""
import time
import numpy as np
from loguru import logger
import rerun as rr
from telekinesis import datatypes
def eigenvectors_example():
"""Demonstrate creation, inspection, visualization, update, tolerance relaxation, eigen-relation verification, and serialization."""
# ======================= Create ============================================
matrix = np.array([[2.0, 1.0], [1.0, 2.0]], dtype=np.float64)
w, v = np.linalg.eigh(matrix)
eigenvectors = datatypes.EigenVectors(v)
logger.info(f"Input eigenvectors:\n{v}")
logger.info(f"Original EigenVectors: {eigenvectors}")
# ======================= Inspect ===========================================
data = eigenvectors.data
shape = eigenvectors.shape
size = eigenvectors.size
dtype = eigenvectors.dtype
ndim = eigenvectors.ndim
numpy_array = eigenvectors.to_numpy()
eigenvectors_copy = eigenvectors.copy()
logger.info(
f"shape={shape}, "
f"size={size}, "
f"ndim={ndim}, "
f"dtype={dtype}"
)
logger.info(f"Data:\n{data}")
logger.info(f"NumPy array: {numpy_array}")
logger.info(f"Copied EigenVectors: {eigenvectors_copy}")
# ======================= Visualize =========================================
rr.init("eigenvectors_example", spawn=True)
datatypes.visualize(eigenvectors, entity_path="/EigenVectors", label="Original EigenVectors")
# ======================= Update ============================================
_, new_v = np.linalg.eigh(np.array([[5.0, 2.0], [2.0, 5.0]], dtype=np.float64))
eigenvectors.data = new_v
logger.info(f"Updated EigenVectors: {eigenvectors}")
datatypes.visualize(
eigenvectors, entity_path="/EigenVectors/updated", label="Updated EigenVectors"
)
# ======================= Tolerance =========================================
relaxed = datatypes.EigenVectors(v + 1e-10, atol=1e-6)
logger.info(f"Noisy input accepted with atol=1e-6: {relaxed}")
# ======================= Verify ============================================
for k in range(eigenvectors.shape[1]):
v_k = data[:, k]
lhs = matrix @ v_k
rhs = w[k] * v_k
logger.info(f"Eigenvector {k} satisfies A @ v == w * v: {np.allclose(lhs, rhs)}")
# ======================= Serialize / Deserialize ===========================
start = time.perf_counter()
serialized = datatypes.serialize(eigenvectors)
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 EigenVectors: {deserialized}")
logger.info(f"Round-trip successful: {deserialized == eigenvectors}")
logger.info(f"Serialization time: {serialization_ms:.3f} ms")
logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")
if __name__ == "__main__":
eigenvectors_example()See also EigenValues and Array.

