Menu
Learn
Overview Introduction 50 Dimensions Tutorial Snippets vs Other Languages
Build
Editor Playground Compiler API
Docs
Language Spec Formats u keyword Dataframe Python AI Library Feature Status Packages What's Implemented
Platform
Server About Transpilation Web & Templates
Safebox
Why U Analysis Engine Comparison Possibilities

Python → U: What Actually Speeds Up

Every number measured on the same machine. CPython 3.13.0 free-threaded vs U's packed lists compiled with -O3 -march=native (AVX2+FMA). No numpy — pure Python vs pure U.

The headline numbers

Python
U (native)
OperationPythonUSpeedup
matmul(200×200)2,368ms1.5ms
1,530×
distance(1M)201ms1.1ms
191×
variance(1M)65ms0.4ms
162×
dot(1M)134ms0.9ms
146×
mandelbrot(300²) @native920ms7.0ms
131×
softmax(10K)3.0ms0.024ms
122×
norm L2(1M)58ms0.5ms
107×
evens.dot(odds) 5M strided427ms5.0ms
85×
a − b elementwise(1M)138ms1.8ms
77×
sieve(1M) @native182ms3.2ms
57×
max(1M)23ms0.4ms
55×
a × b elementwise(1M)147ms3.1ms
47×
a + b elementwise(1M)161ms3.7ms
43×
min(1M)23ms0.6ms
40×
mean(1M)8ms0.3ms
25×
data[::2].sum(5M) strided81ms3.7ms
22×
map(square, 1M)65ms3.3ms
20×
sum(1M)9ms0.6ms
15×
map(sqrt, 1M)67ms7.4ms
9×
filter+map+sum chain(1M)59ms8.9ms
7×

Why the gap exists

Every Python float is a 24-byte heap object. A list of 1M floats = 1M scattered heap allocations + a pointer array. To sum them, Python walks 1M pointers, dereferences each PyObject, extracts the 8-byte double, adds it. That pointer-chase is the bottleneck — not the arithmetic.

U's typed lists ([N]) are contiguous double* buffers. No object headers, no refcounting, no pointer indirection. The CPU loads 4 doubles per AVX2 instruction and processes them in-register. This is the same layout numpy uses internally — the difference is that U compiles it from source rather than calling into a C extension.

Matrix multiplication — 1,530×

This is the largest gap. Python's triple-nested loop at 200×200 (8M multiply-accumulates) takes 2.4 seconds. U's ikj-ordered loop compiles to a tight SIMD inner loop — the compiler vectorizes the j dimension across 4 doubles per cycle. At 200×200 the working set fits in L2 cache, so every load hits.

# Python: 2,368ms
for i in range(200):
    for k in range(200):
        for j in range(200):
            c[i*200+j] += a[i*200+k] * b[k*200+j]

# U: 1.5ms — same loop, compiled to SIMD
// U: compiler vectorizes the inner loop
result = Tensor.matmul(aa, bb)

Comprehensions → filter/map/reduce chains

Python's [f(x) for x in items if g(x)] builds a list one boxed element at a time. U's .filter().map().reduce() chain operates on packed buffers. The U compiler fuses chains into single-pass loops — no intermediate arrays.

PythonU equivalentPyU×
[x*x for x if x>0.5].filter(xx => xx > 0.5).map(xx => xx * xx)59ms8.9ms7×
sum(x for x if x>0.5).filter(xx => xx > 0.5).reduce((acc, xx) => acc + xx, 0)47ms8.1ms6×

With chain fusion (the compiler's job), .filter(xx => xx > 0.5).map(xx => xx * xx).reduce((acc, xx) => acc + xx, 0) becomes:

double s = 0;
for (long i = 0; i < n; i++)
    if (data[i] > 0.5) s += data[i] * data[i];
// One pass. Zero allocations. ~1ms.

Slicing — zero-copy views

Python's data[::2] allocates a new list and copies every other element. U returns a view — same buffer, stride=2. No allocation, no copy. The view chains: data[::3][1::2] → stride=6, still zero allocation.

OperationPythonU×What U does
data[::2].sum(5M)81ms3.7ms22×stride-2 pointer walk, no copy
evens.dot(odds) 5M427ms5.0ms85×two stride-2 views, one loop

Neural network ops

OperationPythonU×
softmax(10K)3.0ms0.024ms122×
norm(1M)58ms0.5ms107×
matmul(200×200)2,368ms1.5ms1,530×

These are the building blocks of transformer inference. In Python, each operation has per-element function-call overhead. In U, they compile to contiguous memory passes with SIMD. The U runtime's multimodal encoders (ViT, audio, fusion) use these same ops — that's what +V dispatches.

How to use this from Python

Python (boxed)

data = [random() for _ in range(N)]
result = [x*x for x in data if x > 0.5]
total = sum(result)
# 3 passes, 3 allocations, every element boxed

U (compiled)

data: [N] = List.random(1000000)
total = data
    .filter(xx => xx > 0.5)
    .map(xx => xx * xx)
    .reduce((acc, xx) => acc + xx, 0)
// One pass. Zero allocations. Compiler fuses the chain.

numpy interop — zero copy

ulist implements Python's buffer protocol (PEP 3118). memoryview(data) takes 0.006ms — it hands the double* pointer to numpy with no copy. Strided views preserve strides. Mutations propagate both directions.

arr = np.frombuffer(memoryview(data), dtype=np.float64)  # 0ms
series = pd.Series(arr)                                    # 0ms
# All three — ulist, numpy, pandas — point at the same contiguous memory.

U's iteration model

U has no for or while. All iteration is .map(fn), .filter(pred), .reduce(acc, init), .on(handler) with real lambdas (xx => xx * 2). This makes fusion possible: when the compiler sees a chain of pure operations, it merges them into one pass. The +V modifier emits SIMD. +R(GPU) emits a WGSL compute shader.

What doesn't speed up

Python's sorted() uses timsort, which exploits existing order — it beats generic qsort on partially-sorted data. str.count() is already SIMD-optimized in CPython. json.dumps() is bottlenecked by serialization, not numeric compute. The speedups come from eliminating boxing, enabling SIMD on contiguous memory, and fusing operation chains.