Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions arkouda/numpy/numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -3767,7 +3767,7 @@ def minimum(x1: Union[pdarray, numeric_scalars], x2: Union[pdarray, numeric_scal

if np.isscalar(tx1) and isinstance(tx2, pdarray):
return (
full(nan, tx2.size) if np.isnan(tx1) else where(isnan(tx2), tx2, where(tx1 < tx2, tx1, tx2))
full(tx2.size, nan) if np.isnan(tx1) else where(isnan(tx2), tx2, where(tx1 < tx2, tx1, tx2))
)

# if tx2 was a scalar, then tx1 isn't (they can't both be, at this point).
Expand Down Expand Up @@ -3855,7 +3855,7 @@ def maximum(x1: Union[pdarray, numeric_scalars], x2: Union[pdarray, numeric_scal

if np.isscalar(tx1) and isinstance(tx2, pdarray):
return (
full(nan, tx2.size) if np.isnan(tx1) else where(isnan(tx2), tx2, where(tx1 > tx2, tx1, tx2))
full(tx2.size, nan) if np.isnan(tx1) else where(isnan(tx2), tx2, where(tx1 > tx2, tx1, tx2))
)

# if tx2 was a scalar, then tx1 isn't (they can't both be, at this point).
Expand Down
102 changes: 78 additions & 24 deletions arkouda/numpy/pdarraycreation.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@
is_supported_int,
is_supported_number,
numeric_scalars,
numeric_and_bool_scalars,
resolve_scalar_dtype,
str_,
str_scalars,
)
from arkouda.numpy.dtypes import dtype as akdtype
from arkouda.numpy.dtypes import int64 as akint64
Expand Down Expand Up @@ -702,7 +704,7 @@ def ones(
size: Union[int_scalars, Tuple[int_scalars, ...], str],
dtype: Union[np.dtype, type, str, bigint] = float64,
max_bits: Optional[int] = None,
) -> pdarray:
) -> Union[pdarray, Strings]:
"""
Create a pdarray filled with ones.

Expand Down Expand Up @@ -757,11 +759,47 @@ def ones(
return full(size=size, fill_value=1, dtype=dtype, max_bits=max_bits)


@overload
def full(
size: Union[int_scalars, Tuple[int_scalars, ...], str],
fill_value: str_scalars,
dtype: None = ...,
max_bits: Optional[int] = ...,
) -> Strings: ...


@overload
def full(
size: Union[int_scalars, Tuple[int_scalars, ...], str],
fill_value: Union[numeric_and_bool_scalars, str_scalars],
dtype: str,
max_bits: Optional[int] = ...,
) -> Strings: ...


@overload
def full(
size: Union[int_scalars, Tuple[int_scalars, ...], str],
fill_value: Union[numeric_and_bool_scalars],
dtype: None = ...,
max_bits: Optional[int] = ...,
) -> pdarray: ...


@overload
def full(
size: Union[int_scalars, Tuple[int_scalars, ...], str],
fill_value: Union[numeric_and_bool_scalars, str_scalars],
dtype: Union[np.dtype, type, bigint],
max_bits: Optional[int] = ...,
) -> pdarray: ...


@typechecked
def full(
size: Union[int_scalars, Tuple[int_scalars, ...], str],
fill_value: Union[numeric_scalars, np.bool, str],
dtype: Union[np.dtype, type, str, bigint] = float64,
fill_value: Union[numeric_and_bool_scalars, str_scalars],
dtype: Union[None, np.dtype, type, str, bigint] = None,
max_bits: Optional[int] = None,
) -> Union[pdarray, Strings]:
"""
Expand All @@ -771,10 +809,10 @@ def full(
----------
size: int_scalars or tuple of int_scalars
Size or shape of the array
fill_value: int_scalars or str
fill_value: numeric_scalars, bool_scalars or str_scalars
Value with which the array will be filled
dtype: all_scalars
Resulting array type, default float64
Resulting array type. If None, it will be inferred from fill_value
max_bits: int
Specifies the maximum number of bits; only used for bigint pdarrays

Expand All @@ -793,6 +831,7 @@ def full(

ValueError
Raised if the rank of the given shape is not in get_array_ranks() or is empty
Raised if a multi-dim Strings array was requested
Raised if max_bits is not NONE and ndim does not equal 1

See Also
Expand All @@ -813,32 +852,44 @@ def full(
array([True True True True True])
"""
from arkouda.client import generic_msg, get_array_ranks
from arkouda.numpy.dtypes import dtype as ak_dtype
from arkouda.numpy.pdarrayclass import create_pdarray
from arkouda.numpy.util import _infer_shape_from_size # placed here to avoid circ import

if isinstance(fill_value, str):
return _full_string(size, fill_value)
elif ak_dtype(dtype) == str_ or dtype == Strings:
return _full_string(size, str_(fill_value))
# Process the arguments (size, fill_value, dtype) before choosing an action.

dtype = dtype if dtype is not None else resolve_scalar_dtype(fill_value)
shape, ndim, full_size = _infer_shape_from_size(size)
fv_dtype = akdtype(resolve_scalar_dtype(fill_value)) # derived from fill_value
dtype = dtype if dtype is not None else fv_dtype # must allow it to be None

if isinstance(dtype, bigint) or isinstance(dtype, np.dtype):
dtype_name = dtype.name
elif isinstance(dtype, type) or isinstance(dtype, str):
dtype_name = akdtype(dtype).name
else:
raise TypeError(f"Unsupported dtype {dtype!r}")

# The only string cases.

if dtype == Strings or akdtype(dtype) == str_:
if ndim != 1:
raise ValueError(f"Size parameter {size} incompatible with Strings.")
else:
if isinstance(fill_value, float): # needed to match numpy, which
fill_value = int(fill_value) # truncates floats to ints before "str"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line leads to this error:

In [8]: ak.full(n, np.nan, dtype=ak.str_)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[8], line 1
----> 1 ak.full(n, np.nan, dtype=ak.str_)

File ~/anaconda3/envs/arkouda-dev/lib/python3.13/site-packages/typeguard/__init__.py:891, in typechecked.<locals>.wrapper(*args, **kwargs)
    889 memo = _CallMemo(python_func, _localns, args=args, kwargs=kwargs)
    890 check_argument_types(memo)
--> 891 retval = func(*args, **kwargs)
    892 check_return_type(retval, memo)
    894 # If a generator is returned, wrap it if its yield/send/return types can be checked

File ~/git/arkouda/arkouda/numpy/pdarraycreation.py:882, in full(size, fill_value, dtype, max_bits)
    880     else:
    881         if isinstance(fill_value, float):  # needed to match numpy, which
--> 882             fill_value = int(fill_value)  # truncates floats to ints before "str"
    883         return _full_string(full_size, str(fill_value))
    885 #  Remaining cases are all numeric.  Check dtype for error

ValueError: cannot convert float NaN to integer

Also consider what happens for np.inf and -np.inf.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those were interesting edge cases. Handled now, with ifs.

return _full_string(full_size, str(fill_value))

# Remaining cases are all numeric. Check dtype for error

dtype = akdtype(dtype) # normalize dtype
dtype_name = dtype.name if isinstance(dtype, bigint) else cast(np.dtype, dtype).name
# check dtype for error
if dtype_name not in NumericDTypes:
raise TypeError(f"unsupported dtype {dtype}")
from arkouda.numpy.util import (
_infer_shape_from_size, # placed here to avoid circ import
)
raise TypeError(f"Unsupported dtype {dtype} in ak.full")

shape, ndim, full_size = _infer_shape_from_size(size)
# dtype is supported. Two more checks.

if ndim not in get_array_ranks():
raise ValueError(f"array rank {ndim} not in compiled ranks {get_array_ranks()}")
raise ValueError(f"Array rank {ndim} not in compiled ranks {get_array_ranks()}")

if isinstance(shape, tuple) and len(shape) == 0:
raise ValueError("size () not currently supported in ak.full.")
raise ValueError("Empty shape () not currently supported in ak.full.")

rep_msg = generic_msg(cmd=f"create<{dtype_name},{ndim}>", args={"shape": shape})

Expand Down Expand Up @@ -1408,11 +1459,11 @@ def linspace(
if endpoint is None:
endpoint = True

# First make sure everything's a float.

start_ = start
stop_ = stop

# First make sure everything's a float.

if isinstance(start_, pdarray):
start_ = start_.astype(float64)
elif isinstance(start_, int):
Expand Down Expand Up @@ -1471,7 +1522,10 @@ def linspace(
else:
if axis == 0:
delta = (stop_ - start_) / divisor
result = full(num, start_) + arange(num).astype(float64) * delta
if isinstance(start_, (int, float, np.number)): # required for mypy
result = full(num, start_) + arange(num).astype(float64) * delta
else: # this should be impossible to reach
raise TypeError("Non-numeric start value found in linspace.")
else:
raise ValueError("axis should not be supplied when start and stop are scalars.")

Expand Down
2 changes: 2 additions & 0 deletions arkouda/numpy/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@ def broadcast_to(x: Union[numeric_scalars, pdarray], shape: Union[int, Tuple[int
from arkouda.numpy.pdarraycreation import full as akfull

if _val_isinstance_of_union(x, numeric_scalars):
assert not isinstance(x, pdarray) # Required for mypy
return akfull(shape, x, dtype=type(x))
elif isinstance(x, pdarray) and isinstance(shape, int):
if x.ndim == 1 and x.size == shape:
Expand Down Expand Up @@ -1012,6 +1013,7 @@ def map(
xtra_keys = gb_keys[in1d(gb_keys, mapping.index.values, invert=True)]

if xtra_keys.size > 0:
nans: Union[pdarray, Strings] # without this, mypy complains
if not isinstance(mapping.values, (Strings, Categorical)):
nans = full(xtra_keys.size, np.nan, mapping.values.dtype)
else:
Expand Down
2 changes: 1 addition & 1 deletion arkouda/pandas/extension/_arkouda_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def isna(self) -> ExtensionArray | ndarray[Any, Any]:
from arkouda.numpy.util import is_float

if not is_float(self._data):
return ak_full(self._data.size, False, dtype=bool)
return ArkoudaArray(ak_full(self._data.size, False, dtype=bool))

return isnan(self._data)

Expand Down
2 changes: 1 addition & 1 deletion tests/pandas/extension/arkouda_array_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def test_isna(self):
ak_data = ak.arange(10)
arr = ArkoudaArray(ak_data)
na = arr.isna()
assert ak.all(na == False)
assert (na == False).all()

def test_isna_with_nan(self):
from arkouda.testing import assert_equal
Expand Down