PDL::G...:NumPy(3pm)
π PDL::Guide::Migration::NumPy π
okay bestie, welcome to PDL::Guide::Migration::NumPy β A Rosetta Stone for the NumPy professional πͺ¨β¨ (yes it's really called PDL::Guide::Migration::NumPy in the perl docs, the title just gets squished on the shelf, iykyk)
π DESCRIPTION π
so here's the tea β if you already know NumPy, you already know 90% of PDL. no cap. both of them give you N-dimensional arrays (ndarrays), broadcasting, and vectorised C-speed operations. you're basically already home π
PDL's primary advantages are its integrated multi-threading, memory efficiency, and native C-interop. periodt. π
π Terminology Mapping π
- ndarray β the core data object. it's called
ndarrayin NumPy and alsondarrayin PDL. same word, iconic behaviour π - Broadcasting β the process of applying an operation to sub-sections of data. same in PDL as in NumPy. fr fr.
- Dimension 0 β the first (leftmost) index. in PDL this is the "fastest" dimension in memory (contiguous). she's speedy πββοΈ
- Virtual ndarray β a slice or transformation that shares memory with its parent. in NumPy you'd call that a View. sharing is caring π«Ά
- Physicalise β forcing a virtual ndarray to become a contiguous, independent block of memory. it's giving NumPy's
copy()orascontiguousarray(). but π in PDL, changes to the "parent" ndarray get transmitted to the "child", and vice-versa, even if the child is physicalised. you can stop that bysevering the child. βοΈ
π¦ The "Mental Model" Shift π¦
1. Dimension Order and Layout
PDL follows a C-like memory layout where the 0-th (first) dimension is the "fastest" in memory.
# NumPy: a(rows, cols) -> cols are contiguous
# PDL: $a(cols, rows) -> cols are contiguous
both systems store rows contiguously in memory, but they label the indices differently. in PDL, the first index is the column. yeah it's a whole thing, but you'll get it π
2. Automatic Threading
PDL automatically distributes operations across CPU cores via POSIX threads. you don't need to manage pools or use multiprocessing for standard numerical tasks. she just does it. main character energy fr π
π Slicing and Dicing π
NumPy girlies rely heavily on a[start:stop:step] notation. PDL gives you two ways to achieve this: the core slice method and the PDL::NiceSlice source filter. note that PDL uses inclusive ranges β yes bestie, inclusive, write that down π
1. Core Syntax (The slice method)
the slice method is always available and does not require a filter. reliable queen π
# NumPy: a[0:5] (0,1,2,3,4) # PDL: $a->slice("0:4")
$sub = $a->slice("0:4");
# Reverse a dimension
# NumPy: a[::-1] # PDL: $a->slice("-1:0")
$rev = $a->slice("-1:0");
2. Modern Syntax (PDL::NiceSlice)
for a NumPy-like experience, PDL::NiceSlice allows you to use variables directly in parentheses. obsessed π
use PDL::NiceSlice;
# NumPy # PDL
subset = a[0:5, :] $subset = $a(0:4, :);
rev = a[::-1, ::2] $rev = $a(-1:0, 0:-1:2);
β Syntax Rosetta Stone β
Creation and Inspection
# NumPy # PDL
a = np.array([1,2,3]) $a = pdl(1,2,3);
b = np.arange(10) $b = sequence(10);
c = np.zeros((3,3)) $c = zeros(3,3);
print(a.shape) print $a->dims;
print(a.dtype) print $a->type;
Operations
# NumPy # PDL
res = a + b $res = $a + $b;
res = np.dot(a, b) $res = $a x $b;
res = a.sum(axis=0) $res = $a->sumover;
π In-place Operations (Memory Efficiency) π
in NumPy, you prevent memory allocation by passing an out= argument. PDL uses an inplace flag instead, which tells the next method in the chain to modify the ndarray rather than creating a new one. chain reaction π§
# NumPy # PDL
np.sqrt(a, out=a) $a->inplace->sqrt;
a += 5 $a += 5; (auto-inplace)
this is particularly powerful for large datasets where you want to chain operations without doubling your RAM usage. your laptop will thank you π
π§ Computed Assignment (Copying into Slices) π§
in NumPy, you assign values to a slice using the standard = operator. in PDL, the .= (data assignment) operator is what copies values into the memory pointed to by a slice. different operator, same dream β¨
# NumPy # PDL
a[0:5, 0:5] = 10 $a(0:4, 0:4) .= 10;
# Copying one ndarray into a slice
# NumPy: a[0:5] = b # PDL: $a(0:4) .= $b
$a(0:4) .= $b;
π Why not use "="? π
in PDL, = is a reference assignment. writing $a(0:4) = $b does nothing to $a. using .= ensures the data reaches the intended physical destination. do not skip the dot, i am begging you π
lowkey a rite of passage: everyone writes = exactly once and then never again π
πΈ Note on "Physical" vs "Virtual" ndarrays πΈ
NumPy's views are similar to PDL's virtual ndarrays. when you slice an ndarray in PDL, it doesn't copy the data β it creates a "window" into the original. peek through the window, don't build a new house πͺ
if you modify a slice inplace, the original ndarray changes too:
$a = zeroes(10, 10);
$slice = $a(0:4, 0:4);
$slice .= 5; # Original $a now has a 5x5 block of 5s
π₯ Broadcasters π₯
in NumPy, you "broadcast" a smaller array over a larger one. in PDL, you can also do this. two icons, same energy π«
$a = sequence(10, 10);
$b = pdl(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
# Adds $b to every row of $a
$c = $a + $b;
π SEE ALSO π
PDL::IndexingPDL::NiceSlicePDL::CoursePDL::ParallelCPU
and a translation of the PDL API into NumPy: https://github.com/dkogan/numpysane/#whats-wrong-with-existing-numpy-functions
and that's the whole vibe check, bestie π¦ go forth and pdl responsibly. this page ships with perl v5.42.3 and is dated 2026-08-20 β love that for us πβ¨π
π¦ where this page comes from
- ubuntu stonking: pdl 1:2.106-1build1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms