From 09eba78069061518a50a2ee761cc92517e22bf45 Mon Sep 17 00:00:00 2001 From: DerWeh Date: Sun, 15 Jun 2025 23:23:50 +0200 Subject: [PATCH 1/4] MNT: sort and fix imports (ruff) Signed-off-by: DerWeh --- python/interpret-core/interpret/utils/_compressed_dataset.py | 2 +- python/interpret-core/interpret/utils/_native.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/python/interpret-core/interpret/utils/_compressed_dataset.py b/python/interpret-core/interpret/utils/_compressed_dataset.py index 16d36fa59..e50cc1be3 100644 --- a/python/interpret-core/interpret/utils/_compressed_dataset.py +++ b/python/interpret-core/interpret/utils/_compressed_dataset.py @@ -5,7 +5,7 @@ import numpy as np -from ._clean_x import unify_columns, categorical_encode +from ._clean_x import categorical_encode, unify_columns from ._native import Native _log = logging.getLogger(__name__) diff --git a/python/interpret-core/interpret/utils/_native.py b/python/interpret-core/interpret/utils/_native.py index e181fe645..8323e0531 100644 --- a/python/interpret-core/interpret/utils/_native.py +++ b/python/interpret-core/interpret/utils/_native.py @@ -8,7 +8,6 @@ import platform import struct import sys -import math from contextlib import AbstractContextManager from math import prod From 64313efdae5bfdec0d49ad78d12997255f8f2ea6 Mon Sep 17 00:00:00 2001 From: DerWeh Date: Sun, 15 Jun 2025 23:24:18 +0200 Subject: [PATCH 2/4] BUG: use datatype matchin native C++ code Signed-off-by: DerWeh --- .../interpret-core/interpret/utils/_compressed_dataset.py | 6 +++--- python/interpret-core/interpret/utils/_native.py | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/python/interpret-core/interpret/utils/_compressed_dataset.py b/python/interpret-core/interpret/utils/_compressed_dataset.py index e50cc1be3..cec04c9bc 100644 --- a/python/interpret-core/interpret/utils/_compressed_dataset.py +++ b/python/interpret-core/interpret/utils/_compressed_dataset.py @@ -6,7 +6,7 @@ import numpy as np from ._clean_x import categorical_encode, unify_columns -from ._native import Native +from ._native import Native, _boolebm_t _log = logging.getLogger(__name__) @@ -81,7 +81,7 @@ def bin_native( n_bytes += native.measure_feature( n_bins, - np.count_nonzero(X_col) != len(X_col), + _boolebm_t(np.count_nonzero(X_col) != len(X_col)), bad is not None, feature_type == "nominal", X_col, @@ -134,7 +134,7 @@ def bin_native( native.fill_feature( n_bins, - np.count_nonzero(X_col) != len(X_col), + _boolebm_t(np.count_nonzero(X_col) != len(X_col)), bad is not None, feature_type == "nominal", X_col, diff --git a/python/interpret-core/interpret/utils/_native.py b/python/interpret-core/interpret/utils/_native.py index 8323e0531..36bd3e2a0 100644 --- a/python/interpret-core/interpret/utils/_native.py +++ b/python/interpret-core/interpret/utils/_native.py @@ -15,6 +15,8 @@ _log = logging.getLogger(__name__) +_boolebm_t = np.int32 + class Native: # see notes in libebm.h on the maximum representable int64 in float64 format From 6897a1c428885a17064a5a8315e0c11bdb32e281 Mon Sep 17 00:00:00 2001 From: DerWeh Date: Tue, 17 Jun 2025 07:33:17 +0200 Subject: [PATCH 3/4] MNT: run ruff format Signed-off-by: DerWeh --- python/interpret-core/tests/glassbox/ebm/test_ebm_exact.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/interpret-core/tests/glassbox/ebm/test_ebm_exact.py b/python/interpret-core/tests/glassbox/ebm/test_ebm_exact.py index c0034c356..3c96bde77 100644 --- a/python/interpret-core/tests/glassbox/ebm/test_ebm_exact.py +++ b/python/interpret-core/tests/glassbox/ebm/test_ebm_exact.py @@ -58,7 +58,7 @@ def test_identical_ebm(): seed += 1 - expected = 3.293830243001896e+19 + expected = 3.293830243001896e19 assert fingerprint == expected From 04483ceea5cb5f08ad48f474a1b941ed9dbe5045 Mon Sep 17 00:00:00 2001 From: DerWeh Date: Tue, 17 Jun 2025 07:51:02 +0200 Subject: [PATCH 4/4] ENH: ensure correct boolean types in nativ calls Signed-off-by: DerWeh --- .../interpret/utils/_compressed_dataset.py | 6 ++--- .../interpret-core/interpret/utils/_native.py | 22 ++++++++++++------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/python/interpret-core/interpret/utils/_compressed_dataset.py b/python/interpret-core/interpret/utils/_compressed_dataset.py index cec04c9bc..e50cc1be3 100644 --- a/python/interpret-core/interpret/utils/_compressed_dataset.py +++ b/python/interpret-core/interpret/utils/_compressed_dataset.py @@ -6,7 +6,7 @@ import numpy as np from ._clean_x import categorical_encode, unify_columns -from ._native import Native, _boolebm_t +from ._native import Native _log = logging.getLogger(__name__) @@ -81,7 +81,7 @@ def bin_native( n_bytes += native.measure_feature( n_bins, - _boolebm_t(np.count_nonzero(X_col) != len(X_col)), + np.count_nonzero(X_col) != len(X_col), bad is not None, feature_type == "nominal", X_col, @@ -134,7 +134,7 @@ def bin_native( native.fill_feature( n_bins, - _boolebm_t(np.count_nonzero(X_col) != len(X_col)), + np.count_nonzero(X_col) != len(X_col), bad is not None, feature_type == "nominal", X_col, diff --git a/python/interpret-core/interpret/utils/_native.py b/python/interpret-core/interpret/utils/_native.py index 36bd3e2a0..01c673935 100644 --- a/python/interpret-core/interpret/utils/_native.py +++ b/python/interpret-core/interpret/utils/_native.py @@ -15,7 +15,13 @@ _log = logging.getLogger(__name__) -_boolebm_t = np.int32 + +def _boolebm(val): + """Convert `bool` to `np.int32` used by libebm to represents `bool`.""" + if not isinstance(val, (bool, np.bool_)): + msg = f"Native EBM functions expect boolean, got f{type(val)}" + raise TypeError(msg) + return np.int32(val) class Native: @@ -575,7 +581,7 @@ def cut_quantile(self, X_col, min_samples_bin, is_rounded, max_cuts): X_col.shape[0], Native._make_pointer(X_col, np.float64), min_samples_bin, - is_rounded, + _boolebm(is_rounded), ct.byref(count_cuts), Native._make_pointer(cuts, np.float64), ) @@ -658,9 +664,9 @@ def measure_dataset_header(self, n_features, n_weights, n_targets): def measure_feature(self, n_bins, is_missing, is_unseen, is_nominal, bin_indexes): n_bytes = self._unsafe.MeasureFeature( n_bins, - is_missing, - is_unseen, - is_nominal, + _boolebm(is_missing), + _boolebm(is_unseen), + _boolebm(is_nominal), len(bin_indexes), Native._make_pointer(bin_indexes, np.int64), ) @@ -712,9 +718,9 @@ def fill_feature( ): return_code = self._unsafe.FillFeature( n_bins, - is_missing, - is_unseen, - is_nominal, + _boolebm(is_missing), + _boolebm(is_unseen), + _boolebm(is_nominal), len(bin_indexes), Native._make_pointer(bin_indexes, np.int64), dataset.nbytes,