Array Broadcasting
Problem Statement
Perform element-wise operations between arrays of different shapes.
Background
Broadcasting rules:
- Dimensions are compared from right to left
- Dimensions are compatible if equal or one of them is 1
- Arrays are "stretched" to match
Example: (3, 1) + (1, 4) → (3, 4)
Your Task
Write a function broadcast_arrays(row_vec, col_vec) that demonstrates broadcasting.
Given:
- row_vec: Shape (1, n) - a row vector
- col_vec: Shape (m, 1) - a column vector
Output Format
Return a dictionary with:
- "sum": row_vec + col_vec (broadcasts to m×n)
- "product": row_vec * col_vec (broadcasts to m×n)
- "result_shape": Shape of result (as list)
Example:
row = [[1, 2, 3]], col = [[10], [20]]
{'sum': [[11, 12, 13], [21, 22, 23]], ...}Each row_vec element combines with each col_vec element
Constraints:
- row_vec has shape (1, n)
- col_vec has shape (m, 1)
More from NumPy Foundations
Array Broadcasting in NumPy: Background Knowledge
Background Knowledge
Broadcasting is a fundamental NumPy mechanism that allows operations between arrays of different shapes without explicitly copying data. Rather than requiring arrays to have identical dimensions, NumPy automatically "stretches" smaller arrays to match larger ones according to specific rules. This enables efficient element-wise operations and eliminates the need for manual loops or array replication, making code both more concise and computationally efficient.
The broadcasting rules operate on a simple principle: dimensions are compared from right to left, and two dimensions are compatible if they are either equal or one of them is 1. When a dimension is 1, that array is conceptually repeated along that axis to match the other array's size. For example, an array of shape (1, 3) can broadcast with an array of shape (2, 1) to produce a result of shape (2, 3). The dimension of size 1 is "stretched" to match the corresponding dimension in the other array.
Understanding broadcasting is essential for writing efficient NumPy code because it avoids unnecessary memory allocation and copying. Instead of creating intermediate arrays, NumPy performs operations directly on the original data with implicit repetition, resulting in faster execution and lower memory usage.
Algorithm/Approach
The general approach to solving broadcasting problems involves three key steps:
- Understand the input shapes: Identify the dimensions of each input array and verify they are compatible according to broadcasting rules.
- Apply the operation: Leverage NumPy's automatic broadcasting to perform element-wise operations without manual reshaping.
- Verify the output shape: Confirm that the resulting array has the expected shape based on broadcasting rules.
The key insight is that you don't need to manually implement broadcasting logic—NumPy handles it automatically. Your task is to understand why the result has a particular shape and to structure your function to return the required information.
Step-by-Step Strategy
Step 1: Parse the inputs
- Receive a row vector of shape (1, n) and a column vector of shape (m, 1)
- Verify these shapes match the expected format
Step 2: Apply element-wise operations
- Perform addition: row_vec + col_vec
- Perform multiplication: row_vec * col_vec
- NumPy automatically broadcasts both to shape (m, n)
Step 3: Determine the result shape
- Compare dimensions from right to left:
- Rightmost: 3 vs 1 → compatible, result is 3
- Next: 1 vs 2 → compatible, result is 2
- Final shape: (2, 3)
- Extract this as a list for the output dictionary
Step 4: Convert to appropriate format
- Convert NumPy arrays to lists (using .tolist()) if the expected output format requires it
- Structure the dictionary with keys "sum", "product", and "result_shape"
Common Pitfalls
- Forgetting the broadcasting rules: Remember that dimensions are compared right to left, not left to right. A shape (1, 3) is compatible with (2, 1), but (3, 1) is not compatible with (1, 2) in the same way.
- Confusing shape representation: Ensure you understand that shape (1, n) means 1 row and n columns, while (m, 1) means m rows and 1 column.
- Output format mismatch: The problem asks for lists in the output dictionary, not NumPy arrays. Use .tolist() to convert if needed.
- Assuming manual broadcasting is necessary: Don't write explicit loops or use np.tile() or np.repeat(). NumPy's built-in broadcasting handles this automatically and more efficiently.
- Incorrect shape extraction: The result shape should be extracted from the actual result array (e.g., result.shape), not computed manually, to avoid off-by-one errors.
Time & Space Complexity
Time Complexity: O(m×n)
The addition and multiplication operations must touch every element in the resulting (m, n) array exactly once. NumPy performs these operations efficiently using vectorized C code, but the fundamental operation count is proportional to the output size.
Space Complexity: O(m×n)
Both the sum and product results require storage for m × n elements. While NumPy uses broadcasting to avoid copying the input arrays during computation, the output arrays themselves must be allocated in memory. If you store both results in the dictionary, you're using space for two (m, n) arrays plus the input arrays.