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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions