Skip to main content

A pure Python linear algebra and tensor library for educational purposes

Project description

PotatoNumPy ๐Ÿฅ”

A pure Python linear algebra and tensor library built entirely from scratch. No NumPy, no C extensions, no shortcuts โ€” just potatoes all the way down.

It took me 3 weeks alone and 2 hours of Claude documentation refinement to make this.

What is this?

PotatoNumPy is a learning project that answers three questions I kept asking myself:

  1. How does linear algebra actually work under the hood? Every matrix multiplication here is three nested loops. Every determinant is recursive cofactor expansion. Nothing hides behind an opaque C function โ€” you can read every line and follow along.

  2. Why is NumPy so ridiculously fast? After watching PotatoNumPy chug through a 50x50 matrix multiply, you'll feel what NumPy's C/Fortran backends, SIMD vectorization, and contiguous memory layouts buy you. It's not subtle.

  3. What does Python's interpreter overhead actually cost? Dynamic type checking, function call overhead, pointer-chasing through Python lists โ€” it all adds up. This library makes that cost painfully tangible.

Installation

pip install potatonumpy

Or clone and install locally:

git clone https://github.com/Madhavyamjala/potatonumpy.git
cd potatonumpy
pip install -e .

No dependencies needed โ€” that's the whole point.

Quick Start

import potatonumpy as pp

# Create arrays
a = pp.array([1, 2, 3])
b = pp.array([4, 5, 6])

# Elementwise math, just like you'd expect
print(a + b)        # [5, 7, 9]
print(a * b)        # [4, 10, 18]
print(a ** 2)       # [1, 4, 9]
print(a + 10)       # [11, 12, 13]

# Linear algebra
print(pp.dot(a, b))         # 32
print(pp.cross(a, b))       # [-3, 6, -3]
print(pp.magnitude(a))      # 3.7416...
print(pp.normalize(a))      # [0.2672, 0.5345, 0.8017]

Matrix Operations

import potatonumpy as pp

A = pp.array([[1, 2], [3, 4]])
B = pp.array([[5, 6], [7, 8]])

print(pp.matmul(A, B))      # [[19, 22], [43, 50]]
print(pp.transpose(A))      # [[1, 3], [2, 4]]
print(pp.determinant(A))    # -2.0
print(pp.inverse(A))        # [[-2, 1], [1.5, -0.5]]
print(pp.trace(A))          # 5
print(pp.diagonal(A))       # [1, 4]

# Special matrices
print(pp.identity(3))
print(pp.zeros((2, 3)))

Array Manipulation & Attributes

You can inspect array metadata and modify structural dimensions.

import potatonumpy as pp

a = pp.array([[1, 2, 3], [4, 5, 6]])

print(a.ndim)
print(a.size)
print(a.shape)

flat = a.flatten()
print(flat)

reshaped = flat.reshape((3, 2))
print(reshaped)

raw_list = reshaped.tolist()
print(raw_list)

Tensors? Yeah, We Got Those

import potatonumpy as pp

# 3D tensor โ€” go wild
t = pp.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print(t.shape)              # (2, 2, 2)

# Reductions
print(pp.tensor_sum(t))             # 36
print(pp.tensor_sum(t, axis=0))     # [[6, 8], [10, 12]]
print(pp.tensor_mean(t))            # 4.5
print(pp.tensor_min(t))             # 1
print(pp.tensor_max(t))             # 8

Type Support

Works with int, float, and complex:

c = pp.array([1+2j, 3+4j])
print(c + 1)    # [(2+2j), (4+4j)]

Error Handling

PotatoNumPy doesn't silently do the wrong thing. It yells at you with specific exceptions:

from potatonumpy import (
    ShapeMismatchError,  # tried to add (2,) and (3,)?
    InvalidTensorError,  # ragged array? nope
    SingularMatrixError,  # can't invert that matrix, sorry
    InvalidOperationError,  # division by zero, etc.
)

pp.array([1, 2]) + pp.array([1, 2, 3])  # ShapeMismatchError
pp.array([[1, 2], [3, 4, 5]])  # InvalidTensorError
pp.inverse(pp.array([[1, 2], [2, 4]]))  # SingularMatrixError
pp.array([1, 2]) / 0  # InvalidOperationError

Benchmarks (Prepare to Cringe)

python examples/benchmarking.py

Here's what you'll see (roughly):

Operation Pure Loops PotatoNumPy NumPy Slowdown vs NumPy
Vector Add (10k) ~2ms ~5ms ~0.01ms ~500x
Matrix Mul (50x50) ~50ms ~80ms ~0.05ms ~1600x
Scalar Mul (10k) ~1ms ~3ms ~0.005ms ~600x

Yeah. NumPy is that much faster. Here's why:

What PotatoNumPy NumPy
Inner loops Python bytecode Compiled C/Fortran
Memory layout Scattered Python objects Contiguous typed arrays
Vectorization Nope SIMD instructions
Type checking Every single operation Once at array creation
Function calls Python stack frames Inlined C calls
Math backend Hand-rolled loops BLAS/LAPACK

Running Tests

python -m unittest discover tests -v

99 tests (One Short ๐Ÿฅฒ) covering all operations, edge cases, and error conditions.

Project Structure

.
โ”œโ”€โ”€ src/
โ”‚   โ””โ”€โ”€ potatonumpy/
โ”‚       โ”œโ”€โ”€ __init__.py       
โ”‚       โ”œโ”€โ”€ core.py           
โ”‚       โ”œโ”€โ”€ linalg.py         
โ”‚       โ”œโ”€โ”€ tensor.py         
โ”‚       โ”œโ”€โ”€ exceptions.py     
โ”‚       โ”œโ”€โ”€ utils.py          
โ”‚       โ””โ”€โ”€ benchmarks.py     
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ test_core.py
โ”‚   โ”œโ”€โ”€ test_linalg.py
โ”‚   โ””โ”€โ”€ test_tensor.py
โ”œโ”€โ”€ examples/
โ”‚   โ”œโ”€โ”€ vectors.py
โ”‚   โ”œโ”€โ”€ matrices.py
โ”‚   โ””โ”€โ”€ benchmarking.py
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ pyproject.toml
โ””โ”€โ”€ setup.py

Design Philosophy

  • No magic. Every operation is explicit loops you can step through in a debugger. Want to understand how matrix inverse works? Read the code.
  • Recursion over cleverness. Determinants use cofactor expansion. Shape validation walks the full tree. This is intentional โ€” clarity over performance.
  • The slowness is a feature. Seriously. The massive performance gap between PotatoNumPy and NumPy is the lesson.
  • Zero dependencies. Standard library only. If Python doesn't ship it, we don't use it.

Limitations (by Design)

  • Slow. Orders of magnitude slower than NumPy. That's the point.
  • Scalar broadcasting only. No fancy NumPy-style shape broadcasting.
  • Memory hungry. Python lists use ~8x more memory per element than NumPy arrays.
  • Determinant is O(n!). Don't try matrices bigger than ~12x12 unless you have time to spare.
  • No eigenvalues, SVD, FFT, or sparse matrices. This is an educational tool, not a production library.

License

MIT License. See LICENSE for details.


Built with love, frustration, and an unreasonable number of nested for loops. ๐Ÿฅ”

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

potatonumpy-0.1.0.tar.gz (18.5 kB view details)

Uploaded Source

Built Distribution

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

potatonumpy-0.1.0-py3-none-any.whl (14.9 kB view details)

Uploaded Python 3

File details

Details for the file potatonumpy-0.1.0.tar.gz.

File metadata

  • Download URL: potatonumpy-0.1.0.tar.gz
  • Upload date:
  • Size: 18.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for potatonumpy-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3d58c8c710981d4ff54459caef2e66064134d867bcabd236630c03fd5dd9b169
MD5 b9efb04e38ae20c80228d4469ee46b29
BLAKE2b-256 717dc0f2efe19cbd6445fa0718631782eb43304ca4fd92e5ac2d9dbf84f1db20

See more details on using hashes here.

Provenance

The following attestation bundles were made for potatonumpy-0.1.0.tar.gz:

Publisher: publish.yml on Madhavyamjala/potatonumpy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file potatonumpy-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: potatonumpy-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for potatonumpy-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 08276c0a5fa5bbd6f69a704aa312be9e199b27249bf92e3c13a4322e43d372a7
MD5 d42bcfc04303f7876b51c471217424bf
BLAKE2b-256 8d4c5f27d097b8684593082ac684834a19eccbcc4b982d2969ea355719dfa85f

See more details on using hashes here.

Provenance

The following attestation bundles were made for potatonumpy-0.1.0-py3-none-any.whl:

Publisher: publish.yml on Madhavyamjala/potatonumpy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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