MatrixOps(3pm)

πŸ“¦
version 1.24.1 Β· 5 versions
, in debian trixie, ubuntu resolute

🌸 PDL::CCS::MatrixOps 🌸

okay bestie, so this is PDL::CCS::MatrixOps, a page from the User Contributed Perl Documentation section of the manual (you know, the 3pm girlies) πŸ’…. It's all about low-level matrix operations for compressed storage sparse PDLs β€” yes it's giving very "under the hood, do not perceive me" energy, but we're gonna get through it together fr fr 🫢.


✨ SYNOPSIS ✨

 use PDL;
 use PDL::CCS::MatrixOps;

 ##---------------------------------------------------------------------
 ## ... stuff happens

no cap, that's literally the whole synopsis. the vibes are immaculate, the details are sparse (pun fully intended πŸ“).


πŸŽ€ FUNCTIONS πŸŽ€

πŸ’– ccs_matmult2d_sdd πŸ’–

signature, bestie, look at her:

  indx ixa(Two=2,NnzA); nza(NnzA); missinga();
  b(O,M);
  zc(O);
  [o]c(O,N)
  ; PDL_Indx sizeN

so what's the tea? this is two-dimensional matrix multiplication of a sparse index-encoded PDL $a() with a dense pdl $b(), and the output goes to a dense pdl $c(). iconic behavior honestly πŸ‘‘

you gotta pass that sparse input PDL $a() in here with 0th dimension "M" and 1st dimension "N" β€” exactly like you would for the built-in PDL::Primitive::matmult(). same rules, different girl πŸ’…

now, the "missing" values in $a()? they get treated as $missinga(). and heads up: $missinga() shouldn't be BAD or infinite, but other than that it ought to be handled correctly. the input pdl $zc() is there to pass along the cached contribution of a $missinga()-row ("M") to an output column ("O"), like so:

 $zc = ((zeroes($M,1)+$missinga) x $b)->flat;

also $SIZE(Two) must be 2. periodt.

and yes, ccs_matmult2d_sdd processes bad values 🫣 β€” it will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.


πŸ’œ ccs_matmult2d_zdd πŸ’œ

signature time:

  indx ixa(Two=2,NnzA); nza(NnzA);
  b(O,M);
  [o]c(O,N)
  ; PDL_Indx sizeN

another two-dimensional matrix multiplication of a sparse index-encoded PDL $a() with a dense pdl $b(), output landing in a dense pdl $c(). the way she's basically the sibling of the function above... family resemblance is real 🌸

same deal as before: pass that sparse input PDL $a() with 0th dimension "M" and 1st dimension "N", just like for the built-in PDL::Primitive::matmult().

the difference? here, "missing" values in $a() are treated as zero. and $SIZE(Two) must be 2.

also she processes bad values πŸ’€ β€” the bad-value flag of all output ndarrays gets set if the flag is set for any of the input ndarrays.


πŸ¦‹ ccs_vnorm πŸ¦‹

signature:

  indx acols(NnzA); avals(NnzA);
  float+ [o]vnorm(M);
  ; PDL_Indx sizeM=>M

okay so this one computes the Euclidean lengths of each column-vector $a(i,*) of a sparse index-encoded pdl $a() of logical dimensions (M,N), and drops the output into a dense piddle $vnorm(). "Missing" values in $a() are treated as zero, and $acols() specifies the (unsorted, bestie, unsorted) indices along the logical dimension M of the corresponding non-missing values in $avals().

this is basically the same thing as:

 $vnorm = ($a**2)->xchg(0,1)->sumover->sqrt;

...but it should be must faster to compute for sparse index-encoded piddles. (yes, that's what the original says. "must faster". we're keeping it, no notes πŸ’€βœ¨)

and ccs_vnorm() always clears the bad-status flag on $vnorm().


🧚 ccs_vcos_zdd 🧚

signature:

  indx ixa(2,NnzA); nza(NnzA);
  b(N);
  float+ [o]vcos(M);
  float+ [t]anorm(M);
  PDL_Indx sizeM=>M;

this girlie computes the vector cosine similarity of a dense row-vector $b(N) with respect to each column $a(i,*) of a sparse index-encoded PDL $a() of logical dimensions (M,N), with output to a dense piddle $vcos(M). "Missing" values in $a() are treated as zero, and the magnitudes for $a() get passed in via the optional parameter $anorm() β€” which will be implicitly computed using ccs_vnorm if the $anorm() parameter is omitted or empty. lowkey convenient 🫢

this is basically the same thing as:

 $anorm //= ($a**2)->xchg(0,1)->sumover->sqrt;
 $vcos    = ($a * $b->slice("*1,"))->xchg(0,1)->sumover / ($anorm * ($b**2)->sumover->sqrt);

...but should be must faster to compute. again. it's her catchphrase.

output values in $vcos() are cosine similarities in the range [-1,1] β€” except for zero-magnitude vectors, which will result in NaN values in $vcos(). if you need non-negative distances, follow this up with a:

 $vcos->minus(1,$vcos,1)
 $vcos->inplace->setnantobad->inplace->setbadtoval(0); ##-- minimum distance for NaN values

to get distance values in the range [0,2]. and the way you can use PDL threading to batch-compute distances for multiple $b() vectors simultaneously?? obsessed 😭

  $bx   = random($N, $NB);                   ##-- get $NB random vectors of size $N
  $vcos = ccs_vcos_zdd($ixa,$nza, $bx, $M);  ##-- $vcos is now ($M,$NB)

ccs_vcos_zdd() always clears the bad status flag on the output piddle $vcos.


πŸ“ _ccs_vcos_zdd πŸ“

signature:

  indx ixa(Two=2,NnzA); nza(NnzA);
  b(N);
  float+ anorm(M);
  float+ [o]vcos(M);

this is the guts for ccs_vcos_zdd() β€” the understudy, the behind-the-scenes main character energy β€” with slightly different calling conventions. iykyk πŸ’…

she always clears the bad status flag on the output piddle $vcos.


🌈 ccs_vcos_pzd 🌈

signature:

  indx aptr(Nplus1); indx acols(NnzA); avals(NnzA);
  indx brows(NnzB);                     bvals(NnzB);
  anorm(M);
  float+ [o]vcos(M);

bestie this one computes the vector cosine similarity of a sparse index-encoded row-vector $b() of logical dimension (N) with respect to each column $a(i,*) β€” a sparse Harwell-Boeing row-encoded PDL $a() of logical dimensions (M,N) β€” with output to a dense piddle $vcos(M).

"Missing" values in $a() are treated as zero, and the magnitudes for $a() are passed in via the obligatory parameter $anorm() (no skipping it, she's required πŸ’…). this is usually much faster than ccs_vcos_zdd() if a CRS pointer over logical dimension (N) is available for $a(). slay.

and ccs_vcos_pzd() always clears the bad status flag on the output piddle $vcos.


🫢 ACKNOWLEDGEMENTS 🫢

shoutout time, we love to see it:

  • Perl by Larry Wall.
  • PDL by Karl Glazebrook, Tuomas J. Lukka, Christian Soeller, and others.

πŸ’€ KNOWN BUGS πŸ’€

ngl, the authors themselves said it: we should really implement matrix multiplication in terms of inner product, and have a good sparse-matrix only implementation of the former. so that's a whole thing that's not done yet. iconic honesty though 🌸


πŸ‘‘ AUTHOR πŸ‘‘

Bryan Jurish <moocow@cpan.org> β€” the mastermind, the moment, the whole vibe ✨

all other parts Copyright (C) 2009-2024, Bryan Jurish. all rights reserved.

this package is free software, and entirely without warranty. you may redistribute it and/or modify it under the same terms as Perl itself. periodt πŸ’…


πŸ”₯ SEE ALSO πŸ”₯

perl(1), PDL(3perl)


and that's the whole page bestie!! this was MatrixOps(3pm) from perl v5.40.0, dated 2025-01-04 β€” go forth and multiply (matrices) πŸ’–πŸ¦‹πŸŽ€

πŸ“¦ where this page comes from