Modular broadcasting This challenge is related to some of the MATL language's features, as part of the May 2018 Language of the Month event.



Introduction

In MATL, many two-input functions work element-wise with broadcast. This means the following:


Element-wise (or vectorized): the function takes as inputs two arrays with matching sizes. The operation defined by the function is applied to each pair of corresponding entries. For example, using post-fix notation:

[2 4 6] [10 20 30] +


gives the ouput

[12 24 36]


This also works with multi-dimensional arrays. The notation [1 2 3; 4 5 6] represents the 2×3 array (matrix)

1 2 3
4 5 6


which has size 2 along the first dimension (vertical) and 3 along the second (horizontal). So for example

[2 4 6; 3 5 7] [10 20 30; 40 60 80] *


gives

[20 80 180; 120 300 560]

Broadcasting or (singleton expansion): the two input arrays do not have matching sizes, but in each non-matching dimension one of the arrays has size 1. This array is implicitly replicated along the other dimensions to make sizes match; and then the operation is applied element-wise as above. For example, consider two input arrays with sizes 1×2 and 3×1:

[10 20] [1; 2; 5] /


Thanks to broadcasting, this is equivalent to

[10 20; 10 20; 10 20] [1 1; 2 2; 5 5] /


and so it gives

[10 20; 5 10; 2 4]


Similarly, with sizes 3×2 and 3×1 (broadcasting now acts along the second dimension only),

[9 8; 7 6; 5 4] [10; 20; 30] +


gives

[19 18; 27 26; 35 34]


The number of dimensions may even be different. For example, inputs with sizes 3×2 and 3×1×5 are compatible, and give a 3×2×5 result. In fact, size 3×2 is the same as 3×2×1 (there are arbitrarily many implicit trailing singleton dimensions).

On the other hand, a pair of 2×2 and 3×1 arrays would give an error, because the sizes along the first dimension are 2 and 3: they are not equal and none of them is 1.


Definition of modular broadcasting

Modular broadcasting is a generalization of broadcasting that works even if none of the non-matching sizes are 1. Consider for example the following 2×2 and 3×1 arrays as inputs of the function +:

[2 4; 6 8] [10; 20; 30] +


The rule is as follows: for each dimension, the array that is smaller along that dimension is replicated modularly (cyclically) to match the size of the other array. This would make the above equivalent to

[2 4; 6 8; 2 4] [10 10; 20 20; 30 30] +


with the result

[12 14; 26 28; 32 34]


As a second example, 

[5 10; 15 20] [0 0 0 0; 1 2 3 4; 0 0 0 0; 5 6 7 8; 0 0 0 0] +


would produce

[5 10 5 10; 16 22 18 24; 5 10 5 10; 20 26 22 28; 5 10 5 10]


In general, inputs with sizes a×b and c×d give a result of size max(a,b)×max(c,d).

The challenge

Implement addition for two-dimensional arrays with modular broadcasting as defined above.

The arrays will be rectangular (not ragged), will only contain non-negative integers, and will have size at least 1 in each dimension.

Aditional rules:


Input and output can be taken by any reasonable means. Their format is flexible as usual.
Programs or functions are allowed, in any programming language. Standard loopholes are forbidden.
Shortest code in bytes wins.


Test cases

The following uses ; as row separator (as in the examples above). Each test case shows the two inputs and then the output.

[2 4; 6 8]
[10; 20; 30]
[12 14; 26 28; 32 34]

[5 10; 15 20]
[0 0 0 0; 1 2 3 4; 0 0 0 0; 5 6 7 8; 0 0 0 0]
[5 10 5 10; 16 22 18 24; 5 10 5 10; 20 26 22 28; 5 10 5 10]

[1]
[2]
[3]

[1; 2]
[10]
[11; 12]

[1 2 3 4 5]
[10 20 30]
[11 22 33 14 25]

[9 12 5; 5 4 2]
[4 2; 7 3; 15 6; 4 0; 3 3]
[13 14 9;12 7 9;24 18 20;9 4 6;12 15 8]

[9 12 5; 5 4 2]
[4 2 6 7; 7 3 7 3; 15 6 0 1; 4 0 1 16; 3 3 3 8]
[13 14 11 16; 12 7 9 8; 24 18 5 10; 9 4 3 21; 12 15 8 17]

[6 7 9]
[4 2 5]
[10 9 14]
Charcoal, 25 23 bytes

ＡθＩＥ⌈ＥθＬιＥ⌈ＥθＬ§λ⁰ΣＥθ§§νιλ

Try it online! Link is to verbose version of code. Takes input as a 3-dimensional array. Explanation:

Ａθ


Input everything.

    θ                   Input
   Ｅ                    Map over arrays
      ι                 Current array
     Ｌ                  Length
  ⌈                     Maximum
 Ｅ                      Map over implicit range
          θ             Input
         Ｅ              Map over arrays
             λ          Current array
            § ⁰         First element
           Ｌ            Length
        ⌈               Maximum
       Ｅ                Map over implicit range
                 θ      Input
                Ｅ       Map over arrays
                    ν   Current array
                   § ι  Cyclically index using outer loop index
                  §   λ Cyclically index using inner loop index
               Σ        Sum
Ｉ                       Cast to string
                        Implicitly print on separate lines and paragraphs