Subtract the Folded Matrix

21

Challenge:

Given an NxN matrix where \$N\geq2\$ and one of eight distinct 'folding options', output a 2D array/list with the subtracted values.

The eight folding options are: left-to-right; right-to-left; top-to-bottom; bottom-to-top; topleft-to-bottomright; topright-to-bottomleft; bottomleft-to-topright; bottomright-to-topleft.

Step by step examples:

Input matrix:

[[ 1, 3, 5, 7],
 [ 0, 8, 6, 4],
 [ 1, 1, 1, 1],  (a'th row in the explanation below)
 [ 1,25, 0,75]]

With folding option top-to-bottom we output the following as result:

[[ 1,-7,-5,-3],
 [ 0,22,-5,68]]

Why? We fold from the top to the bottom. Since the matrix dimensions are even, we don't have a middle layer to preserve as is. The \$a\$'th row [1, 1, 1, 1] will be subtracted by the \$(a-1)\$'th row (would have been \$(a-2)\$'th row for odd dimension matrices); so [1-0, 1-8, 1-6, 1-4] becomes [1, -7, -5, -3]. The \$(a+1)\$'th row [1, 25, 0, 75] will then be subtracted by the \$(a-2)\$'th row (would have been \$(a-3)\$'th row for odd dimension matrices); so [1-1, 25-3, 0-5, 75-7] becomes [0, 22, -5, 68].

With folding option bottomright-to-topleft instead (with the same input-matrix above) we output the following as result:

[[-74,  2,  1,  7],
 [  0,  7,  6],
 [-24,  1],
 [  1]]

With the following folding subtractions:

[[1-75,  3-1,  5-4,    7],
 [ 0-0,  8-1,    6],
 [1-25,    1],
 [   1]]

Challenge rules:

  • You can use any eight distinct letters [A-Za-z] or distinct numbers in the range \$[-99,99]\$ for the folding options. Numbers \$[1..8]\$ or \$[0..7]\$ are probably the most common options, but if you want to use different numbers within the range for some smart calculations, feel free to do so. Please state which folding options you've used in your answer.
  • The input-matrix will always be a square NxN matrix, so you don't have to handle any rectangular NxM matrices. \$N\$ will also always be at least 2, since an empty or 1x1 matrix cannot be folded.
  • The input of the matrix will always contain non-negative numbers in the range \$[0, 999]\$ (the numbers in the output will therefore be in the range \$[-999, 999]\$).
  • With the (anti-)diagonal folding or odd-dimension vertical/horizontal folding, the middle 'layer' will remain unchanged.
  • I/O is flexible. Can be a 2D array/list of integers; can be returned or printed as a space-and-newline delimited string; you can modify the input-matrix and replace the numbers that should be gone with null or a number outside of the [-999, 999] range to indicate they're gone; etc. etc.

General rules:

  • This is , so shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer with default I/O rules, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters and return-type, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code (i.e. TIO).
  • Also, adding an explanation for your answer is highly recommended.

Test cases:

Input-matrix 1:

Input-matrix (for the following eight test cases):
[[ 1, 3, 5, 7],
 [ 0, 8, 6, 4],
 [ 1, 1, 1, 1],
 [ 1,25, 0,75]]

Input-folding option: left-to-right
Output: [[2,6],[-2,4],[0,0],[-25,74]]

Input-folding option: right-to-left
Output: [[-6,-2],[-4,2],[0,0],[-74,25]]

Input-folding option: top-to-bottom
Output: [[1,-7,-5,-3],[0,22,-5,68]]

Input-folding option: bottom-to-top
Output: [[0,-22,5,-68],[-1,7,5,3]]

Input-folding option: topleft-to-bottomright
Output: [[7],[6,-1],[1,-7,-2],[1,24,0,74]]

Input-folding option: topright-to-bottomleft
Output: [[1],[-3,8],[-4,-5,1],[-6,21,-1,75]]

Input-folding option: bottomleft-to-topright
Output: [[1,3,4,6],[8,5,-21],[1,1],[75]]

Input-folding option: bottomright-to-topleft
Output: [[-74,2,1,7],[0,7,6],[-24,1],[1]]

Input-matrix 2:

Input-matrix (for the following eight test cases):
[[17, 4, 3],
 [ 8, 1,11],
 [11, 9, 7]]

Input-folding option: left-to-right
Output: [[4,-14],[1,3],[9,-4]]

Input-folding option: right-to-left
Output: [[14,4],[-3,1],[4,9]]

Input-folding option: top-to-bottom
Output: [[8,1,11],[-6,5,4]]

Input-folding option: bottom-to-top
Output: [[6,-5,-4],[8,1,11]]

Input-folding option: topleft-to-bottomright
Output: [[3],[1,7],[11,1,-10]]

Input-folding option: topright-to-bottomleft
Output: [[17],[4,1],[8,-2,7]]

Input-folding option: bottomleft-to-topright
Output: [[17,-4,-8],[1,2],[7]]

Input-folding option: bottomright-to-topleft
Output: [[10,-7,3],[-1,1],[11]]

Kevin Cruijssen

Posted 2019-06-17T11:24:16.880

Reputation: 67 575

Does the order of the folding options matter? – Expired Data – 2019-06-17T14:12:41.787

Also, can we just output the 8xNxN matrix of all possible folds? – Expired Data – 2019-06-17T14:19:55.160

Shouldn't this test sample Input-folding option: bottom-to-top Output: [[-1,7,5,3],[0,-22,5,-68]] be flipped? – OrangeCherries – 2019-06-17T14:33:20.023

also for matrix 2, 17-11 is 6, not 4? – OrangeCherries – 2019-06-17T14:52:15.957

@ExpiredData As specified in the rules, you can use any letter A-Za-z or any integer in the range [-999,999], so order doesn't matter. And sorry, but you must output the correct fold based on the input, so outputting all eight isn't allowed. – Kevin Cruijssen – 2019-06-17T16:41:26.967

@OrangeCherries You're indeed right. Both are fixed, thanks for noticing! – Kevin Cruijssen – 2019-06-17T16:44:10.317

@Arnauld Ah, similar as the one mentioned by OrangeCherries, but then top-to-bottom instead of bottom-to-top. Thanks, fixed. – Kevin Cruijssen – 2019-06-18T12:20:13.473

Answers

5

Octave, 256 248 244 248 bytes

m=d=x=@(a,b=1)rot90(a,b)
y=@(a,b=2)flip(a,b)
z=@(a,b=1)tril(a+1e3,-1)+a-x(y(tril(a)))+b*diag(diag(a))
f=@(a,b){m=((a-y(a))(:,1:(d=size(a,2)/2))),-y(m),m=y(x((a=x(a))-y(a)))(d+1:end,:),y(m,1),-y(z(a,-1)),x(z(x(a,2)),2),z(a=x(a,3)),x(z(x(a,2)),2)}{b}

Try it online!

-2 bytes (and a bity of tidying up) thanks to Luis Mendo

+2 bytes due to the correction for T-B

1-Indexed operations for values of b from 1-8:

R-L
L-R
B-T
T-B
BR-TL
TR-BL
BL-TR
TL-BR

This gave me a headache, I'll golf it properly later

Expired Data

Posted 2019-06-17T11:24:16.880

Reputation: 3 129

Suggest rows(a) instead of size(a,2) – ceilingcat – 2019-10-15T21:49:23.503

5

Jelly,  39  34 bytes

There is possibly further golfing possible by combining some of the two "functions".
...yep: -5 thanks to NickKennedy!

ṃ“Z“Ṛ“U“ “ŒDṙL ZZṚ”ŒḄFḲj“ŒH_Ṛ}¥/”v

Try it online!

A dyadic link accepting an integer (the instruction) and a list of lists of numbers (the matrix).

Uses the option to take the instruction as an integer in \$[-99,99]\$ to our advantage, and hence has the following seemingly bizarre mapping:

           Instruction  |  integer
------------------------+---------
         left-to-right  |     4
         right-to-left  |    14
         top-to-bottom  |     9
         bottom-to-top  |    39
topleft-to-bottomright  |    65
topright-to-bottomleft  |    15
bottomleft-to-topright  |    10
bottomright-to-topleft  |     0

How?

The link creates Jelly code which is then evaluated using M as an input...

ṃ“Z“Ṛ“U“ “ŒDṙL ZZṚ”ŒḄFḲj“ŒH_Ṛ}¥/”v - Link: integer, I; matrix, M
 “Z“Ṛ“U“ “ŒDṙL ZZṚ”                - list of lists of characters = ["Z", "Ṛ", "U", " ", "ŒDṙL ZZṚ"]
ṃ                                  - base decompress (I) using those lists as the digits
                                   -  ...i.e. convert to base 5 and then convert the digits:
                                   -          [1,2,3,4,0] -> ["Z", "Ṛ", "U", " ", "ŒDṙL ZZṚ"]
                   ŒḄ              - bounce
                                   -  ...e.g. [a, b, c] -> [a, b, c, b, a]
                     F             - flatten to a list of characters
                      Ḳ            - split at spaces
                       j           - join with:
                        “ŒH_Ṛ}¥/”  -   list of characters = "ŒH_Ṛ}¥/"
                                 v - evaluate as Jelly code with an input of M

Each of the eight options are then:

left-to-right           (4): ŒH_Ṛ}¥/
right-to-left          (14): ṚŒH_Ṛ}¥/Ṛ
top-to-bottom           (9): ZŒH_Ṛ}¥/Z
bottom-to-top          (39): ZṚŒH_Ṛ}¥/ṚZ
topleft-to-bottomright (65): ṚUŒDṙLŒH_Ṛ}¥/ZZṚUṚ
topright-to-bottomleft (15): UŒDṙLŒH_Ṛ}¥/ZZṚU
bottomleft-to-topright (10): ṚŒDṙLŒH_Ṛ}¥/ZZṚṚ
bottomright-to-topleft  (0): ŒDṙLŒH_Ṛ}¥/ZZṚ

These each (except 0 and 4) apply a transform to M using some of Z (transpose), (reverse), and U (reverse each); then one of two functions (see below), then the inverse of the setup transformation (if there was one) implemented with the reverse of the code.

The two inner functions are:

ŒH_Ṛ}¥/ - Function A: Fold bottom-to-top: matrix, M
ŒH       - split M into two equal lists of rows (first half bigger by 1 if need be)
      / - reduce by:
     ¥  - last two links as a dyad:
    }   -  using the right argument (i.e. second half):
   Ṛ    -    reverse
  _     -  subtract

ŒDṙLŒH_Ṛ}¥/ZZṚ - Function B: Fold topright-to-bottomleft: matrix, M
ŒD             - diagonals of M
  ṙ            - rotate left by:
   L           -   length of M (puts them in order from bottom left most)
    ŒH_Ṛ}¥/    - same action as calling Function A on the diagonals
           Z   - transpose
            Z  - transpose
             Ṛ - reverse

Jonathan Allan

Posted 2019-06-17T11:24:16.880

Reputation: 67 804

1Ah nice, I was wondering if anyone would make use of the somewhat flexible input-options! Cool to see how you've used the values for a convenient base-conversion to Jelly code to evaluate to the desired folding. :) – Kevin Cruijssen – 2019-06-18T20:34:11.790

Using some of the code from my answer, and reusing code common to both, here’s a 34-byter: https://tio.run/##y0rNyan8///hzuZHDXOigPjhzllAMhSIFYD46CSXhztn@ihERYHF5x6d9HBHi9vDHZuywJIe8UDh2kNL9YFSZf8PL3/UtOb/fxMdBUMgttRRMAZiAyAPhE11FCxM/0dHKxgCxXUUgFzzWB0uhWiQAgsdBTMdBRMIHygPRTC@kSnIGHPT2FgA

– Nick Kennedy – 2019-06-18T20:54:27.427

If we were allowed 16 bit integers it could be even shorter – Nick Kennedy – 2019-06-18T20:56:03.387

Non-competing 23 byte answer using 16-bit integers as the parameter for selecting which fold: https://tio.run/##y0rNyan8///hzuZHDXOigPjhzllAMhSIj05yebhzpg@Y5REPFK89tFT/UcNct7L/h5c/alrz/7@BjoKpkY6CkZmOgoUFkDAyNQZyDc1NgWxTS1NjCyBlamZq8T86WsFQR8EYyNVRMI/V4VKIVgDqBUoDFZpA@EB5KILxjYCKDXTMTWNjAQ

– Nick Kennedy – 2019-06-18T21:04:12.810

@NickKennedy - thanks. I like the split and join! I'll have to come back later to change the description fully. – Jonathan Allan – 2019-06-20T08:12:52.700

3

Jelly, 71 34 bytes

ḃ2ŒḄ,UZṚŒDṙLƊŒH_Ṛ}¥/$ZZṚƊṚZ8ƭ$ị@¥ƒ

Try it online!

Test Suite

A full program. Right argument is the matrix. Left argument is the type of fold:

44 = L-R
40 = R-L
36 = T-B
32 = B-T
50 = TL-BR
34 = TR-BR
54 = BL-TR
38 = BR-TL

Rewritten to use 5-bit bijective binary as input. Note the program given above won’t work repeatedly for multiple folds.

Nick Kennedy

Posted 2019-06-17T11:24:16.880

Reputation: 11 829

3

JavaScript (ES6),  149 ... 133  128 bytes

Takes input as (matrix)(d) with \$0\le d\le7\$. Removed values are replaced with NaN.

Folding directions: \$0 =\;\rightarrow\$, \$1 =\;\downarrow\$, \$2 =\;\small\searrow\$, \$3 =\;\small\swarrow\$, \$4 =\;\leftarrow\$, \$5 =\;\uparrow\$, \$6 =\;\small\nwarrow\$, \$7 =\;\small\nearrow\$

m=>d=>m.map((r,y)=>r.map((v,x)=>v-=(w=m.length+~y)-(p=[x+x-y,y,x,q=w+y-x][d&3])&&[r[q],m[w][x],m[q][w],m[x][y]][d>3^p>w?d&3:m]))

Try it online!

Commented

m => d =>                   // m[] = matrix; d = direction
  m.map((r, y) =>           // for each row r[] at position y in m[]:
    r.map((v, x) =>         //   for each value v at position x in r[]:
      v -=                  //     subtract from v:
        (                   //       define w as:
          w = m.length + ~y //         the width of input matrix - y - 1
        ) - (               //       and compare it with
          p = [             //       p defined as:
            x + x - y,      //         2 * x - y for vertical folding
            y,              //         y for horizontal folding
            x,              //         x for diagonal folding
            q = w + y - x   //         q = w + y - x for anti-diagonal folding
          ][d & 3]          //       using d MOD 4
        ) &&                //       if p is equal to w, leave v unchanged
        [                   //       otherwise, subtract:
          r[q],             //         r[q] for vertical folding
          m[w][x],          //         m[w][x] for horizontal folding
          m[q][w],          //         m[q][w] for diagonal folding
          m[x][y]           //         m[x][y] for anti-diagonal folding
        ][                  //       provided that we're located in the target area:
          d > 3 ^           //         test p < w if d > 3 
          p > w ? d & 3     //         or p > w if d <= 3
                : m         //         and yield either d MOD 4 or m[]
        ]                   //       (when using m[], we subtract 'undefined' from v,
                            //       which sets it to NaN instead)
    )                       //   end of inner map()
  )                         // end of outer map()

Arnauld

Posted 2019-06-17T11:24:16.880

Reputation: 111 334

1

Octave, 482 bytes, 459 Bytes

The inputs for deciding folding directions are:
1)left to right
2)bottom to top
3)right to left
4)top to bottom
5)tr to bl
6)br to tl
7)bl to tr
8)tl to br
Each call only generates the specified fold, rather than all of them (which would probably would take less bytes). Biggest problem is that for this case I can't figure out how to put folds 1-4 and 5-8 in the same loop. But at least octave has nice looking matrices.

    function[m]=f(n,o)
    k=length(n);m=NaN(k);if(o<5)
    if(mod(o,2)>0)n=n'end
    q=[0,0,k+1,k+1](o)
    for x=1:ceil(k/2)if(x*2>k)m(x,:)=n(x,:)else
    for a=1:k
    m(abs(q-x),a)=n(abs(q-x),a)-n(abs(q-(k+1-x)),a)end
    end
    end
    if(mod(o,2)>0)m=flipud(m')end
    else
    if(mod(o,2)>0)n=flip(n)end
    q=[0,0,k+1,k+1](o-4)
    for x=1:k
    for a=1:k+1-x
    if(a==k+1-x)m(x,a)=n(x,a)else
    m(abs(q-x),abs(q-a))=n(abs(q-x),abs(q-a))-n(abs(q-(k+1-a)),abs(q-(k+1-x)))end
    end
    end
    end
    if(mod(o,2)>0)m=flip(m)end
    end

Try it online!

Output suppression costs bytes, so ignore everything that isn't the return statement(ans = ).

OrangeCherries

Posted 2019-06-17T11:24:16.880

Reputation: 321

How many bytes did you lose to writing "end"? – Expired Data – 2019-06-17T15:06:01.230

do you not have to write end? – OrangeCherries – 2019-06-17T15:07:06.003

You do unless you restructure it so it's not a bunch of if/else and for statements – Expired Data – 2019-06-17T15:08:36.610

wow tbh looking at your code there's tons of stuff I didn't even know you could do in matlab. – OrangeCherries – 2019-06-17T15:10:47.483

I don't know much about octave tbh it can probably save 50-100 bytes pretty easily – Expired Data – 2019-06-17T15:11:57.453

1

Charcoal, 78 77 bytes

F⁴«UMηE⮌η§μλ¿⁼ιθUMηEκ⎇‹⊕⊗νLη⁻μ§⮌κν⎇›⊕⊗νLηωμ¿⁼ι﹪θ⁴UMηEκ⎇‹λν⁻짧ηνλ⎇›λνωμ»Eη⪫ι,

Try it online! Link is to verbose version of code. Uses the following folding options:

0   top-to-bottom
1   left-to-right
2   bottom-to-top
3   right-to-left
4   bottomright-to-topleft
5   topright-to-bottomleft
6   topleft-to-bottomright
7   bottomleft-to-topright

Folded values are replaced by empty strings. Explanation:

F⁴«≔UMηE⮌η§μλ

Rotate the array four times.

¿⁼ιθUMηEκ⎇‹⊕⊗νLη⁻μ§⮌κν⎇›⊕⊗νLηωμ

Fold the array horizontally when appropriate.

¿⁼ι﹪θ⁴UMηEκ⎇‹λν⁻짧ηνλ⎇›λνωμ

Fold the array diagonally when appropriate.

»Eη⪫ι,

Output the array once it is rotated back to its original orientation.

Neil

Posted 2019-06-17T11:24:16.880

Reputation: 95 035