28 for (int64_t i = 1; i <= k; ++i) {
29 result = result *
static_cast<double>(n - k + i) /
static_cast<double>(i);
41 BinomialCoefficient(n, coalition_size) *
static_cast<double>(coalition_size) *
static_cast<double>(n - coalition_size);
42 return static_cast<float>(
static_cast<double>(n - 1) / denominator);
82 throw std::invalid_argument(
"KernelSHAP::explain: input and baseline must have the same numel");
84 const int64_t n = input.
numel();
85 if (n < 1 || n > 20) {
86 throw std::invalid_argument(
"KernelSHAP::explain: input feature count must be in [1, 20]");
90 const std::vector<float> baseline_values = baseline.
to_host_vector();
92 std::vector<float> z_values(
static_cast<size_t>(n));
94 auto coalition_value = [&](uint64_t mask) {
95 for (int64_t i = 0; i < n; ++i) {
96 bool active = ((mask >> i) & 1u) != 0;
97 const auto idx =
static_cast<size_t>(i);
98 z_values[idx] = active ? input_values[idx] : baseline_values[idx];
105 const float f_baseline = coalition_value(0);
106 const uint64_t full_mask = (n == 64) ? ~0ULL : ((1ULL << n) - 1);
107 const float total_diff = coalition_value(full_mask) - f_baseline;
109 std::vector<float> phi(
static_cast<size_t>(n), 0.0f);
114 std::vector<std::vector<float>> reduced_samples;
115 std::vector<float> reduced_targets;
116 std::vector<float> weights;
118 for (uint64_t mask = 1; mask < full_mask; ++mask) {
119 int64_t coalition_size = 0;
120 for (int64_t i = 0; i < n; ++i) {
121 if ((mask >> i) & 1u) {
125 bool z_last = ((mask >> (n - 1)) & 1u) != 0;
126 float value = coalition_value(mask) - f_baseline;
127 float reduced_target = value - (z_last ? total_diff : 0.0f);
129 std::vector<float> reduced_row(
static_cast<size_t>(n - 1));
130 for (int64_t i = 0; i < n - 1; ++i) {
131 bool z_i = ((mask >> i) & 1u) != 0;
132 reduced_row[
static_cast<size_t>(i)] = (z_i ? 1.0f : 0.0f) - (z_last ? 1.0f : 0.0f);
135 reduced_samples.push_back(std::move(reduced_row));
136 reduced_targets.push_back(reduced_target);
140 std::vector<float> reduced_phi =
143 float sum_reduced = 0.0f;
144 for (int64_t i = 0; i < n - 1; ++i) {
145 phi[
static_cast<size_t>(i)] = reduced_phi[
static_cast<size_t>(i)];
146 sum_reduced += reduced_phi[
static_cast<size_t>(i)];
148 phi[
static_cast<size_t>(n - 1)] = total_diff - sum_reduced;
153 return Attribution{
"kernel_shap", std::move(values), {{
"target_index", std::to_string(target_index)}}};
PULSATRIX_ASSERT – debug-only invariant check for programmer errors, distinct from throw (used for ca...
First-class explanation result type – values, method, and metadata together.
Vendor-agnostic compute/memory backend. CPUBackend, CUDABackend (Phase 1.5), and HIPBackend (Phase 1....
Definition device_backend.hpp:219
Approximates Shapley values via full coalition enumeration + SHAP-kernel-weighted linear regression,...
Definition kernel_shap.hpp:65
Attribution explain(const std::function< Tensor(const Tensor &)> &predict, const Tensor &input, const Tensor &baseline, int64_t target_index, DeviceBackend *backend) const
Computes Shapley value approximations for one output index.
Definition kernel_shap.hpp:77
N-dimensional tensor. Owns its data buffer exclusively; a DeviceBackend* is injected (not owned) – th...
Definition tensor.hpp:29
DeviceType device() const
Which device this tensor's buffer conceptually resides on.
Definition tensor.hpp:122
int64_t numel() const
Total element count – shape().numel().
Definition tensor.hpp:116
const Shape & shape() const
This tensor's shape.
Definition tensor.hpp:113
float read_element(int64_t flat_index) const
Reads one element to the host through the owning backend, on any device.
std::vector< float > to_host_vector() const
Copies the whole buffer to a host vector through the owning backend, on any device.
Abstract interface isolating vendor-specific memory/compute operations from Tensor/ComputationGraph.
float ShapKernelWeight(int64_t n, int64_t coalition_size)
The SHAP kernel pi(z') = (n-1) / [C(n,|z'|) * |z'| * (n-|z'|)], for 1 <= |z'| <= n-1.
Definition kernel_shap.hpp:39
double BinomialCoefficient(int64_t n, int64_t k)
Binomial coefficient C(n,k), computed iteratively to avoid factorial overflow.
Definition kernel_shap.hpp:26
DeviceBackend * backend_beside(const Tensor &like, DeviceBackend *backend)
The backend to allocate a tensor through that must live beside like.
Definition attribution.hpp:49
Definition acquisition_functions.hpp:16
std::vector< float > fit_weighted_linear_regression(const std::vector< std::vector< float > > &samples, const std::vector< float > &targets, const std::vector< float > &weights, float l2_lambda)
Fits w* = argmin_w sum_i weight_i*(target_i - w^T sample_i)^2 + l2_lambda*||w||^2 via the normal equa...
Definition weighted_linear_regression.hpp:38
An explanation result: the raw attribution values, the method that produced them, and any relevant me...
Definition attribution.hpp:23
N-dimensional tensor – owns a buffer via DeviceBackend*, RAII (Rule of Five).
Weighted least squares via normal equations – the shared fitting primitive Phase 3's LIME and KernelS...