Rotation summation

26

3

Take a square matrix containing positive integers as input, and calculate the "rotated sum" of the matrix.

Rotated sum:

Take the sum of the original matrix and the same matrix rotated 90, 180 and 270 degrees.

Suppose the matrix is:

 2    5    8
 3   12    8
 6    6   10

then the rotated sum will be:

2    5    8     8    8   10    10    6    6     6    3    2
3   12    8  +  5   12    6  +  8   12    3  +  6   12    5  = 
6    6   10     2    3    6     8    5    2    10    8    8   

26   22   26
22   48   22
26   22   26

Test cases:

Input and output separated by dashes, different test cases separated by a newline. Test cases in more convenient formats can be found here.

1
-------------
4

1 3
2 4
-------------
10   10 
10   10    

14    6    7   14
 6   12   13   13
 6    2    3   10
 5    1   12   12
-------------
45   37   24   45
24   30   30   37
37   30   30   24
45   24   37   45    

14    2    5   10    2
18    9   12    1    9
 3    1    5   11   14
13   20    7   19   12
 2    1    9    5    6
-------------
24   29   31   41   24
41   49   31   49   29
31   31   20   31   31
29   49   31   49   41
24   41   31   29   24

Shortest code in bytes in each language wins. Explanations are highly encouraged!

Stewie Griffin

Posted 2018-01-20T10:18:19.480

Reputation: 43 471

Answers

9

Python 2, 78 bytes

Thanks to Dennis for golfing two bytes off my previous recursive approach.

f=lambda*l:l[3:]and[map(sum,zip(*d))for d in zip(*l)]or f(zip(*l[0][::-1]),*l)

Try it online! or See a test suite.


Python 2, 80 81 83 85 bytes (non-recursive)

Takes input as a singleton list.

l=input()
exec"l+=zip(*l[-1][::-1]),;"*3
print[map(sum,zip(*d))for d in zip(*l)]

Try it online!

Code functionality

Since this is quite length-ish to analyse it as a whole, let's check it out piece-by-piece:

f = lambda *l:                # This defines a lambda-function that can accept any number
                              # of arguments (the matrix) using starred expressions.
l[3:] and ...X... or ...Y...  # If l[3:] is truthy (that is, the length of the list is
                              # higher than 3), return X, otherwise Y.

[map(sum,zip(*d))for d in zip(*l)]     # The first expression, X.
[                                ]     # Start a list comprehension, that:
                 for d in              # ... Iterates using a variable d on:
                          zip(*l)      # ... The "input", l, transposed.
         zip(*d)                       # ... And for each d, transpose it...
 map(sum,       )                      # ... And compute the sum of its rows.
                                       # The last two steps sum the columns of d.

f(zip(*l[0][::-1]),*l)     # The second expression, Y. This is where the magic happens.
f(                   )     # Call the function, f with the following arguments:
  zip(*          )         # ... The transpose of:
       l[0][::-1]          # ...... The first element of l (the first arg.), reversed.
                  ,        # And:
                   *l      # ... l splatted. Basically turns each element of l
                           # into a separate argument to the function.

And for the second program:

l=input()                                # Take input and assign it to a variable l.
                                         # Note that input is taken as a singleton list.

exec"l+=zip(*l[-1][::-1]),;"*3           # Part 1. Create the list of rotations.
exec"                     ;"*3           # Execute (Do) the following 3 times:
     l+=                 ,               # ... Append to l the singleton tuple:
        zip(*           )                # ...... The transpose of:
             l[-1][::-1]                 # ......... The last element of l, reversed.

print[map(sum,zip(*d))for d in zip(*l)]  # Part 2. Generate the matrix of sums.
print                                    # Output the result of this expression:
     [                for d in        ]  # Create a list comprehension, that iterates
                                         # with a variable called "d" over:
                               zip(*l)   # ... The transpose of l.
      map(sum,       )                   # ... And computes the sum:
              zip(*d)                    # ... Of each row in d's transpose.
                                         # The last 2 steps generate the column sums.

TL;DR: Generate the list of matrices needed by rotating the input 3 times by 90-degrees and collecting the results. Then, get the sums of the columns of each matrix in the result's transpose.

Mr. Xcoder

Posted 2018-01-20T10:18:19.480

Reputation: 39 774

f=lambda*l:l[3:]and[map(sum,zip(*d))for d in zip(*l)]or f(zip(*l[0][::-1]),*l) saves two bytes with "normal" input. Try it online! – Dennis – 2018-01-20T13:21:59.677

@Dennis Thank you! I thought lambda*l wasn't possible in Python 2 for some reason. – Mr. Xcoder – 2018-01-20T13:25:21.780

You can't do x,*y=1,2,3 in Python 2.7 or [*x] in Python 3.4, but starred expressions can be used for function arguments even in Python 1.6. Try it online!

– Dennis – 2018-01-20T13:31:20.153

8

Octave, 29 bytes

@(x)(y=x+rot90(x))+rot90(y,2)

Try it online!

Explanation

This adds the input matrix with a 90-degree rotated version of itself. The result is then added with a 180-degree rotated version of itself.

Luis Mendo

Posted 2018-01-20T10:18:19.480

Reputation: 87 464

5

Clean, 110 bytes

import StdEnv,StdLib
r=reverse
t=transpose
z=zipWith(+)
$m=[z(z(r b)a)(z(r c)d)\\a<-m&b<-r m&c<-t m&d<-r(t m)]

Try it online!

From the matricies:

  • X = transpose(reverse M): 90-degree rotation
  • Y = reverse(map reverse M): 180-degree rotation
  • Z = reverse(transpose M): 270-degree rotation

This zips the addition operator over M and X, as well as Y and Z, and then over the results.

Οurous

Posted 2018-01-20T10:18:19.480

Reputation: 7 916

5

Wolfram Language (Mathematica), 28 bytes

Sum[a=Reverse@a,{a=#;4}]&

is \[Transpose].

Try it online!

alephalpha

Posted 2018-01-20T10:18:19.480

Reputation: 23 988

Nice solution. I tried ReplacePart[#,{a_,b_}:>Tr@Extract[#,{{a,b},{b,-a},{-a,-b},{-b,a}}]]& and also Plus@@NestList[Reverse@#&,#,3]& – Kelly Lowder – 2018-01-21T03:16:40.540

5

Julia 0.6, 28 24 bytes

~A=sum(rotr90.([A],0:3))

Try it online!

~A=sum(rotr90.([A],0:3)) #
~                        # redefine unary operator ~
 A                       # function argument
               [A]       # put input matrix A into a list with one element
                   0:3   # integer range from 0 to 3
       rotr90.(   ,   )  # apply function rotr90 elementwise, expand singleton dimensions
       rotr90.([A],0:3)  # yields list of rotated matrices:
                         # [rotr90(A,0), rotr90(A,1), rotr90(A,2), rotr90(A,3)]
  sum(                )  # sum

LukeS

Posted 2018-01-20T10:18:19.480

Reputation: 421

1It is worth perhaps noting that to do the [1] example on should do ~reshape([1], (1,1)) because that is how a 1x1 matrix is declared in julia 0.6. – Lyndon White – 2018-01-21T13:09:25.077

5

Julia 0.6, 29 bytes

x*y=rotr90(y,x)
!x=x+1x+2x+3x

Try it online!

I couldn't get below LukeS's solution

But in trying I did come up with this, which I think is kinda cute.

First we redefine multiplication to be the rotate operation, where there first time is the number of times to rotate. So since julia multipes by juxtaposition then: 1x becomes rotr90(x,1) and 3x becomes rotr90(x,3) etc.

Then we write out the sum.

Lyndon White

Posted 2018-01-20T10:18:19.480

Reputation: 1 021

4

Jelly, 7 bytes

ZU+µUṚ+

Try it online!

Leaky Nun

Posted 2018-01-20T10:18:19.480

Reputation: 45 011

4

Octave, 33 bytes

@(a)a+(r=@rot90)(a)+r(a,2)+r(a,3)

Try it online!

Explanation:

(r=@rot90) in an inline way of creating a function handle r used to rotate the matrix 90 degrees. If a second argument, k is given to r then it will rotate the matrix k*90 degrees. So this is equivalent to the pseudo code:

a + rot90(a) + rot180(a) + rot270(a)

Stewie Griffin

Posted 2018-01-20T10:18:19.480

Reputation: 43 471

4

MATL, 9 bytes

i3:"G@X!+

Try it at MATL Online

Explanation

i       # Explicitly grab the input matrix
3:"     # Loop through the values [1, 2, 3], and for each value, N:
  G     # Grab the input again
  @X!   # Rotate the value by 90 degrees N times
  +     # Add it to the previous value on the stack
        # Implicitly end the for loop and display the resulting matrix

Suever

Posted 2018-01-20T10:18:19.480

Reputation: 10 257

3

Pyth, 13 bytes

m+MCdC.u_CN3Q

Try it online!

Leaky Nun

Posted 2018-01-20T10:18:19.480

Reputation: 45 011

3

J, 16 15 bytes

[:+/|.@|:^:(<4)

Try it online!

FrownyFrog

Posted 2018-01-20T10:18:19.480

Reputation: 3 112

1This is a perfect challenge for ^:. Clever solution! – cole – 2018-01-20T18:15:24.487

That's an elegant solution! – Galen Ivanov – 2018-01-20T18:24:27.170

3

MATL, 7 bytes

,t@QX!+

Try it at MATL Online!

Explanation

Port of my Octave answer.

,        % Do twice
  t      %   Duplicate. Takes input (implicit) the first time
  @Q     %   Push 1 in the first iteration, and 2 in the second
  X!     %   Rotate by that many 90-degree steps
  +      %   Add
         % End (implicit). Display (implicit)

Luis Mendo

Posted 2018-01-20T10:18:19.480

Reputation: 87 464

3

R, 69 64 bytes

function(x,a=function(y)apply(y,1,rev))x+a(x)+a(a(x))+a(a(a(x)))

Try it online!


Attempt number three at codegolf. From 69 to 64 bytes thanks to Giuseppe!

Florian

Posted 2018-01-20T10:18:19.480

Reputation: 201

Moving a to a function argument will save bytes by allowing you to get rid of the {} around the function body. Also, porting Luis Mendo's Octave approach might save some bytes? Finally, I'm not 100% sure but is t(apply(x,2,rev)) equivalent to apply(x,1,rev)? – Giuseppe – 2018-01-21T13:22:08.993

Thanks, I was able to improve with tip #1 and #3. I did not succeed in saving bytes by adding an argument n to a() to repeat the operation though. – Florian – 2018-01-21T14:02:38.503

1

I meant something like this

– Giuseppe – 2018-01-21T16:49:53.827

3

APL (Dyalog Classic), 8 bytes

(⌽+⍉)⊖+⌽

Try it online!

ngn

Posted 2018-01-20T10:18:19.480

Reputation: 11 449

2

Jelly, 7 bytes

ṚZ$3СS

Try it online!

Saved 1 byte thanks to Erik the Outgolfer (also thanks to a suggestion for fixing a bug).

How?

ṚZ$3СS || Full program (monadic).

   3С  || Do this 3 times and collect results in a list
  $     || –> Apply the last two links as a monad
Ṛ       || –––> Reverse,
 Z      || –––> Transpose.
      S || Summation.

Mr. Xcoder

Posted 2018-01-20T10:18:19.480

Reputation: 39 774

2

Pari/GP, 31 bytes

a->sum(i=1,4,a=Mat(Vecrev(a))~)

Try it online!

alephalpha

Posted 2018-01-20T10:18:19.480

Reputation: 23 988

2

JavaScript (ES6), 77 bytes

a=>a.map((b,i)=>b.map((c,j)=>c+a[j][c=l+~i]+a[c][c=l+~j]+a[c][i]),l=a.length)

Neil

Posted 2018-01-20T10:18:19.480

Reputation: 95 035

2

Python 2, 76 bytes

f=lambda x,k=-2:k*x or[map(sum,zip(*r))for r in zip(x,f(zip(*x)[::-1],k+1))]

Try it online!

Dennis

Posted 2018-01-20T10:18:19.480

Reputation: 196 637

2

APL (Dyalog Classic), 17 bytes

{⍵+⌽∘⍉⍵+⌽∘⊖⍵+⍉⌽⍵}

Try it online!

APL NARS 34bytes 2117 chars

{⍵+⌽∘⍉⍵+⌽∘⊖⍵+⍉⌽⍵}

-2 chars thanks to ngn

-2 chars because operator composite ∘ seems to have precedence on +

it seems ⌽⍉a rotate a from 90°,⌽⊖a rotate a from 180°,⌽⍉⌽⊖a rotate a from 270° as ⍉⌽

If exist the operator p as:

∇r←(g p)n;a;i;k
   a←⌽,n⋄r←⍬⋄i←0⋄k←⍴a⋄→C
A: →B×⍳r≡⍬⋄r←g¨r
B: r←r,⊂i⊃a
C: →A×⍳k≥i+←1
   r←⌽r
∇

The operator p above would be such that if g is a 1 argument function (monadic?) it should be:

"g f a a a a" is "a ga gga ggga"

the solution would be pheraps 15 chars

  g←{⊃+/⌽∘⍉ p 4⍴⊂⍵}
  a←2 2⍴1 3 2 4
  g a
10 10 
10 10 
  g 1
4

But could be better one operator "composed n time" d such that "3 d f w" is f(f(f(w))).

Now I wrote something but it is too much fragile without the need type checking.

But i like more the operator q that repeat compose of f with argument m (it is not complete because the error cases of the types are not written)

∇r←(n q f)m;i;k;l
   r←⍬⋄k←⍴,n⋄→A×⍳k≤1⋄i←0⋄→D
C: r←r,⊂(i⊃n)q f m
D: →C×⍳k≥i+←1
   →0
A: l←n⋄r←m⋄→0×⍳n≤0
B: l-←1⋄r←f r⋄→B×⍳l≥1
∇

the solution would be 17 chars but i prefer it

  g←{⊃+/(0..3)q(⌽⍉)⍵}
  ⎕fmt g a
┌2─────┐
2 10 10│
│ 10 10│
└~─────┘
  ⎕fmt g 1
4
~

RosLuP

Posted 2018-01-20T10:18:19.480

Reputation: 3 036

270 could be just ⍉⌽ and the whole thing is suitable for a train

– ngn – 2018-01-21T16:02:19.703

If exist one f such that g f w w w w is w gw ggw gggw the answer would be +/⌽⍉f 4/rho w – RosLuP – 2018-01-22T10:02:36.057

You mean +/⌽∘⍉f 4⍴⊂⍵? To get four copies of , first you should enclose it with . To have ⌽⍉ as an operand to f, you must compose it into a single function like this: ⌽∘⍉. The mysterious f could be scan (backslash), but there's another detail to take care of - ⌽∘⍉ will get a left argument, so we must make it ignores it: +/{⌽⍉⍵}\4⍴⊂⍵ or +/⊢∘⌽∘⍉\4⍴⊂⍵. – ngn – 2018-01-22T13:47:54.363

In my first comment I was suggesting this train: ⊢ + ⌽∘⍉ + ⌽∘⊖ + ⍉∘⌽. That can lead to even shorter solutions if you rearrange the squiggles cleverly and make good use of trains.

– ngn – 2018-01-22T13:49:17.227

@ngn even a simple {⍵+ ⍺ }\1 2 3 4 return domain error – RosLuP – 2018-01-23T08:19:12.523

@ngn even a simple {⍵+ ⍺ }\1 2 3 4 return domain error... For me could be ok the function +/ {⍺,⌽⍉⍵}\a a a a or f<-,⌽⍉; +/f\a a a a, where a is the matrix – RosLuP – 2018-01-23T08:25:25.130

2

Ruby, 74 72 66 bytes

->a{r=0...a.size;r.map{|i|r.map{|j|(0..3).sum{i,j=j,~i;a[i][j]}}}}

Try it online!

This works on an element-by-element basis, finding the associated elements mathematically, instead of rotating the array. The key part is i,j=j,~i, which turns (i, j) clockwise 90 degrees.

-2 bytes thanks to Mr. Xcoder

-6 bytes because of sum

MegaTom

Posted 2018-01-20T10:18:19.480

Reputation: 3 787

2

K4 / K (oK), 23 8 bytes

Solution:

+/(|+:)\

Try it online!

Example:

+/(|+:)\5 5#14 2 5 10 2 18 9 12 1 9 3 1 5 11 14 13 20 7 19 12 2 1 9 5 6
24 29 31 41 24
41 49 31 49 29
31 31 20 31 31
29 49 31 49 41
24 41 31 29 24

Explanation:

Thanks to ngn for the simplified transformation technique.

+/(|+:)\ / the solution
       \ / converge
  (   )  / function to converge
    +:   / flip
   |     / reverse
+/       / sum over the result

Extra:

In Q this could be written as

sum (reverse flip @) scan

streetster

Posted 2018-01-20T10:18:19.480

Reputation: 3 635

+/{|+x}\ – ngn – 2018-01-23T03:13:09.803

I knew there was a better way to apply the transformations! – streetster – 2018-01-23T07:39:29.547

+/(|+:)\ https://tio.run/##y9bNz/7/X1tfo0bbSjPGWMFY2UjBVMFCwVjB0AhImQGhocH//wA is sadly the same count... Gah cannot figure out markup on mobile.

– streetster – 2018-01-23T07:43:15.177

It seems markup in comments has a bug, not only on mobile - backslash before backquote messes things up. I avoided it by inserting a space. – ngn – 2018-01-23T12:25:04.940

1

Python 3, 105 102 bytes

3 bytes thanks to Mr. Xcoder.

def f(a):l=len(a)-1;r=range(l+1);return[[a[i][j]+a[l-j][i]+a[l-i][l-j]+a[j][l-i]for j in r]for i in r]

Try it online!

Leaky Nun

Posted 2018-01-20T10:18:19.480

Reputation: 45 011

1

Ruby 89 79 bytes

-10 bytes thanks to Unihedron

->m{n=m;3.times{n=n.zip(m=m.transpose.reverse).map{|i,j|i.zip(j).map &:sum}};n}

Try it online!

Asone Tuhid

Posted 2018-01-20T10:18:19.480

Reputation: 1 944

1I'm pretty sure you can replace .map &:dup with *1 to cut off a lot of characters. array*length creates a new array and is a handy way to shallow clone. – Unihedron – 2018-01-20T13:35:42.770

Actually, n=*m is even shorter. – Unihedron – 2018-01-20T13:41:06.780

@Unihedron that's the problem, I need to deep clone – Asone Tuhid – 2018-01-20T14:17:17.070

Seems to me that it doesn't affect the output; I fiddled with it in your "try it online" link and the output appears to remain correct with that change – Unihedron – 2018-01-20T14:31:48.403

You're right, actually you don't even need a shallow clone, transpose takes care of that – Asone Tuhid – 2018-01-20T15:36:30.457

1

Haskell, 84 83 67 bytes

z=zipWith
e=[]:e
f l=foldr(\_->z(z(+))l.foldr(z(:).reverse)e)l"123"

Try it online!

Thanks to Laikoni and totallyhuman for saving a lot of bytes!

Cristian Lupascu

Posted 2018-01-20T10:18:19.480

Reputation: 8 369

83 bytes. – totallyhuman – 2018-01-20T14:54:45.210

@totallyhuman That's clever! Thanks! – Cristian Lupascu – 2018-01-20T15:00:56.063

67 bytes: Try it online!

– Laikoni – 2018-01-21T07:12:49.583

1

05AB1E, 12 bytes

3FÂø}3F‚øε`+

Try it online!

Erik the Outgolfer

Posted 2018-01-20T10:18:19.480

Reputation: 38 134

1

Husk, 9 bytes

F‡+↑4¡(↔T

Try it online!

Explanation

F‡+↑4¡(↔T)  -- implicit input M, for example: [[1,0,1],[2,3,4],[0,0,2]]
     ¡(  )  -- repeat infinitely times starting with M  
        T   -- | transpose: [[1,2,0],[0,3,0],[1,4,2]]
       ↔    -- | reverse: [[1,4,2],[0,3,0],[1,2,0]]
            -- : [[[1,0,1],[2,3,4],[0,0,2]],[[1,4,2],[0,3,0],[1,2,0]],[[2,0,0],[4,3,2],[1,0,1]],[[0,2,1],[0,3,0],[2,4,1]],[[1,0,1],[2,3,4],[0,0,2]],…
   ↑4       -- take 4: [[[1,0,1],[2,3,4],[0,0,2]],[[1,4,2],[0,3,0],[1,2,0]],[[2,0,0],[4,3,2],[1,0,1]],[[0,2,1],[0,3,0],[2,4,1]]]
F           -- fold (reduce) the elements (example with [[1,0,1],[2,3,4],[0,0,2]] [[1,4,2],[0,3,0],[1,2,0]])
 ‡+         -- | deep-zip addition (elementwise addition): [[2,4,3],[2,6,4],[1,2,2]]
            -- : [[4,6,4],[6,12,6],[4,6,4]]

ბიმო

Posted 2018-01-20T10:18:19.480

Reputation: 15 345

1

tinylisp, 132 bytes

Let's take the recently added library function transpose for a spin!

(load library
(d T transpose
(d R(q((m #)(i #(c m(R(reverse(T m))(dec #)))(
(q((m)(foldl(q(p(map(q((r)(map sum(T r))))(T p))))(R m 4

The last line is an unnamed lambda function that performs rotation summation. To actually use it, you'll want to use d to bind it to a name. Try it online!

Ungolfed, with comments

(load library) (comment Get functions from the standard library)

(comment Rotating a matrix by 90 degrees is just transpose + reverse)
(def rotate
 (lambda (matrix)
  (reverse (transpose matrix))))

(comment This function recursively generates a list of (count) successive rotations
          of (matrix))
(def rotations
 (lambda (matrix count)
  (if count
   (cons matrix
    (rotations (rotate matrix) (dec count)))
   nil)))

(comment To add two matrices, we zip them together and add the pairs of rows)
(def matrix-add
 (lambda two-matrices
  (map row-sum (transpose two-matrices))))

(comment To add two rows of a matrix, we zip them together and add the pairs of numbers)
(def row-sum
 (lambda (two-rows)
  (map sum (transpose two-rows))))

(comment Our final function: generate a list containing four rotations of the argument
          and fold them using matrix-add)
(def rotated-sum
 (lambda (matrix)
  (foldl matrix-add (rotations matrix 4))))

DLosc

Posted 2018-01-20T10:18:19.480

Reputation: 21 213

1

Attache, 20 bytes

Sum@MatrixRotate&0:3

Try it online!

Explanation

Sum@MatrixRotate&0:3

MatrixRotate&0:3 expands to, with input x, MatrixRotate[x, 0:3], which in turn exapnds to [MatrixRotate[x, 0], MatrixRotate[x, 1], MatrixRotate[x, 2], MatrixRotate[x, 3]]. That is to say, it vectorizes over the RHS. Then, Sum takes the sum of all of these matrices by one level. This gives the desired result.

Conor O'Brien

Posted 2018-01-20T10:18:19.480

Reputation: 36 228

1

Java 8, 135 133 bytes

a->{int l=a.length,r[][]=new int[l][l],i=0,j;for(;i<l;i++)for(j=0;j<l;)r[i][j]=a[i][j]+a[j][l+~i]+a[l+~i][l-++j]+a[l-j][i];return r;}

-2 bytes thanks to @ceilingcat.

Explanation:

Try it online.

a->{                        // Method with integer-matrix as both parameter and return-type
  int l=a.length,           //  Dimensions of the input-matrix
      r[][]=new int[l][l],  //  Result-matrix of same size
      i=0,j;                //  Index-integers
  for(;i<l;i++)             //  Loop over the rows
    for(j=0;j<l;)           //   Loop over the columns
      r[i][j]=              //    Set the cell of the result-matrix to:
              a[i][j]+a[j][l+~i]+a[l+~i][l-++j]+a[l-j][i];
                            //     The four linked cells of the input-matrix
  return r;}                //  Return the result-matrix

Kevin Cruijssen

Posted 2018-01-20T10:18:19.480

Reputation: 67 575