Thursday, December 31, 2015

From dot product to matrix multiplication

From dot product to matrix multiplication is only a small step now:

CREATE OR REPLACE FUNCTION public._matmul(
    m1 anyarray,
    m2 anyarray,
    r anyarray)
  RETURNS anyarray AS
$BODY$
DECLARE
ubm1 integer;
ubm2 integer;
BEGIN
ubm1 := array_upper(m1,1);
ubm2 := array_upper(m2,1);

FOR i IN 1..ubm1 LOOP
FOR j in 1..ubm1 loop
r[i][j] := m1[i:i][1:ubm2] +* m2[1:ubm2][j:j];
END LOOP;
END LOOP;

return r;
END;
$BODY$
  LANGUAGE plpgsql IMMUTABLE STRICT;

Since I didn't find a way to either create an array of type anyarray, or determine the type of the input array elements, a correctly sized result array has to be created outside and is passed as an anyarray argument into the function:

select _matmul('{{1.0,2.0,3.0},{4.0,5.0,6.0}}'::double precision[], '{{7.0,8.0},{9.0,10.0},{11.0,12.0}}'::double precision[], '{{null,null},{null,null}}');

{{58,64},{139,154}}

11 ms

This is only a proof of concept. It likely has problems but works good enough to run the example. I especially don't like the two nested loops and the result element access by index, maybe there is a better solution...

3 comments:

  1. you should to use OUT modifier for parameter r

    CREATE OR REPLACE FUNCTION foo(a anyarray, OUT r anyarray) AS $$ ... $$

    ReplyDelete
    Replies
    1. If I declare r as OUT or INOUT, the function does not compile: ERROR: RETURN cannot have a parameter in function with OUT parameters

      So I could do this in a procedure but not in a function.

      Delete
  2. OK, but shouldn't that be:

    CREATE OR REPLACE FUNCTION foo(a anyarray, INOUT r anyarray) AS $$ ... $$

    then because it is passed in, modified and out again? And is this more than syntax? Because it works with the IN default without obvious problems and the documentation does not say wheter argmode triggers some special handling inside the backend...

    ReplyDelete