Skip to main content

TasteConfig

Struct TasteConfig 

Source
pub struct TasteConfig {
    pub n_features: usize,
    pub k_styles: usize,
    pub n_stars: usize,
    pub theta_prior_std: Option<f64>,
    pub recency_half_life: Option<f64>,
    pub fused: Vec<Vec<usize>>,
    pub fused_rho: Option<f64>,
}
Expand description

Model configuration.

Fields§

§n_features: usize

Feature dimension (after standardization).

§k_styles: usize

Number of style components (mixture of linear experts).

§n_stars: usize

Number of star categories (ratings 0..n_stars).

§theta_prior_std: Option<f64>

Prior std of each θ coordinate. None1/√n_features.

§recency_half_life: Option<f64>

Recency half-life in observations: an observation h places back in the log weighs 0.5^(h / half_life) in the likelihood, so old taste fades as new evidence arrives. None → no forgetting.

§fused: Vec<Vec<usize>>

Groups of φ coordinates that measure one perceptual thing, and so share a latent per-style mean instead of being independent draws.

Empty by default, which is the flat prior this model has always had. The caller supplies indices because only it knows the feature names; see SessionConfig for the brightness group it fills in.

§Why a fused prior rather than dropping a column

rolloff_mean, zcr_mean and centroid_mean are three genuine measurements of brightness, and over 1200 prior draws they carry VIFs of ~16.9 / ~9.7 / ~5.9 — rolloff_mean is the worst-conditioned coordinate in φ. Dropping any of them discards real signal: they disagree about which brightness (spectral tilt, high-frequency energy, and waveform sign changes are not the same statistic), and a listener who prefers one shading over another is expressing something the survivors cannot represent alone.

A shared mean says what is actually true: these coordinates are correlated a priori, so evidence about one is partial evidence about the others. The model can still separate them when the data insist — Self::sigma_within is what buys that freedom — but with few duels it pools them instead of splitting an ill-conditioned ridge three ways at random, which is the failure mode a high VIF names.

§fused_rho: Option<f64>

How strongly a fused group’s coordinates are correlated a priori, in [0, 1). None → 0.0, i.e. off — see Self::fused_rho for the measurement that switched it off.

Parameterized as a correlation rather than as an inner SD so that the marginal prior on each coordinate is unchanged: with σ_μ = σ_θ√ρ and σ_within = σ_θ√(1−ρ), every θ still has prior variance σ_θ² and only the covariance between group members moves. At ρ = 0 the program is exactly the flat one.

That distinction is not cosmetic. An earlier version of this used σ_within = σ_θ/2 with σ_μ = σ_θ, which quietly inflated the marginal variance to 1.25 σ_θ² — so it changed the prior’s scale as well as its correlation, and any measurement of “does fusing help” was really measuring two changes at once.

Implementations§

Source§

impl TasteConfig

Source

pub fn linear(n_features: usize) -> Self

A K=1 config for the given feature dimension.

Source

pub fn mixture(n_features: usize, k_styles: usize) -> Self

A K-style mixture config for the given feature dimension.

Source

pub fn fused_rho(&self) -> f64

Prior correlation within a fused group, clamped to [0, 0.99].

§Why this ships at zero

The machinery is implemented, correct and switched off, the way RefineKeep::Best and Acquisition::Thompson are kept after losing. Two gates were run and they disagreed, which is the finding.

Swept against the always-on closed-loop gate — five seeds, a real posterior fit against a synthetic listener — fusing helps:

rho    mean posterior/truth r
0.00   0.657   (the flat prior, reproduced exactly)
0.25   0.702   <- best
0.50   0.644
0.75   fails the per-seed floor (seed 0x2 at 0.437)

Measured on the climb at rho = 0.25 — 48 paired seeds, the gate that asks what the pool is actually worth to the listener — it hurts, and not marginally:

paired (fused − flat)   10% trimmed  −0.579 ± 0.188   (−3.09 se)
                        median       −0.726
                        sign         16 better / 32 worse, p = 0.029
                        climbed      41/48 → 38/48

Both are true, and the reason is that they measure different things. The closed-loop gate scores θ recovery, where pooling an ill-conditioned ridge is a real regularizer. The climb scores the true utility of the pool the search delivers, and there the pooling is a bias: this listener’s taste puts 2.0 on centroid_mean and exactly 0 on the other two, so shrinking them together drags the one coefficient that matters toward two that do not, and the search aims worse.

That is the general warning, and it is worth more than the feature. A VIF says the three brightness coordinates move together across patches — a fact about φ. Fusing their coefficients asserts that a listener’s preferences about them move together — a fact about people, which does not follow from the first and was not measured.

Re-open this if the listener model ever gains a reason to believe preferences follow φ’s correlation structure; the sweep and both gates are here to re-run.

Source

pub fn sigma_group(&self) -> f64

SD of a fused group’s latent mean: σ_θ√ρ.

Source

pub fn sigma_within(&self) -> f64

SD of a fused coordinate about its group mean: σ_θ√(1−ρ). Together with Self::sigma_group this keeps the marginal at σ_θ.

Source

pub fn effective_fused(&self) -> &[Vec<usize>]

The groups actually in force. Empty when ρ = 0, so ρ = 0 is the flat prior node for node — no latent means, no extra sites, the same program this model has always run. A guard rather than an accident: a zero-SD Normal is not a distribution, and “turn the feature off” should not depend on remembering to also clear fused.

Source

pub fn sigma_theta(&self) -> f64

Prior SD of one θ coordinate, corrected for the max-of-K utility so that Var(u_a − u_b) is invariant to K (module doc).

Trait Implementations§

Source§

impl Clone for TasteConfig

Source§

fn clone(&self) -> TasteConfig

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for TasteConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for TasteConfig

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl PartialEq for TasteConfig

Source§

fn eq(&self, other: &TasteConfig) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for TasteConfig

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for TasteConfig

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,