1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! Learned (differentiable) kernel composition.
//!
//! This module provides a differentiable mixture over a library of base
//! kernels. Given a library `{K_1, ..., K_n}` and a vector of trainable
//! logits `w = [w_1, ..., w_n]`, the mixture kernel is defined as
//!
//! ```text
//! p = softmax(w),
//! K_mix(x, y) = sum_i p_i * K_i(x, y).
//! ```
//!
//! The mixture is gradient-aware with respect to the logits. Using the
//! Jacobian of softmax `d p_j / d w_i = p_j * (delta_{ij} - p_i)`, the
//! gradient of the mixture with respect to logit `w_i` reduces to the
//! numerically clean identity
//!
//! ```text
//! d K_mix / d w_i = p_i * (K_i - K_mix).
//! ```
//!
//! This identity is implemented exactly in [`LearnedMixtureKernel::gradient_wrt_logits`]
//! and unit-tested against a finite-difference reference.
//!
//! # Scope (v0.2.0 preview)
//!
//! * Differentiability is w.r.t. mixture logits only — base kernel
//! hyperparameters are treated as frozen.
//! * Weights are the softmax of logits; they are always strictly positive
//! and sum to 1, so the mixture is PSD whenever every base kernel is PSD.
//! * The [`TrainableKernelMixture`] adapter exposes a single gradient step
//! (take a gradient, update logits) — the optimizer loop lives with the
//! caller (`tensorlogic-train`).
//!
//! # Example
//!
//! ```rust
//! use std::sync::Arc;
//! use tensorlogic_sklears_kernels::{
//! learned_composition::{LearnedMixtureBuilder, LearnedMixtureKernel},
//! LinearKernel, RbfKernel, RbfKernelConfig,
//! };
//!
//! let kernel: LearnedMixtureKernel = LearnedMixtureBuilder::new()
//! .push_kernel(Arc::new(LinearKernel::new()))
//! .push_kernel(Arc::new(
//! RbfKernel::new(RbfKernelConfig::new(0.5)).expect("valid gamma"),
//! ))
//! .build()
//! .expect("non-empty library");
//!
//! let x = vec![1.0, 2.0];
//! let y = vec![0.5, 1.0];
//! let _value = kernel.evaluate(&x, &y).expect("compatible dims");
//! ```
pub use LearnedMixtureBuilder;
pub use LearnedMixtureKernel;
pub use TrainableKernelMixture;