"""Copy values from one array to another, broadcasting as necessary."""
from __future__ import annotations
import logging
import numpy
import numpy.typing
import numpoly
from ..baseclass import ndpoly, PolyLike
from ..dispatch import implements
[docs]@implements(numpy.copyto)
def copyto(
dst: ndpoly,
src: PolyLike,
casting: str = "same_kind",
where: numpy.typing.ArrayLike = True,
) -> None:
"""
Copy values from one array to another, broadcasting as necessary.
Raises a TypeError if the `casting` rule is violated, and if
`where` is provided, it selects which elements to copy.
Args:
dst:
The array into which values are copied.
src:
The array from which values are copied.
casting:
Controls what kind of data casting may occur when copying.
* 'no' means the data types should not be cast at all.
* 'equiv' means only byte-order changes are allowed.
* 'safe' means only casts which can preserve values are allowed.
* 'same_kind' means only safe casts or casts within a kind,
like float64 to float32, are allowed.
* 'unsafe' means any data conversions may be done.
where:
A boolean array which is broadcasted to match the dimensions
of `dst`, and selects elements to copy from `src` to `dst`
wherever it contains the value True.
Example:
>>> q0 = numpoly.variable()
>>> poly1 = numpoly.polynomial([1, q0**2, q0])
>>> poly2 = numpoly.polynomial([2, q0, 3])
>>> numpoly.copyto(poly1, poly2, where=[True, False, True])
>>> poly1
polynomial([2, q0**2, 3])
>>> numpoly.copyto(poly1, poly2)
>>> poly1
polynomial([2, q0, 3])
"""
logger = logging.getLogger(__name__)
src = numpoly.aspolynomial(src)
assert isinstance(dst, numpy.ndarray)
if not isinstance(dst, numpoly.ndpoly):
if dst.dtype.names is None:
if src.isconstant():
return numpy.copyto(dst, src.tonumpy(), casting=casting, where=where)
raise ValueError(f"Could not convert src {src} to dst {dst}")
if casting != "unsafe":
raise ValueError(f"could not safely convert src {src} to dst {dst}")
logger.warning("Copying ndpoly input into ndarray")
logger.warning("You might need to cast `numpoly.polynomial(dst)`.")
logger.warning("Indeterminant names might be lost.")
dst_keys = dst.dtype.names
dst_ = dst
else:
dst_keys = dst.keys
src, _ = numpoly.align_indeterminants(src, dst)
dst_ = dst.values
missing_keys = set(src.keys).difference(dst_keys)
if missing_keys:
raise ValueError(f"memory layouts are incompatible: {missing_keys}")
for key in dst_keys:
if key in src.keys:
numpy.copyto(dst_[key], src.values[key], casting=casting, where=where)
else:
numpy.copyto(
dst_[key],
numpy.array(False, dtype=dst_[key].dtype),
casting=casting,
where=where,
)