Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5395e73
Convert examples from workload style to standalone style
nayyirahsan Jan 23, 2026
cd6811c
Addressed comments (Reversed READ.ME, inclusive_scan_team.py, and all…
nayyirahsan Jan 26, 2026
4221719
Format examples with Black
nayyirahsan Jan 29, 2026
c6a0215
Deleted ufunc implementations and tests. Replaced ufunc usage in exam…
nayyirahsan Feb 12, 2026
19e7fd7
Merge branch 'main' into nayyirahsan/ufunc-removal
nayyirahsan Feb 12, 2026
275c89d
fix array api tests and further removed pk usage
nayyirahsan Feb 22, 2026
e1bd7ef
fix array api test
nayyirahsan Feb 22, 2026
f056ad9
pass tests
nayyirahsan Feb 25, 2026
d2962f0
format
nayyirahsan Feb 25, 2026
5ea2991
remove duplicate
nayyirahsan Feb 25, 2026
97be73f
revert data_type.py
nayyirahsan Feb 25, 2026
4e42b48
format
nayyirahsan Feb 25, 2026
3254455
add pk_array helper
nayyirahsan Feb 25, 2026
06fe715
add pk_array lib
nayyirahsan Feb 25, 2026
8f6dea9
format
nayyirahsan Feb 25, 2026
58715ec
revert abstraction
nayyirahsan Mar 2, 2026
9ec995c
remove unnessesary test
nayyirahsan Mar 3, 2026
bd1c1e9
remove all PKArray usage
nayyirahsan Mar 3, 2026
8fb75d7
Merge branch 'main' into nayyirahsan/ufunc-removal
IvanGrigorik Mar 6, 2026
4159771
fix for other execution spaces
nayyirahsan Mar 9, 2026
effcd59
Merge branch 'nayyirahsan/ufunc-removal' of https://github.com/nayyir…
nayyirahsan Mar 9, 2026
5d61e30
fix isnan and isfinite errors
nayyirahsan Mar 9, 2026
299b46f
add isinf function
nayyirahsan Mar 9, 2026
6b1d185
restore workunits
nayyirahsan Mar 9, 2026
0cd79dc
fix equal
nayyirahsan Mar 9, 2026
c97a5bc
format
nayyirahsan Mar 9, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/array_api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,6 @@ jobs:
# to circumvent the currently slow performance of
# JIT compile/link, which can otherwise cause issues
# for hypothesis-driven test case generation
pytest $GITHUB_WORKSPACE/tools/pre_compile_ufuncs.py -s
# pytest $GITHUB_WORKSPACE/tools/pre_compile_ufuncs.py -s
# only run a subset of the conformance tests to get started
pytest array_api_tests/meta/test_broadcasting.py array_api_tests/meta/test_equality_mapping.py array_api_tests/meta/test_signatures.py array_api_tests/meta/test_special_cases.py array_api_tests/test_constants.py array_api_tests/meta/test_utils.py array_api_tests/test_creation_functions.py::test_ones array_api_tests/test_creation_functions.py::test_ones_like array_api_tests/test_data_type_functions.py::test_result_type array_api_tests/test_operators_and_elementwise_functions.py::test_log10 array_api_tests/test_operators_and_elementwise_functions.py::test_sqrt array_api_tests/test_operators_and_elementwise_functions.py::test_isfinite array_api_tests/test_operators_and_elementwise_functions.py::test_log2 array_api_tests/test_operators_and_elementwise_functions.py::test_log1p array_api_tests/test_operators_and_elementwise_functions.py::test_isinf array_api_tests/test_operators_and_elementwise_functions.py::test_log array_api_tests/test_array_object.py::test_scalar_casting array_api_tests/test_operators_and_elementwise_functions.py::test_sign array_api_tests/test_operators_and_elementwise_functions.py::test_square array_api_tests/test_operators_and_elementwise_functions.py::test_cos array_api_tests/test_operators_and_elementwise_functions.py::test_round array_api_tests/test_operators_and_elementwise_functions.py::test_trunc array_api_tests/test_operators_and_elementwise_functions.py::test_ceil array_api_tests/test_operators_and_elementwise_functions.py::test_floor array_api_tests/test_operators_and_elementwise_functions.py::test_exp array_api_tests/test_operators_and_elementwise_functions.py::test_sin array_api_tests/test_operators_and_elementwise_functions.py::test_tan array_api_tests/test_operators_and_elementwise_functions.py::test_tanh array_api_tests/test_creation_functions.py::test_zeros array_api_tests/test_creation_functions.py::test_zeros_like array_api_tests/test_creation_functions.py::test_full_like array_api_tests/test_operators_and_elementwise_functions.py::test_positive array_api_tests/test_operators_and_elementwise_functions.py::test_isnan array_api_tests/test_operators_and_elementwise_functions.py::test_equal "array_api_tests/test_has_names.py::test_has_names[array_method-__pos__]"
18 changes: 9 additions & 9 deletions examples/LogisticRegression/LR.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ def _logistic_regression_path(

_, n_features = X.shape

classes = pk.unique(y)
classes = np.unique(y)

random_state = check_random_state(random_state)

Expand Down Expand Up @@ -333,8 +333,8 @@ def _logistic_regression_path(
lbin = LabelBinarizer()
Y_multi = asarray(lbin.fit_transform(y))
if Y_multi.shape[1] == 1:
Y_multi = pk.hstack(
pk.negative(pk.subtract(Y_multi, asarray([1]))), Y_multi
Y_multi = np.hstack(
np.negative(np.subtract(Y_multi, asarray([1]))), Y_multi
)

w0 = pk.zeros((classes.size, n_features + int(fit_intercept)), dtype=X.dtype)
Expand Down Expand Up @@ -397,7 +397,7 @@ def _logistic_regression_path(
func = loss.loss
grad = loss.gradient
hess = loss.gradient_hessian_product # hess = [gradient, hessp]
warm_start_sag = {"coef": pk.transpose(w0)}
warm_start_sag = {"coef": np.transpose(np.array(w0))}
else:
target = y_bin
if solver == "lbfgs":
Expand Down Expand Up @@ -471,7 +471,7 @@ def _logistic_regression_path(
)
coef_ = asarray(coef_)
if fit_intercept:
w0 = pk.hstack(pk.ravel(coef_), intercept_)
w0 = np.hstack(pk.ravel(coef_), intercept_)
else:
w0 = pk.ravel(coef_)

Expand Down Expand Up @@ -862,7 +862,7 @@ def fit(self, X, y, sample_weight=None):

X = asarray(X)
y = asarray(y)
self.classes_ = pk.unique(y)
self.classes_ = np.unique(np.array(y))

multi_class = _check_multi_class(self.multi_class, solver, len(self.classes_))

Expand Down Expand Up @@ -1024,7 +1024,7 @@ def predict_proba(self, X):
if decision.ndim == 1:
# Workaround for multi_class="multinomial" and binary outcomes
# which requires softmax prediction with only a 1D decision.
decision_2d = pk.hstack(pk.negative(decision), decision)
decision_2d = np.hstack((np.negative(decision), decision))
else:
decision_2d = decision
return softmax(decision_2d, copy=False)
Expand All @@ -1045,7 +1045,7 @@ def predict_log_proba(self, X):
Returns the log-probability of the sample for each class in the
model, where classes are ordered as they are in ``self.classes_``.
"""
return pk.log(self.predict_proba(X))
return np.log(self.predict_proba(X))

def predict(self, X):
"""
Expand All @@ -1065,7 +1065,7 @@ def predict(self, X):
else:
indices = scores.argmax(axis=1)

return pk.index(self.classes_, asarray(indices, dtype=pk.int32))
return self.classes_[np.array(indices, dtype=np.int32)]


def main():
Expand Down
52 changes: 27 additions & 25 deletions examples/NaiveBayes/GaussianNB.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,15 @@ def type_of_target(y, input_name=""):
else:
suffix = "" # [1, 2, 3] or [[1], [2], [3]]

if (len(pk.unique(y)) > 2) or (len(y.shape) >= 2 and len(y[0]) > 1):
if (len(np.unique(y)) > 2) or (len(y.shape) >= 2 and len(y[0]) > 1):
return "multiclass" + suffix # [1, 2, 3] or [[1., 2., 3]] or [[1, 2]]
else:
return "binary" # [1, 2] or [["a"], ["b"]]


def _unique_multiclass(y):
if hasattr(y, "__array__"):
return pk.unique(asarray(y))
return np.unique(asarray(y))
else:
return set(y)

Expand Down Expand Up @@ -264,7 +264,7 @@ def predict(self, X):
X = self._check_X(X)
jll = self._joint_log_likelihood(X)

return pk.index(self.classes_, pk.argmax(jll, axis=1))
return self.classes_[np.argmax(np.array(jll), axis=1)]

def predict_log_proba(self, X):
"""
Expand All @@ -285,7 +285,7 @@ def predict_log_proba(self, X):
jll = self._joint_log_likelihood(X)
# normalize by P(x) = P(f_1, ..., f_n)
# log_prob_x = logsumexp(jll, axis=1)
# return jll - pk.transpose(pk.atleast_2d())
# return jll - np.transpose(pk.atleast_2d())

def predict_proba(self, X):
"""
Expand All @@ -301,7 +301,7 @@ def predict_proba(self, X):
the model. The columns correspond to the classes in sorted
order, as they appear in the attribute :term:`classes_`.
"""
return pk.exp(self.predict_log_proba(X))
return np.exp(self.predict_log_proba(X))


class GaussianNB(_BaseNB):
Expand Down Expand Up @@ -366,7 +366,7 @@ class labels known to the classifier.
>>> print(clf.predict([[-0.8, -1]]))
[1]
>>> clf_pf = GaussianNB()
>>> clf_pf.partial_fit(X, Y, pk.unique(Y))
>>> clf_pf.partial_fit(X, Y, np.unique(Y))
GaussianNB()
>>> print(clf_pf.predict([[-0.8, -1]]))
[1]
Expand Down Expand Up @@ -397,7 +397,7 @@ def fit(self, X, y, sample_weight=None):
y = asarray(self._validate_data(y=y))

return self._partial_fit(
X, y, pk.unique(y), _refit=True, sample_weight=sample_weight
X, y, np.unique(y), _refit=True, sample_weight=sample_weight
)

def _check_X(self, X):
Expand Down Expand Up @@ -440,12 +440,14 @@ def _update_mean_variance(n_past, mu, var, X, sample_weight=None):
# Compute (potentially weighted) mean and variance of new datapoints
if sample_weight is not None:
n_new = float(sample_weight.sum())
new_mu = pk.average(X, axis=0, weights=sample_weight)
new_var = pk.average((X - new_mu) ** 2, axis=0, weights=sample_weight)
new_mu = np.average(np.array(X), axis=0, weights=sample_weight)
new_var = np.average(
np.array(X - new_mu) ** 2, axis=0, weights=sample_weight
)
else:
n_new = X.shape[0]
new_var = pk.var(X, axis=0)
new_mu = pk.mean(X, axis=0)
new_var = np.var(np.array(X), axis=0)
new_mu = np.mean(np.array(X), axis=0)

if n_past == 0:
return new_mu, new_var
Expand Down Expand Up @@ -534,7 +536,7 @@ def _partial_fit(self, X, y, classes=None, _refit=False, sample_weight=None):
# will cause numerical errors. To address this, we artificially
# boost the variance by epsilon, a small fraction of the standard
# deviation of the largest dimension.
self.epsilon_ = self.var_smoothing * pk.find_max(pk.var(X, axis=0))
self.epsilon_ = self.var_smoothing * pk.find_max(np.var(np.array(X), axis=0))
Comment thread
nayyirahsan marked this conversation as resolved.
Outdated

if first_call:
# This is the first call to partial_fit:
Expand Down Expand Up @@ -569,13 +571,13 @@ def _partial_fit(self, X, y, classes=None, _refit=False, sample_weight=None):

classes = self.classes_

unique_y = pk.unique(y)
unique_y_in_classes = pk.in1d(unique_y, classes)
unique_y = np.unique(y)
unique_y_in_classes = np.in1d(unique_y, classes)

if not pk.all(unique_y_in_classes):
raise ValueError(
"The target label(s) %s in y do not exist in the initial classes %s"
% (unique_y[pk.logical_not(unique_y_in_classes)], classes)
% (unique_y[np.logical_not(unique_y_in_classes)], classes)
)

for y_i in unique_y:
Expand All @@ -602,7 +604,7 @@ def _partial_fit(self, X, y, classes=None, _refit=False, sample_weight=None):
# Update if only no priors is provided
if self.priors is None:
# Empirical prior, with sample_weight taken into account
self.class_prior_ = pk.divide(self.class_count_, pk.sum(self.class_count_))
self.class_prior_ = np.divide(self.class_count_, pk.sum(self.class_count_))

return self

Expand All @@ -611,15 +613,15 @@ def _joint_log_likelihood(self, X):
total_classes = reduce(lambda a, b: a * b, self.classes_.shape, 1)

for i in range(total_classes):
jointi = pk.log(self.class_prior_[i])
jointi = np.log(self.class_prior_[i])

n_ij = -0.5 * pk.sum(pk.log(pk.multiply(self.var_[i, :], 2.0 * pi)))
n_ij = pk.add(
pk.negative(
pk.multiply(
n_ij = -0.5 * pk.sum(np.log(np.multiply(self.var_[i, :], 2.0 * pi)))
n_ij = np.add(
np.negative(
np.multiply(
pk.sum(
pk.divide(
pk.power(pk.add(X, pk.negative(self.theta_[i, :])), 2),
np.divide(
np.power(np.add(X, np.negative(self.theta_[i, :])), 2),
self.var_[i, :],
),
1,
Expand All @@ -630,9 +632,9 @@ def _joint_log_likelihood(self, X):
n_ij,
)

joint_log_likelihood.append(pk.add(n_ij, jointi))
joint_log_likelihood.append(np.add(n_ij, jointi))

joint_log_likelihood = pk.transpose(asarray(joint_log_likelihood))
joint_log_likelihood = np.transpose(asarray(joint_log_likelihood))
return joint_log_likelihood


Expand Down
60 changes: 0 additions & 60 deletions pykokkos/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,62 +17,6 @@
set_device_id,
)

from pykokkos.lib.ufuncs import (
reciprocal,
log,
log2,
log10,
log1p,
sqrt,
sign,
add,
copyto,
subtract,
dot,
multiply,
matmul,
np_matmul,
divide,
negative,
positive,
power,
fmod,
square,
greater,
logaddexp,
true_divide,
logaddexp2,
floor_divide,
sin,
cos,
tan,
tanh,
logical_and,
logical_or,
logical_xor,
logical_not,
fmax,
fmin,
exp,
exp2,
argmax,
unique,
var,
in1d,
mean,
hstack,
transpose,
index,
isinf,
isnan,
equal,
isfinite,
round,
trunc,
ceil,
floor,
broadcast_view,
)
from pykokkos.lib.info import iinfo, finfo
from pykokkos.lib.create import zeros, zeros_like, ones, ones_like, full, full_like
from pykokkos.lib.manipulate import reshape, ravel, expand_dims
Expand All @@ -89,10 +33,6 @@
from pykokkos.lib.constants import e, pi, inf, nan
from pykokkos.interface.views import astype

__array_api_version__ = "2021.12"

__all__ = ["__array_api_version__"]

runtime_singleton.runtime = Runtime()

import weakref
Expand Down
14 changes: 8 additions & 6 deletions pykokkos/interface/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,8 +503,6 @@ def _get_type(self, dtype: Union[DataType, type]) -> Optional[DataType]:
return None

def __eq__(self, other):
# avoid circular import with scoped import
from pykokkos.lib.ufuncs import equal

if isinstance(other, float):
new_other = pk.View((), dtype=pk.double)
Expand Down Expand Up @@ -539,7 +537,10 @@ def __eq__(self, other):
new_other = other
else:
raise ValueError("unexpected types!")
return equal(self, new_other)
result_np = np.equal(np.array(self), np.array(new_other))
result = pk.View(result_np.shape, dtype=pk.bool)
result[:] = result_np
return result

def __hash__(self):
try:
Expand Down Expand Up @@ -667,8 +668,6 @@ def _get_base_view(self, parent_view: Union[Subview, View]) -> View:
return base_view

def __eq__(self, other):
# avoid circular import with scoped import
from pykokkos.lib.ufuncs import equal

if isinstance(other, float):
new_other = pk.View((), dtype=pk.double)
Expand Down Expand Up @@ -703,7 +702,10 @@ def __eq__(self, other):
new_other = other
else:
raise ValueError("unexpected types!")
return equal(self, new_other)
result_np = np.equal(np.array(self), np.array(new_other))
result = pk.View(result_np.shape, dtype=pk.bool)
result[:] = result_np
return result

def __add__(self, other):
if isinstance(other, float):
Expand Down
Loading
Loading