(
variable: Variable,
broadcast_dims: tuple[Hashable, ...],
core_dims: tuple[Hashable, ...],
)
| 646 | |
| 647 | |
| 648 | def broadcast_compat_data( |
| 649 | variable: Variable, |
| 650 | broadcast_dims: tuple[Hashable, ...], |
| 651 | core_dims: tuple[Hashable, ...], |
| 652 | ) -> Any: |
| 653 | data = variable.data |
| 654 | |
| 655 | old_dims = variable.dims |
| 656 | new_dims = broadcast_dims + core_dims |
| 657 | |
| 658 | if new_dims == old_dims: |
| 659 | # optimize for the typical case |
| 660 | return data |
| 661 | |
| 662 | set_old_dims = set(old_dims) |
| 663 | set_new_dims = set(new_dims) |
| 664 | unexpected_dims = [d for d in old_dims if d not in set_new_dims] |
| 665 | |
| 666 | if unexpected_dims: |
| 667 | raise ValueError( |
| 668 | "operand to apply_ufunc encountered unexpected " |
| 669 | f"dimensions {unexpected_dims!r} on an input variable: these are core " |
| 670 | "dimensions on other input or output variables" |
| 671 | ) |
| 672 | |
| 673 | # for consistency with numpy, keep broadcast dimensions to the left |
| 674 | old_broadcast_dims = tuple(d for d in broadcast_dims if d in set_old_dims) |
| 675 | reordered_dims = old_broadcast_dims + core_dims |
| 676 | if reordered_dims != old_dims: |
| 677 | order = tuple(old_dims.index(d) for d in reordered_dims) |
| 678 | data = duck_array_ops.transpose(data, order) |
| 679 | |
| 680 | if new_dims != reordered_dims: |
| 681 | key_parts: list[slice | None] = [] |
| 682 | for dim in new_dims: |
| 683 | if dim in set_old_dims: |
| 684 | key_parts.append(SLICE_NONE) |
| 685 | elif key_parts: |
| 686 | # no need to insert new axes at the beginning that are already |
| 687 | # handled by broadcasting |
| 688 | key_parts.append(np.newaxis) |
| 689 | data = data[tuple(key_parts)] |
| 690 | |
| 691 | return data |
| 692 | |
| 693 | |
| 694 | def _vectorize(func, signature, output_dtypes, exclude_dims): |
searching dependent graphs…