Skip to content
Merged
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
7 changes: 2 additions & 5 deletions python/cuml/cuml/internals/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2025, NVIDIA CORPORATION.
# SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
#
# TODO: remove in 26.04
import cuml.internals.memory_utils

from cuml.internals.base import Base, get_handle
from cuml.internals.internals import GraphBasedDimRedCallback
from cuml.internals.outputs import (
Expand Down
20 changes: 0 additions & 20 deletions python/cuml/cuml/internals/memory_utils.py

This file was deleted.

42 changes: 13 additions & 29 deletions python/cuml/cuml/manifold/umap/umap.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -560,25 +560,8 @@ cdef init_params(self, lib.UMAPParams &params, n_rows, is_sparse=False, is_fit=T
)

build_kwds = self.build_kwds or {}
if "nnd_n_clusters" in build_kwds:
warnings.warn(
"`nnd_n_clusters` was deprecated in 26.02 and will be changed to "
"`knn_n_clusters` in 26.04."
)
n_clusters = build_kwds.get("nnd_n_clusters", 1)
else:
n_clusters = build_kwds.get("knn_n_clusters", 1)
if "nnd_overlap_factor" in build_kwds:
warnings.warn(
"`nnd_overlap_factor` was deprecated in 26.02 and will be changed to "
"`knn_overlap_factor` in 26.04."
)
overlap_factor = build_kwds.get("nnd_overlap_factor", 2)
else:
overlap_factor = build_kwds.get("knn_overlap_factor", 2)

params.build_params.n_clusters = n_clusters
params.build_params.overlap_factor = overlap_factor
n_clusters = build_kwds.get("knn_n_clusters", 1)
overlap_factor = build_kwds.get("knn_overlap_factor", 2)

if n_clusters < 1:
raise ValueError(f"Expected `knn_n_clusters >= 1`, got {n_clusters}")
Expand All @@ -588,19 +571,24 @@ cdef init_params(self, lib.UMAPParams &params, n_rows, is_sparse=False, is_fit=T
f"knn_overlap_factor ({overlap_factor})`"
)

# Supported metrics: L2Expanded, L2SqrtExpanded, CosineExpanded, InnerProduct
all_neighbors_supported_metrics = ['l2', 'euclidean', 'sqeuclidean', 'cosine',
'inner_product']
if (build_algo == "brute_force_knn" and
n_clusters > 1 and
self.metric.lower() not in all_neighbors_supported_metrics):
all_neighbors_supported_metrics = [
'l2', 'euclidean', 'sqeuclidean', 'cosine', 'inner_product'
]
if (
build_algo == "brute_force_knn" and
n_clusters > 1 and
self.metric.lower() not in all_neighbors_supported_metrics
):
warnings.warn(
f"metric='{self.metric}' is not supported for batched knn build with "
f"knn_n_clusters > 1. Supported metrics are: {all_neighbors_supported_metrics}. "
f"The knn_n_clusters parameter will be ignored and regular brute force knn "
f"(without batching) will be used instead."
)

params.build_params.n_clusters = n_clusters
params.build_params.overlap_factor = overlap_factor

if build_algo == "brute_force_knn":
params.build_algo = lib.graph_build_algo.BRUTE_FORCE_KNN
else:
Expand Down Expand Up @@ -835,10 +823,6 @@ class UMAP(Base, InteropMixin, CMajorInputTagMixin, SparseInputTagMixin):
memory usage. This is independent from knn_overlap_factor as long as
'knn_overlap_factor' < 'knn_n_clusters'.

.. deprecated:: 26.02
The `nnd_n_clusters` and `nnd_overlap_factor` was deprecated in 26.02 and
will be changed to `knn_n_clusters` and `knn_overlap_factor` in 26.04.

device_ids : list[int], "all", or None, default=None
The device IDs to use during fitting (only used when
`build_algo=nn_descent` and `knn_n_clusters > 1`). May be a list of
Expand Down
65 changes: 0 additions & 65 deletions python/cuml/cuml/model_selection/_split.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#
from __future__ import annotations

import warnings
from abc import ABC, abstractmethod

import cudf
Expand All @@ -20,7 +19,6 @@

def train_test_split(
*arrays,
y="deprecated",
test_size=None,
train_size=None,
random_state=None,
Expand All @@ -37,14 +35,6 @@ def train_test_split(
arrays, numpy arrays, pandas DataFrames/Series, or any array-like
objects with a shape attribute.

y : str, default="deprecated"
The name of the column that contains the target variable.

.. deprecated:: 26.02
The ``y`` parameter is deprecated and will be removed in 26.04.
Extract the column manually:
``X, y = df.drop('col', axis=1), df['col']``

test_size : float or int, default=None
If float, should be between 0.0 and 1.0 and represent the proportion
of the dataset to include in the test split. If int, represents the
Expand Down Expand Up @@ -87,65 +77,10 @@ def train_test_split(
>>> X_train, X_test, y_train, y_test = train_test_split(
... X, y, test_size=0.2, random_state=42
... )

Notes
-----
.. versionchanged:: 26.02
The names and the order of the optional keyword arguments was changed to
match the scikit-learn equivalent function. The ``y`` parameter was
deprecated (see above).

.. versionchanged:: 26.02
Output types now consistently match input types. Previously, pandas
inputs were converted to cudf outputs. Now pandas inputs return pandas
outputs, cudf inputs return cudf outputs.
"""
if len(arrays) == 0:
raise ValueError("At least one array required as input")

# Handle deprecated y parameter usage
# Case 1: y passed as keyword: train_test_split(df, y=...)
# Case 2: column name passed as second positional arg: train_test_split(df, "col")
y_is_column_name_positional = len(arrays) == 2 and isinstance(
arrays[1], str
)
# Use isinstance check to avoid ambiguous truth value with array-like y
y_was_passed = not (isinstance(y, str) and y == "deprecated")

if y_was_passed or y_is_column_name_positional:
warnings.warn(
"The explicit 'y' parameter is deprecated and will be "
"removed in 26.04. Extract the column manually: "
"X, y = df.drop('col', axis=1), df['col']",
FutureWarning,
stacklevel=2,
)

if y_is_column_name_positional:
# User passed: train_test_split(df, "colname")
X = arrays[0]
col_name = arrays[1]
X, y = X.drop(col_name, axis=1), X[col_name]
arrays = (X, y)
elif isinstance(y, str):
# User passed: train_test_split(df, y="colname")
X = arrays[0]
if not hasattr(X, "drop"):
raise TypeError(
"X must be a DataFrame when y is a column name string"
)
X, y = X.drop(y, axis=1), X[y]
arrays = (X, y)
else:
# User passed: train_test_split(X, y=array)
if len(arrays) > 1:
raise ValueError(
"Cannot use deprecated 'y' parameter with multiple "
"positional arrays. Pass all arrays as positional "
"arguments instead: train_test_split(X, y, ...)"
)
arrays = (arrays[0], y)

# Validate arrays have consistent first dimension
n_samples = arrays[0].shape[0]
for i, arr in enumerate(arrays[1:], 1):
Expand Down
42 changes: 2 additions & 40 deletions python/cuml/cuml/svm/svm_base.pyx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
#
import warnings

import cupy as cp
import cupyx.scipy.sparse
import numpy as np
Expand Down Expand Up @@ -137,19 +134,6 @@ cdef class _SVMModel:
return support, support_vectors, dual_coef, intercept


class TotalIters(int):
"""Indicates the maximum number of total iterations the solver may run.

.. deprecated:: 26.02

TotalIters was deprecated in 26.02 and will be removed in 26.04.
The `max_iter` parameter now always places a limit on total iterations,
wrapping with `TotalIters` is no longer necessary.
"""
def __repr__(self):
return f"TotalIters({int(self)})"


class SVMBase(Base,
InteropMixin,
FMajorInputTagMixin,
Expand Down Expand Up @@ -200,11 +184,6 @@ class SVMBase(Base,
}

def _params_to_cpu(self):
if isinstance(self.max_iter, TotalIters):
max_iter = int(self.max_iter)
else:
max_iter = self.max_iter

return {
"kernel": self.kernel,
"degree": self.degree,
Expand All @@ -213,7 +192,7 @@ class SVMBase(Base,
"tol": self.tol,
"C": self.C,
"cache_size": self.cache_size,
"max_iter": max_iter,
"max_iter": self.max_iter,
"epsilon": self.epsilon,
}

Expand Down Expand Up @@ -418,21 +397,8 @@ class SVMBase(Base,
param.verbosity = self._verbose_level
param.epsilon = self.epsilon
param.svmType = lib.SvmType.C_SVC if is_classifier else lib.SvmType.EPSILON_SVR

param.max_outer_iter = -1
if isinstance(self.max_iter, TotalIters):
warnings.warn(
(
"Passing `TotalIters` to `max_iter` was deprecated in 26.02 "
"and will be removed in 26.04. `max_iter` now always places a "
"limit on total iterations, please pass an integer directly "
"instead of wrapping with `TotalIters`."
),
FutureWarning,
)
param.max_iter = int(self.max_iter)
else:
param.max_iter = self.max_iter
param.max_iter = self.max_iter

handle = get_handle(model=self)
cdef handle_t* handle_ = <handle_t*><size_t>handle.getHandle()
Expand Down Expand Up @@ -679,7 +645,3 @@ class SVMBase(Base,
handle.sync()

return out


# Add TotalIters to the SVC/SVR class for easier access
SVMBase.TotalIters = TotalIters
11 changes: 0 additions & 11 deletions python/cuml/tests/test_reflection.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,6 @@ def returns_array_one_arg(n):
return cp.ones(n)


def test_deprecated_memory_utils():
for name in ["set_global_output_type", "using_output_type"]:
with pytest.warns(FutureWarning, match=name):
func = getattr(cuml.internals.memory_utils, name)
assert func is getattr(cuml, name)

# Unknown attributes error
with pytest.raises(AttributeError, match="not_a_real_attr"):
cuml.internals.memory_utils.not_a_real_attr


def test_set_global_output_type():
gs = GlobalSettings()
assert gs.output_type is None
Expand Down
6 changes: 0 additions & 6 deletions python/cuml/tests/test_svm.py
Original file line number Diff line number Diff line change
Expand Up @@ -613,12 +613,6 @@ def test_max_iter_n_iter(classifier):
model = cls(max_iter=5).fit(X, y)
assert (model.n_iter_.item() if classifier else model.n_iter_) == 5

# Using TotalIters results in the same behavior, but warns
model = cls(max_iter=cls.TotalIters(5))
with pytest.warns(FutureWarning, match="TotalIters"):
model.fit(X, y)
assert (model.n_iter_.item() if classifier else model.n_iter_) == 5


def test_svc_multiclass_n_iter():
X, y = make_classification(random_state=42, n_classes=3, n_informative=4)
Expand Down
Loading
Loading