Dear NumPy Developers,

I hope you are doing well. I am writing to propose an enhancement to
NumPy’s broadcasting mechanism that could make the library even more
powerful, intuitive, and flexible while maintaining its memory
efficiency.

## **Current Broadcasting Rule and Its Limitation**
As per NumPy's current broadcasting rules, if two arrays have
different shapes, the smaller array can be expanded **only if one of
its dimensions is 1**. This allows memory-efficient expansion of data
without copying. However, if a dimension is greater than 1, NumPy
**does not** allow expansion to a larger size, even when the larger
size is a multiple of the smaller size.

### **Example of Current Behavior (Allowed Expansion)**
```python
import numpy as np

A = np.array([[1, 2, 3]])  # Shape (1,3)
B = np.array([[4, 5, 6],    # Shape (2,3)
              [7, 8, 9]])

C = A + B  # Broadcasting works because (1,3) can expand to (2,3)
print(C)

*Output:*

[[ 5  7  9]
 [ 8 10 12]]

Here, A has shape (1,3), which is automatically expanded to (2,3) without
copying because *a dimension of size 1 can be stretched*.

However, *NumPy fails when trying to expand a dimension where N > 1, even
if the larger size is a multiple of N*.
*Example of a Case That Fails (Even Though It Could Work)*

A = np.array([[1, 2, 3],    # Shape (2,3)
              [4, 5, 6]])

B = np.array([[10, 20, 30],  # Shape (4,3)
              [40, 50, 60],
              [70, 80, 90],
              [100, 110, 120]])

C = A + B  # Error! NumPy does not allow (2,3) to (4,3)

*This fails with the error:*

ValueError: operands could not be broadcast together with shapes (2,3) (4,3)

*Why Should This Be Allowed?*

If *a larger dimension is an exact multiple of a smaller one*, then
logically, the smaller array can be *repeated* along that axis *without
physically copying data*—just like NumPy does when broadcasting (1,M) to
(N,M).

In the above example,

   - A has shape (2,3), and B has shape (4,3).
   - Since 4 is *a multiple of* 2 (4 % 2 == 0), A could be *logically
   repeated 2 times* to become (4,3).
   - NumPy *already does* a similar expansion when a dimension is 1, so why
   not extend the same logic?

*Proposed Behavior (Expanding N → M When M % N == 0)*

Allow an axis with size N to be broadcast to size M *if and only if M is an
exact multiple of N (M % N == 0)*. This is *just as memory-efficient* as
the current broadcasting rules because it can be done using *stride tricks
instead of copying data*.
*Example of the Proposed Behavior*

If NumPy allowed this new form of broadcasting:

A = np.array([[1, 2, 3],    # Shape (2,3)
              [4, 5, 6]])

B = np.array([[10, 20, 30],  # Shape (4,3)
              [40, 50, 60],
              [70, 80, 90],
              [100, 110, 120]])

# Proposed new broadcasting rule
C = A + B

print(C)

*Expected Output:*

[[ 11  22  33]
 [ 44  55  66]
 [ 71  82  93]
 [104 115 126]]

This works by *logically repeating A* to match B’s shape (4,3).
*Why This is a Natural Extension of Broadcasting*

   - *Memory Efficiency:* Just like broadcasting (1,M) to (N,M), this
   expansion does *not* require physically copying data. Instead, strides
   can be adjusted to *logically repeat elements*, making this as efficient
   as current broadcasting.
   - *Intuitiveness:* Right now, broadcasting already surprises new users.
   If (1,3) can become (2,3), why not (2,3) to (4,3) when 4 is a multiple
   of 2? This would be a more intuitive rule.
   - *Extends Current Functionality:* This is *not* a new concept—it *extends
   the existing rule* where 1 can be stretched to any value. We are
   generalizing it to *any factor relationship* (N → M when M % N == 0).

*Implementation Considerations*

The logic behind NumPy’s current broadcasting already uses *stride tricks*
for memory-efficient expansion. Extending it to handle (N, M) → (K, M)
(where K % N == 0) would require:

   - Updating np.broadcast_shapes(), np.broadcast_to(), and related
   functions.
   - Extending the existing logic that handles expanding 1 to support
   factors as well.
   - Ensuring backward compatibility and maintaining performance.

*Conclusion*

I strongly believe this enhancement would make NumPy’s broadcasting *more
powerful, more intuitive, and just as efficient as before*. The fact that
we can implement this *without unnecessary copying* makes it a natural
extension of the existing feature.

I would love to hear the NumPy team’s thoughts on this! If the community is
open to it, I am also interested in contributing to its implementation.

Looking forward to your feedback!

Best regards,
*Shasang Thummar*
shasangthumm...@gmail.com
_______________________________________________
NumPy-Discussion mailing list -- numpy-discussion@python.org
To unsubscribe send an email to numpy-discussion-le...@python.org
https://mail.python.org/mailman3/lists/numpy-discussion.python.org/
Member address: arch...@mail-archive.com

Reply via email to