Skip to content

Broadcasting ​

Broadcasting allows operations between arrays of different shapes by automatically expanding dimensions to make them compatible.

How Broadcasting Works ​

When operating on two arrays, NDArray compares their shapes element-wise starting from the trailing (rightmost) dimension. Two dimensions are compatible when:

  1. They are equal, or
  2. One of them is 1

Missing dimensions are treated as 1.

Rules of Broadcasting ​

  1. Start from the trailing (rightmost) dimension and work left
  2. Compare dimensions one by one:
    • If dimensions are equal, they are compatible
    • If one dimension is 1, the array is stretched (broadcast) along that axis to match the other
    • If dimensions are different and neither is 1, broadcasting fails
  3. Missing dimensions in the smaller array are treated as 1

Common Broadcasting Patterns ​

Scalar Broadcasting ​

Scalars are broadcast to match any array shape:

php
$arr = NDArray::ones([3, 3]);
$result = $arr->add(5);  // 5 is broadcast to [3, 3]
// Result: all elements are 6

$matrix = NDArray::zeros([3, 4]);
$result = $matrix->add(10);  // Every element becomes 10

Row Broadcasting ​

A 1D array can be broadcast across rows of a 2D matrix:

php
$matrix = NDArray::zeros([3, 4]);
$row = NDArray::array([1, 2, 3, 4]);  // Shape [4]
$result = $matrix->add($row);  // Row broadcast to [3, 4]
// Result:
// [[1, 2, 3, 4]
//  [1, 2, 3, 4]
//  [1, 2, 3, 4]]

Column Broadcasting ​

An array with shape [n, 1] can be broadcast across columns:

php
$matrix = NDArray::zeros([3, 4]);
$col = NDArray::array([[1], [2], [3]]);  // Shape [3, 1]
$result = $matrix->add($col);  // Column broadcast to [3, 4]
// Result:
// [[1, 1, 1, 1]
//  [2, 2, 2, 2]
//  [3, 3, 3, 3]]

3D Broadcasting ​

Broadcasting works with any number of dimensions:

php
// Shape [2, 3, 4] broadcast with shape [3, 4]
$tensor = NDArray::ones([2, 3, 4]);
$matrix = NDArray::array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]);
$result = $tensor->add($matrix);  // Shape [2, 3, 4]
// The [3, 4] matrix is broadcast across the first dimension

Shape Compatibility Examples ​

php
// Compatible: (5, 4) and (4,)
$a = NDArray::ones([5, 4]);
$b = NDArray::ones([4]);
$result = $a->add($b);  // OK: b is broadcast to [5, 4]

// Compatible: (5, 4) and (5, 1)
$a = NDArray::ones([5, 4]);
$b = NDArray::ones([5, 1]);
$result = $a->add($b);  // OK: b is broadcast to [5, 4]

// Compatible: (3, 1, 1) and (1, 5)
$a = NDArray::ones([3, 1, 1]);
$b = NDArray::ones([1, 5]);
$result = $a->add($b);  // OK: shapes become [3, 1, 5] and [3, 1, 5]

// NOT Compatible: (5, 4) and (5,)
$a = NDArray::ones([5, 4]);
$b = NDArray::ones([5]);
// $a->add($b);  // Error: trailing dimensions don't match (4 vs 5)

Broadcasting in Arithmetic Operations ​

All arithmetic operations support broadcasting:

php
$a = NDArray::array([[1, 2], [3, 4]]);  // Shape [2, 2]
$b = NDArray::array([10, 20]);          // Shape [2]

$sum = $a->add($b);           // [[11, 22], [13, 24]]
$diff = $a->subtract($b);     // [[-9, -18], [-7, -16]]
$prod = $a->multiply($b);     // [[10, 40], [30, 80]]
$quot = $a->divide($b);       // [[0.1, 0.1], [0.3, 0.2]]

Broadcasting with Comparison Operations ​

Comparison operations also broadcast:

php
$matrix = NDArray::array([[1, 2, 3], [4, 5, 6]]);
$threshold = NDArray::array([[2], [5]]);  // Shape [2, 1]

$mask = $matrix->gt($threshold);
// Result:
// [[false, false, true]
//  [false, false, true]]

Practical Examples ​

Normalizing Data ​

php
// Normalize each column by its mean
$data = NDArray::array([[1, 10], [2, 20], [3, 30]]);
$colMeans = $data->mean(axis: 0)->reshape([1, 2]);  // Shape [1, 2]
$normalized = $data->subtract($colMeans);  // Broadcast subtraction

Adding Bias to Neural Network Activations ​

php
// activations: shape [batch_size, num_neurons]
// bias: shape [num_neurons]
$activations = NDArray::zeros([32, 100]);
$bias = NDArray::ones([100]);
$output = $activations->add($bias);  // Broadcast bias to each batch

Computing Distances ​

php
// Compute (x - mean)^2 for each element
$x = NDArray::array([[1, 2], [3, 4], [5, 6]]);
$mean = NDArray::array([3, 4])->reshape([1, 2]);
$squaredDiff = $x->subtract($mean)->power(2);

Common Mistakes ​

1. Mismatched Dimensions ​

php
// WRONG: dimensions don't match from the right
$a = NDArray::ones([5, 4]);
$b = NDArray::ones([5]);  // Error: 4 != 5
// $a->add($b);  // Broadcasting error

Fix: Reshape to add a dimension of size 1:

php
$b = NDArray::ones([5])->reshape([5, 1]);  // Now compatible
$result = $a->add($b);

2. Confusing Row and Column Vectors ​

php
// Row vector
$row = NDArray::array([1, 2, 3]);        // Shape [3]

// Column vector  
$col = NDArray::array([[1], [2], [3]]);  // Shape [3, 1]

$matrix = NDArray::ones([3, 3]);

$rowResult = $matrix->add($row);  // Adds to each row
$colResult = $matrix->add($col);  // Adds to each column

Performance Considerations ​

Broadcasting is memory-efficient - it doesn't actually create copies of the broadcasted array. The operations are applied on-the-fly during computation.

However, if you need to use a broadcasted array multiple times, consider explicitly creating a full-size copy with tile() or repeat() methods (when available).

See Also ​

Released under the MIT License.