PDL::G...:NumPy(3pm)

πŸ“¦ version 2.106, in ubuntu stonking

πŸ’– 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 ndarray in NumPy and also ndarray in 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() or ascontiguousarray(). 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 by severing 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::Indexing
  • PDL::NiceSlice
  • PDL::Course
  • PDL::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