Summary
The impl<D, T, P, R> Fit<Array2<D>, T, Error> for AdaBoostValidParams<P, R> block in algorithms/linfa-ensemble/src/adaboost.rs cannot satisfy Rust's trait solver under our ndarray 0.17 / rand 0.9 ecosystem. AdaBoost source files have been temporarily orphaned (kept on disk, not declared via mod in lib.rs) on the feat/ndarray-0.17-upgrade branch (PR #2) so the dependency upgrade can ship.
Repro on master (post-rebase onto ndarray 0.17)
cargo check -p linfa-ensemble --lib produces ~26 cascading errors of the form:
the trait bound \P: ParamGuard` is not satisfied`
- After adding
P: ParamGuard: <P as ParamGuard>::Checked: ParamGuard is not satisfied
- After adding that:
<<P as ParamGuard>::Checked as ParamGuard>::Checked: ParamGuard is not satisfied
- And so on — infinite regress.
Root cause
Linfa's Fit blanket impl in src/param_guard.rs:55-66:
```rust
impl<R: Records, T, E, P: ParamGuard> Fit<R, T, E> for P
where
P::Checked: Fit<R, T, E>,
E: Error + Fromcrate::error::Error + From<P::Error>,
```
AdaBoost writes where P: Fit<Array2<D>, T, Error> — for generic P, the only way to satisfy this is via the blanket. The blanket then needs P::Checked: Fit, which (for unknown P::Checked) again only resolves via blanket → needs P::Checked: ParamGuard → recursive.
This may have worked under older nightly / older ndarray because of slight differences in trait selection / coherence checks. Under stable + ndarray 0.17 it doesn't.
What's been done in PR #2
mod adaboost; and mod adaboost_hyperparams; removed from linfa-ensemble/src/lib.rs.
- 6 AdaBoost test functions gated with
#[cfg(any())] (always-false; preserves source).
- Doc comment AdaBoost section removed.
examples/adaboost_iris.rs deleted.
- Source files
src/adaboost.rs, src/adaboost_hyperparams.rs left on disk (orphaned). Cargo doesn't see them since they're not declared via mod.
Suggested fix paths
-
Structural rework: Replace P: Fit + Clone with a model factory:
```rust
pub struct AdaBoostValidParams<F, R> {
model_factory: F, // Fn(&BootstrapDataset) -> Result<Box<dyn Predict<...>>, Error>
n_estimators: usize,
...
}
```
Sidesteps trait-system entanglement entirely.
-
Use P::Checked: Fit directly + manual check call: change body to call self.model_params.clone().check()?.fit(...) and bound where P: ParamGuard, P::Checked: Fit<...>, Error: From<P::Error>. Does NOT work today (compiler still demands <P::Checked>::Checked: ParamGuard); would need either trait-system improvement upstream or a workaround.
-
Erase the trait genericism: take &dyn Trait or specific concrete model types only. Less flexible but compile-stable.
Acceptance criteria
References
Summary
The
impl<D, T, P, R> Fit<Array2<D>, T, Error> for AdaBoostValidParams<P, R>block inalgorithms/linfa-ensemble/src/adaboost.rscannot satisfy Rust's trait solver under our ndarray 0.17 / rand 0.9 ecosystem. AdaBoost source files have been temporarily orphaned (kept on disk, not declared viamodinlib.rs) on thefeat/ndarray-0.17-upgradebranch (PR #2) so the dependency upgrade can ship.Repro on master (post-rebase onto ndarray 0.17)
cargo check -p linfa-ensemble --libproduces ~26 cascading errors of the form:the trait bound \P: ParamGuard` is not satisfied`P: ParamGuard:<P as ParamGuard>::Checked: ParamGuardis not satisfied<<P as ParamGuard>::Checked as ParamGuard>::Checked: ParamGuardis not satisfiedRoot cause
Linfa's
Fitblanket impl insrc/param_guard.rs:55-66:```rust
impl<R: Records, T, E, P: ParamGuard> Fit<R, T, E> for P
where
P::Checked: Fit<R, T, E>,
E: Error + Fromcrate::error::Error + From<P::Error>,
```
AdaBoost writes
where P: Fit<Array2<D>, T, Error>— for generic P, the only way to satisfy this is via the blanket. The blanket then needsP::Checked: Fit, which (for unknown P::Checked) again only resolves via blanket → needsP::Checked: ParamGuard→ recursive.This may have worked under older nightly / older ndarray because of slight differences in trait selection / coherence checks. Under stable + ndarray 0.17 it doesn't.
What's been done in PR #2
mod adaboost;andmod adaboost_hyperparams;removed fromlinfa-ensemble/src/lib.rs.#[cfg(any())](always-false; preserves source).examples/adaboost_iris.rsdeleted.src/adaboost.rs,src/adaboost_hyperparams.rsleft on disk (orphaned). Cargo doesn't see them since they're not declared viamod.Suggested fix paths
Structural rework: Replace
P: Fit + Clonewith a model factory:```rust
pub struct AdaBoostValidParams<F, R> {
model_factory: F, // Fn(&BootstrapDataset) -> Result<Box<dyn Predict<...>>, Error>
n_estimators: usize,
...
}
```
Sidesteps trait-system entanglement entirely.
Use
P::Checked: Fitdirectly + manual check call: change body to callself.model_params.clone().check()?.fit(...)and boundwhere P: ParamGuard, P::Checked: Fit<...>, Error: From<P::Error>. Does NOT work today (compiler still demands<P::Checked>::Checked: ParamGuard); would need either trait-system improvement upstream or a workaround.Erase the trait genericism: take
&dyn Traitor specific concrete model types only. Less flexible but compile-stable.Acceptance criteria
cargo check -p linfa-ensemble --libwarning-freecargo test -p linfa-ensemble --lib— 6 AdaBoost tests un-gated and passingexamples/adaboost_iris.rsrestoredmod adaboost;/pub use adaboost::*;restored inlinfa-ensemble/src/lib.rsFit-able weak learner)References
09b2f39("Merge origin/master into feat/ndarray-0.17-upgrade")