def f_a_v2(m, n):
M = numpy.ones((m, n))
x = numpy.arange(m).reshape((m, 1))
y = numpy.arange(n).reshape((1, n))
M = M * x
M = M * y
return M
M = numpy.ones((m, n))
M
with shape (m, n)
, filled entirely with the value 1.M[i, j]
is 1
for every i, j
.x = numpy.arange(m).reshape((m, 1))
y = numpy.arange(n).reshape((1, n))
numpy.arange(m)
Creates a numpy array of integers from 0
to m - 1
.
Example: if m = 3
, numpy.arange(3)
is [0, 1, 2]
.
.reshape((m, 1))
Reshapes the 1D array into a 2D array with m
rows and 1
column.
For m = 3
, x
becomes:
$$ \begin{bmatrix} 0\\ 1\\ 2 \end{bmatrix} $$
So, x
is shape (3, 1)
.
numpy.arange(n).reshape((1, n))
0
to n - 1
, then reshapes it into one row and n
columns.n = 4
, y
becomes:$$ [0\ 1\ 2\ 3] $$
So, y
has shape (1, 4)
.
M = M * x
M = M * y
First multiplication: M = M * x
Since M
was all ones of shape (m, n)
, and x
is shape (m, 1
), the multiplication is done via numpy broadcasting.
x
is “stretched” or “replicated” across all the columns of M
.i
in M
gets multiplied by x[i, 0]
.M[i, j] = i
for all valid i, j
.
For example, if m = 3
and n = 4
, after the first multiplication:
M = [[0, 0, 0, 0], # row i = 0 (0 * 1 = 0 for all columns)
[1, 1, 1, 1], # row i = 1 (1 * 1 = 1 for all columns)
[2, 2, 2, 2]] # row i = 2 (2 * 1 = 2 for all columns)
Second multiplication: M = M * y
Now M
is multiplied by y
which has shape (1, n)
. This time, the array y
is broadcasted along each row.
For each column j
, the multiplication factor becomes y[0, j] = j
.
After this step, each element in M
becomes i * j
.
Continuing the example with m = 3
and n = 4
:
M = [[0, 0, 0, 0], # row i = 0 multiplied by each column index j
[0, 1, 2, 3], # row i = 1 multiplied by each column index j
[0, 2, 4, 6]] # row i = 2 multiplied by each column index j
Hence, the result is a 2D array of shape (m, n)
whose element at (i, j)
is i * j
.