Skip to content

linfa-ensemble: AdaBoost trait bounds need structural rework (orphaned in #2) #3

Description

@jagan-nuvai

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

  1. 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.

  2. 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.

  3. Erase the trait genericism: take &dyn Trait or specific concrete model types only. Less flexible but compile-stable.

Acceptance criteria

  • cargo check -p linfa-ensemble --lib warning-free
  • cargo test -p linfa-ensemble --lib — 6 AdaBoost tests un-gated and passing
  • examples/adaboost_iris.rs restored
  • mod adaboost; / pub use adaboost::*; restored in linfa-ensemble/src/lib.rs
  • Original PR Add AdaBoost classifier to linfa-ensemble rust-ml/linfa#427's intent preserved (AdaBoost still wraps any Fit-able weak learner)

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions