Compute the Matrix-Vector

14

1

Given an integer array of at least two elements, output the Matrix-Vector (defined below) of the array.

To compute the Matrix-Vector, first rotate through the size-n input array to create a matrix of size n x n, with the first element of the array following the main diagonal. This forms the matrix portion. For the vector, flip the input array vertically. Then perform normal matrix multiplication. The output vector is the result.

For example,

a = [1, 2, 3]

First, rotate the array two times to the right, to obtain [3, 1, 2] and [2, 3, 1], then stack them to form a 3x3 matrix

[[1, 2, 3]
 [3, 1, 2]
 [2, 3, 1]]

Next, flip the array vertically to form the vector

[[1, 2, 3]    [[1]
 [3, 1, 2]  x  [2]
 [2, 3, 1]]    [3]]

Perform usual matrix multiplication

[[1, 2, 3]    [[1]    [[1+4+9]    [[14]
 [3, 1, 2]  x  [2]  =  [3+2+6]  =  [11]
 [2, 3, 1]]    [3]]    [2+6+3]]    [11]]

And the output is [14, 11, 11] or [[14], [11], [11]] (your choice of whether it's flattened or not).

Example #2

a = [2, 5, 8, 3]

[[2, 5, 8, 3]    [[2]    [[4+25+64+9]     [[102]
 [3, 2, 5, 8]  x  [5]  =  [6+10+40+24]  =  [80]
 [8, 3, 2, 5]     [8]     [16+15+16+15]    [62]
 [5, 8, 3, 2]]    [3]]    [10+40+24+6]]    [80]]

[102, 80, 62, 80]

Rules

  • The input and output can be assumed to fit in your language's native integer type.
  • The input and output can be given in any convenient format.
  • Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
  • If possible, please include a link to an online testing environment so other people can try out your code!
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

AdmBorkBork

Posted 2017-07-28T14:36:48.590

Reputation: 41 581

Answers

8

Jelly, 5 bytes

ṙJṚæ.

Try it online!

Explanation

Firstly:

where vk are row vectors and x is a column vector.

This demonstrates that matrix multiplication is just dot product between rows and columns.

Then, v1 is actually v rotated 0 to the right, and vk is v rotated k-1 to the right, etc.

From another angle, v1 is v rotated n to the left, and vn is v rotated 1 to the left, etc.

How it works

ṙJṚæ.   input: z (a list of length n)
ṙJ      [rot(z,1), rot(z,2), ..., rot(z,n)] (to the left)
  Ṛ     [rot(z,n), ..., rot(z,2), rot(z,1)]
   æ.   [rot(z,n).z , ..., rot(z,2).z , rot(z,1).z] (dot product)

Leaky Nun

Posted 2017-07-28T14:36:48.590

Reputation: 45 011

5

Python 2, 68 bytes

lambda x:[sum(map(int.__mul__,x,x[i:]+x[:i]))for i in range(len(x))]

Try it online!

Rod

Posted 2017-07-28T14:36:48.590

Reputation: 17 588

4

Python 2, 73 bytes

def f(v):r=range(len(v));return[sum(v[i]*(v*2)[i+j]for i in r)for j in r]

Try it online!

Arfie

Posted 2017-07-28T14:36:48.590

Reputation: 1 230

(v*2)[i+j] nice trick – Leaky Nun – 2017-07-28T14:44:53.667

4

Pyth, 10 bytes

ms*VQ.>QdU

Test suite.

Leaky Nun

Posted 2017-07-28T14:36:48.590

Reputation: 45 011

3

Jelly, 9 bytes

LḶN⁸ṙæ×W€

Try it online!

A function that returns a vertical array. As a full program it appears as if it returns a horizontal array. To return a horizontal array you'd do LḶN⁸ṙ×⁸S€ instead.

Erik the Outgolfer

Posted 2017-07-28T14:36:48.590

Reputation: 38 134

3

05AB1E, 11 bytes

DgGDÁ})ε*}O

Try it online!

Erik the Outgolfer

Posted 2017-07-28T14:36:48.590

Reputation: 38 134

2

Mathematica, 35 bytes

Most@FoldList[RotateRight,#,1^#].#&

Try it online!

-9 bytes from @Not a tree

J42161217

Posted 2017-07-28T14:36:48.590

Reputation: 15 931

2

It's shorter to use Mathematica's own matrix multiplication than to recreate it yourself: Most@FoldList[RotateRight,#,1^#].#&. (But nice trick using Fold instead of Nest!)

– Not a tree – 2017-07-28T23:52:16.013

2

R, 66 62 bytes

sapply(length(n<-scan()):1,function(i)c(n[-(1:i)],n[1:i])%*%n)

Try it online!

Leaky Nun

Posted 2017-07-28T14:36:48.590

Reputation: 45 011

using Map(function(i)c(n[-(1:i)],n[1:i])%*%n,length(n<-scan()):1) is 3 bytes shorter; it just returns a list of matrices. – Giuseppe – 2017-08-02T14:23:21.430

and a for loop for(i in seq(n<-scan()))F=c(c(n[-(1:i)],n[1:i])%*%n,F);F[1:i] is 61 bytes without returning a weird output format. – Giuseppe – 2017-08-02T14:45:49.213

2

Haskell, 49 bytes

f v=sum.zipWith(*)v.fst<$>zip(iterate tail$v++v)v

Try it online!

For an input v=[1,2]

  • iterate tail$v++v yields the list [[1,2,1,2],[2,1,2],[1,2],[2],[],...]
  • fst<$>zip l v is the same as take(length v)l and yields [[1,2,1,2],[2,1,2]]
  • sum.zipWith(*)v is mapped on each element and to yield the vector-matrix row product.

Laikoni

Posted 2017-07-28T14:36:48.590

Reputation: 23 676

A lot smarter than my answer! I like fst<$>zip l v very much. – jferard – 2017-07-28T19:55:57.150

1

CJam, 17 bytes

{__,,\fm>\f.*::+}

Try it online!

Erik the Outgolfer

Posted 2017-07-28T14:36:48.590

Reputation: 38 134

1

GolfScript, 37 bytes

{..,({.)\+}[*]{[1$\]zip{~*}%{+}*}%\;}

Try it online!

Erik the Outgolfer

Posted 2017-07-28T14:36:48.590

Reputation: 38 134

1

Python 3 + numpy, 68 bytes

lambda v:dot([roll(v,i)for i in range(len(v))],v)
from numpy import*

Try it online!

notjagan

Posted 2017-07-28T14:36:48.590

Reputation: 4 011

1

J, 14 bytes

+/ .*~#\.1&|.]

Try it online!

Explanation

+/ .*~#\.1&|.]  Input: array M
      #\.       Length of each suffix, forms the range [len(M), ..., 2, 1]
             ]  Identity, get M
         1&|.   For each 'x' in the suffix lengths, rotate left M  by 'x'
+/ .*~          Dot product with M

miles

Posted 2017-07-28T14:36:48.590

Reputation: 15 654

This is quite nice. One question. When you do 1&|. aren't you bonding 1 to |., creating a monad? but then you use that monad with both a left and right arg, with the left one determining how many times it's applied. What's going on here? – Jonah – 2017-07-28T19:32:24.390

@Jonah It's a special form for &. When used as u n&f v, it is performing (n&f)^:u v. See the bottom of bond to see more parses of it.

– miles – 2017-07-28T21:44:48.387

ah, TIL. is that something you use often? – Jonah – 2017-07-28T21:46:56.283

@Jonah It's useful for golfing in many cases. In this case, it could have been done in an equal number of bytes using rank #\.|."{], but I posted the shortest that I came up with first before trying alternatives. – miles – 2017-07-28T22:22:40.527

1

Haskell, 56 55 52 bytes

f l=[sum$zipWith(*)l$drop i$l++l|i<-[0..length l-1]]

Try it online!

Saved one byte thanks to @Laikoni

Saved three bytes: l++l instead of cycle l

jferard

Posted 2017-07-28T14:36:48.590

Reputation: 1 764

You can save a byte with zipWith(*)l$drop i$cycle l. – Laikoni – 2017-07-28T18:51:45.090

1

APL, 17 bytes

(↑¯1⌽(⍳≢)⌽¨⊂)+.×⍪

Explanation:

(↑¯1⌽(⍳≢)⌽¨⊂)+.×⍪

 ↑                      matrix format of
  ¯1⌽                   right rotate by 1 of
     (⍳≢)               the 1..[length N]
         ⌽¨             rotations of
           ⊂            the enclosed input
             +.×        inner product with
                ⍪       1-column matrix of input

marinus

Posted 2017-07-28T14:36:48.590

Reputation: 30 224

1

Octave - 67 48 bytes

Thanks to Luis Mendo for shaving this code down by 19 bytes!

Note: This code can only run in Octave. MATLAB does not support expressions inside functions that can create variables while simultaneously evaluating the expressions that create them.

n=numel(a=input(''));a(mod((x=0:n-1)-x',n)+1)*a'

The original code in MATLAB can be found here, but can be run in any version of MATLAB. This code is 67 bytes:

a=input('');n=numel(a)-1;a(mod(bsxfun(@minus,0:n,(0:n)'),n+1)+1)*a'

Explanation

  1. a=input(''); - Receives a (row) vector from the user through standard input. You must enter the vector in Octave form (i.e. [1,2,3]).
  2. n=numel(...); - Obtains the total number of elements in the input vector.
  3. x=0:n-1- Creates a row vector that increases from 0 up to n-1 in steps of 1.
  4. (x=0:n-1)-x' - Performs broadcasting so that we have a n x n matrix so that each row i are elements from 0 up to n-1 with each element in row i subtracted by i.
  5. mod(..., n)+1 - Ensures that any values that are negative wrap around to n so that each row i contains the vector from 0 up to n-1 circularly shifted to the left by i elements. We add 1 as MATLAB / Octave starts indexing vectors or matrices with 1.
  6. a(...) - Creates a n x n matrix where using (4), we access the correct indices of the input vector dictated by each value from (4) thus achieving the matrix we need.
  7. (...)*a' - Performs matrix vector multiplication by transposing / flipping a to become a column vector prior to doing the multiplication.

Example Runs

>> n=numel(a=input(''));a(mod((x=0:n-1)-x',n)+1)*a'
[1,2,3]

ans =

         14.00
         11.00
         11.00

>> n=numel(a=input(''));a(mod((x=0:n-1)-x',n)+1)*a'
[2,5,8,3]

ans =

        102.00
         80.00
         62.00
         80.00

Try it online!

rayryeng - Reinstate Monica

Posted 2017-07-28T14:36:48.590

Reputation: 1 521

You can use implicit expansion instead of bsxfun. Defining n without -1 saves a few bytes too. And if you restrict to Octave you can assign a and 0:n to variables on the fly and save some more. Also, come here more often!! :-D

– Luis Mendo – 2017-07-29T15:48:09.247

@LuisMendo ah yes. I forget Octave has implicit expansion already supported. Also saving the variable inside the input function is a great trick. I didn't think it could support that. I've seen it only in C or C++ from my own experience. Thanks! – rayryeng - Reinstate Monica – 2017-07-29T21:49:48.857

1@LuisMendo I'll place your suggested changes as an edit soon. I have been busy, but I haven't made this a priority as this entry will surely never win in byte count. – rayryeng - Reinstate Monica – 2017-07-30T08:10:37.210

@LuisMendo Changed. Thank you very much :) Got to understand the code as I was changing my explanation above. – rayryeng - Reinstate Monica – 2017-07-30T13:12:14.970

Glad I could help :-) – Luis Mendo – 2017-07-30T15:04:46.723

1

Octave, 34 bytes

@(a)a*toeplitz(a,shift(flip(a),1))

Try it online!

alephalpha

Posted 2017-07-28T14:36:48.590

Reputation: 23 988

1

Husk, 11 bytes

mΣ§‡*´ṀKoṫ¢

Try it online!

Explanation

mΣ§‡*´ṀKoṫ¢  Implicit input, e.g. [1,2,3]
          ¢  Cycle: [1,2,3,1,2,3,...
        oṫ   Tails: [[1,2,3,1,2,3...],[2,3,1,2,3...],[3,1,2,3...]...
     ´ṀK     Replace each element of input with input: [[1,2,3],[1,2,3],[1,2,3]]
   ‡*        Vectorized multiplication (truncated with respect to shortest list)
  §          applied to the last two results: [[1,4,9],[2,6,3],[3,2,6]]
mΣ           Sum of each row: [14,11,11]

Zgarb

Posted 2017-07-28T14:36:48.590

Reputation: 39 083

0

Javascript 79 bytes

Takes in an input array and outputs an array of the matrix vector

a=>(b=[...a],a.map(x=>([...b].reduce((m,n,i)=>m+=n*a[i],0,b.push(b.shift())))))

Explanation

a=>(
    b=[...a],                    // copy the input into b
    a.map(x=>(                   // transform a into a new array
        [...b].reduce(           // copy b into a new array and reduce
            (m,n,i)=>m+=n*a[i],  // memo += the element in the array * the ith
                                 // element in a
            0,                   // start memo at 0
            b.push(b.shift())    // shift the first element in b to the end
                                 // not used by reduce, but performing this op
                                 // here saves a few bytes
        )
    ))
)

asgallant

Posted 2017-07-28T14:36:48.590

Reputation: 309

0

Clojure, 80 bytes

#(map(fn[_ c](apply +(map * c %)))%(iterate(fn[c](into[(last c)](butlast c)))%))

iterate produces an infinite sequence, but instead of using (take (count %) (iterate ...)) to stop it I use % as an extra argument to map.

NikoNyrh

Posted 2017-07-28T14:36:48.590

Reputation: 2 361

0

Perl 5, 65 + 1 (-a) = 66 bytes

@o=@F;for(@o){$r=0;$r+=$_*$F[$i++%@F]for@o;say$r;unshift@F,pop@F}

Try it online!

Takes the input vector as space separated numbers. Outputs linefeed separated numbers representing the result vector.

Xcali

Posted 2017-07-28T14:36:48.590

Reputation: 7 671

0

C (gcc), 126 bytes

i,j;int*f(int*a,int n){int*r=malloc(n*sizeof(int));for(i=0;i<n;i++){r[i]=0;for(j=0;j<n;j++)r[i]+=a[j]*a[(j-i+n)%n];}return r;}

Try it online!

An array may be represented in input as a pointer and length.

Leaky Nun

Posted 2017-07-28T14:36:48.590

Reputation: 45 011

0

Common Lisp, 78 bytes

(lambda(x)(loop as i on(append x x)as y in x collect(reduce'+(mapcar'* i x))))

Try it online!

Double the array (in this case a Lisp list) and iterate over the sublists with i (using x, through y, to stop the iteration). Then calculate the next element of the result by summing the result of multiplying each element of x with each element of i (again stopping when the shorter list is terminated).

Renzo

Posted 2017-07-28T14:36:48.590

Reputation: 2 260