pub fn train<F: Fn(&[f64]) -> f64>(
    settings: TrainingSettings,
    weights: &[f64],
    f: F
) -> Result<Fit, Fit> {
    let mut ws = vec![0.0; settings.error_predictions + weights.len()];
    for i in 0..weights.len() {
        ws[i + settings.error_predictions] = weights[i];
    }
    if settings.error_predictions > 0 {
        ws[0] = settings.step;
    }
    let eval = |ws: &[f64]| {
        let mut score = f(&ws[settings.error_predictions..]);
        for i in 0..settings.error_predictions {
            score += (score - ws[i]).abs();
        }
        score
    };
    let step = |ws: &[f64], i: usize| {
        settings.elasticity * if i + 1 < settings.error_predictions {
            // Use next error prediction level for change.
            ws[i + 1]
        } else if i + 1 == settings.error_predictions {
            // The last error prediction level uses normal step.
            settings.step
        } else if settings.error_predictions > 0 {
            // Adjust step to predicted error.
            ws[0]
        } else {
            settings.step
        }
    };
    let check = |w: &mut f64, i: usize| {
        if i < settings.error_predictions {
            if *w <= settings.step {*w = settings.step}
        }
    };
    let mut iterations = 0;
    // Keep track of last score to detect unchanged loop.
    let mut last_score: Option<f64> = None;
    let mut last_score_iterations = 0;
    loop {
        // Evaluate score without error predictions.
        let score = f(&ws[settings.error_predictions..]);
        if score <= settings.accuracy_error {
            return Ok(Fit {
                error: score,
                weights: ws[settings.error_predictions..].into(),
                error_predictions: ws[0..settings.error_predictions].into(),
                iterations,
            })
        } else if iterations >= settings.max_iterations ||
            last_score_iterations >= 2 * settings.reset_interval {
            return Err(Fit {
                error: score,
                weights: ws[settings.error_predictions..].into(),
                error_predictions: ws[0..settings.error_predictions].into(),
                iterations,
            })
        }
        if last_score == Some(score) {
            last_score_iterations += 1;
        } else {
            last_score_iterations = 0;
        }
        last_score = Some(score);
        // Reset error predictions.
        if iterations % settings.reset_interval == 0 {
            if settings.debug {
                println!("{:?}", Fit {
                    error: score,
                    weights: ws[settings.error_predictions..].into(),
                    error_predictions: ws[0..settings.error_predictions].into(),
                    iterations,
                });
            }
            for i in 0..settings.error_predictions {
                ws[i] = 0.0;
            }
            ws[0] = settings.step;
        }
        // Change eight weight in either direction and pick the best.
        // This also changes the error prediction weights.
        for i in 0..ws.len() {
            let score = eval(&ws);
            let old = ws[i];
            let step = step(&ws, i);
            ws[i] += step;
            check(&mut ws[i], i);
            let score_up = eval(&ws);
            ws[i] -= 2.0 * step;
            check(&mut ws[i], i);
            let score_down = eval(&ws);
            if score <= score_up && score <= score_down {
                ws[i] = old;
            } else if score_up < score_down {
                ws[i] += 2.0 * step;
            }
        }
        iterations += 1;
    }
}
/// Trains to fit a vector of weights on a black-box function returning error.
///
/// Returns `Ok` if acceptable accuracy error was achieved.
/// Returns `Err` if exceeding max iterations or score was unchanged
/// for twice the reset interval.
Trains to fit a vector of weights on a black-box function returning error.
Returns `Ok` if acceptable accuracy error was achieved.
Returns `Err` if exceeding max iterations or score was unchanged
for twice the reset interval.
Trains to fit a vector of weights on a black - box function returning error . Returns ` Ok ` if acceptable accuracy error was achieved . Returns ` Err ` if exceeding max iterations or score was unchanged for twice the reset interval .
pub fn train<F: Fn(&[f64]) -> f64>(
    settings: TrainingSettings,
    weights: &[f64],
    f: F
) -> Result<Fit, Fit> {
    let mut ws = vec![0.0; settings.error_predictions + weights.len()];
    for i in 0..weights.len() {
        ws[i + settings.error_predictions] = weights[i];
    }
    if settings.error_predictions > 0 {
        ws[0] = settings.step;
    }
    let eval = |ws: &[f64]| {
        let mut score = f(&ws[settings.error_predictions..]);
        for i in 0..settings.error_predictions {
            score += (score - ws[i]).abs();
        }
        score
    };
    let step = |ws: &[f64], i: usize| {
        settings.elasticity * if i + 1 < settings.error_predictions {
            // Use next error prediction level for change.
            ws[i + 1]
        } else if i + 1 == settings.error_predictions {
            // The last error prediction level uses normal step.
            settings.step
        } else if settings.error_predictions > 0 {
            // Adjust step to predicted error.
            ws[0]
        } else {
            settings.step
        }
    };
    let check = |w: &mut f64, i: usize| {
        if i < settings.error_predictions {
            if *w <= settings.step {*w = settings.step}
        }
    };
    let mut iterations = 0;
    // Keep track of last score to detect unchanged loop.
    let mut last_score: Option<f64> = None;
    let mut last_score_iterations = 0;
    loop {
        // Evaluate score without error predictions.
        let score = f(&ws[settings.error_predictions..]);
        if score <= settings.accuracy_error {
            return Ok(Fit {
                error: score,
                weights: ws[settings.error_predictions..].into(),
                error_predictions: ws[0..settings.error_predictions].into(),
                iterations,
            })
        } else if iterations >= settings.max_iterations ||
            last_score_iterations >= 2 * settings.reset_interval {
            return Err(Fit {
                error: score,
                weights: ws[settings.error_predictions..].into(),
                error_predictions: ws[0..settings.error_predictions].into(),
                iterations,
            })
        }
        if last_score == Some(score) {
            last_score_iterations += 1;
        } else {
            last_score_iterations = 0;
        }
        last_score = Some(score);
        // Reset error predictions.
        if iterations % settings.reset_interval == 0 {
            if settings.debug {
                println!("{:?}", Fit {
                    error: score,
                    weights: ws[settings.error_predictions..].into(),
                    error_predictions: ws[0..settings.error_predictions].into(),
                    iterations,
                });
            }
            for i in 0..settings.error_predictions {
                ws[i] = 0.0;
            }
            ws[0] = settings.step;
        }
        // Change eight weight in either direction and pick the best.
        // This also changes the error prediction weights.
        for i in 0..ws.len() {
            let score = eval(&ws);
            let old = ws[i];
            let step = step(&ws, i);
            ws[i] += step;
            check(&mut ws[i], i);
            let score_up = eval(&ws);
            ws[i] -= 2.0 * step;
            check(&mut ws[i], i);
            let score_down = eval(&ws);
            if score <= score_up && score <= score_down {
                ws[i] = old;
            } else if score_up < score_down {
                ws[i] += 2.0 * step;
            }
        }
        iterations += 1;
    }
}
pub fn train < F : Fn ( & [ f64 ] ) -> f64 > ( settings : TrainingSettings , weights : & [ f64 ] , f : F ) -> Result < Fit , Fit > { let mut ws = vec ! [ 0.0 settings error_predictions weights len ( ) ] ; for i in 0 .. weights . len ( ) { ws [ i + settings . error_predictions ] = weights [ i ] ; } if settings . error_predictions > 0 { ws [ 0 ] = settings . step ; } let eval = | ws : & [ f64 ] | { let mut score = f ( & ws [ settings . error_predictions .. ] ) ; for i in 0 .. settings . error_predictions { score += ( score - ws [ i ] ) . abs ( ) ; } score } ; let step = | ws : & [ f64 ] , i : usize | { settings . elasticity * if i + 1 < settings . error_predictions { // Use next error prediction level for change. ws [ i + 1 ] } else if i + 1 == settings . error_predictions { // The last error prediction level uses normal step. settings . step } else if settings . error_predictions > 0 { // Adjust step to predicted error. ws [ 0 ] } else { settings . step } } ; let check = | w : & mut f64 , i : usize | { if i < settings . error_predictions { if * w <= settings . step { * w = settings . step } } } ; let mut iterations = 0 ; // Keep track of last score to detect unchanged loop. let mut last_score : Option < f64 > = None ; let mut last_score_iterations = 0 ; loop { // Evaluate score without error predictions. let score = f ( & ws [ settings . error_predictions .. ] ) ; if score <= settings . accuracy_error { return Ok ( Fit { error : score , weights : ws [ settings . error_predictions .. ] . into ( ) , error_predictions : ws [ 0 .. settings . error_predictions ] . into ( ) , iterations , } ) } else if iterations >= settings . max_iterations || last_score_iterations >= 2 * settings . reset_interval { return Err ( Fit { error : score , weights : ws [ settings . error_predictions .. ] . into ( ) , error_predictions : ws [ 0 .. settings . error_predictions ] . into ( ) , iterations , } ) } if last_score == Some ( score ) { last_score_iterations += 1 ; } else { last_score_iterations = 0 ; } last_score = Some ( score ) ; // Reset error predictions. if iterations % settings . reset_interval == 0 { if settings . debug { println ! ( " " Fit { error score weights ws [ settings error_predictions ] into ( ) error_predictions ws [ 0 settings error_predictions ] into ( ) iterations } ) ; } for i in 0 .. settings . error_predictions { ws [ i ] = 0.0 ; } ws [ 0 ] = settings . step ; } // Change eight weight in either direction and pick the best. // This also changes the error prediction weights. for i in 0 .. ws . len ( ) { let score = eval ( & ws ) ; let old = ws [ i ] ; let step = step ( & ws , i ) ; ws [ i ] += step ; check ( & mut ws [ i ] , i ) ; let score_up = eval ( & ws ) ; ws [ i ] -= 2.0 * step ; check ( & mut ws [ i ] , i ) ; let score_down = eval ( & ws ) ; if score <= score_up && score <= score_down { ws [ i ] = old ; } else if score_up < score_down { ws [ i ] += 2.0 * step ; } } iterations += 1 ; } }
Trains to fit a vector of weights on a black-box function returning error.
Trains to fit a vector of weights on a black - box function returning error .
settings
TrainingSettings
weights
&[f64]
f
F
settings
TrainingSettings
weights
&[f64]
f
F