1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2018 Stefan Kroboth
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! # Beta update methods
//!
//! TODO: Proper documentation.
//!
//! # References:
//!
//! [0] Jorge Nocedal and Stephen J. Wright (2006). Numerical Optimization.
//! Springer. ISBN 0-387-30303-0.
// //!
// //! # Example
// //!
// //! ```rust
// //! todo
// //! ```

use crate::prelude::*;
use serde::{Deserialize, Serialize};

/// Fletcher and Reeves (FR) method
/// TODO: Reference
#[derive(
    Default, Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug,
)]
pub struct FletcherReeves {}

impl FletcherReeves {
    /// Constructor
    pub fn new() -> Self {
        FletcherReeves {}
    }
}

impl<T> ArgminNLCGBetaUpdate<T> for FletcherReeves
where
    T: Clone + ArgminDot<T, f64>,
{
    fn update(&self, dfk: &T, dfk1: &T, _pk: &T) -> f64 {
        dfk1.dot(&dfk1) / dfk.dot(&dfk)
    }
}

/// Polak and Ribiere (PR) method
/// TODO: Reference
#[derive(
    Default, Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug,
)]
pub struct PolakRibiere {}

impl PolakRibiere {
    /// Constructor
    pub fn new() -> Self {
        PolakRibiere {}
    }
}

impl<T> ArgminNLCGBetaUpdate<T> for PolakRibiere
where
    T: Clone + ArgminDot<T, f64> + ArgminSub<T, T> + ArgminNorm<f64>,
{
    fn update(&self, dfk: &T, dfk1: &T, _pk: &T) -> f64 {
        let dfk_norm_sq = dfk.norm().powi(2);
        dfk1.dot(&dfk1.sub(&dfk)) / dfk_norm_sq
    }
}

/// Polak and Ribiere Plus (PR+) method
/// TODO: Reference
#[derive(
    Default, Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug,
)]
pub struct PolakRibierePlus {}

impl PolakRibierePlus {
    /// Constructor
    pub fn new() -> Self {
        PolakRibierePlus {}
    }
}

impl<T> ArgminNLCGBetaUpdate<T> for PolakRibierePlus
where
    T: Clone + ArgminDot<T, f64> + ArgminSub<T, T> + ArgminNorm<f64>,
{
    fn update(&self, dfk: &T, dfk1: &T, _pk: &T) -> f64 {
        let dfk_norm_sq = dfk.norm().powi(2);
        let beta = dfk1.dot(&dfk1.sub(&dfk)) / dfk_norm_sq;
        0.0f64.max(beta)
    }
}

/// Hestenes and Stiefel (HS) method
/// TODO: Reference
#[derive(
    Default, Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug,
)]
pub struct HestenesStiefel {}

impl HestenesStiefel {
    /// Constructor
    pub fn new() -> Self {
        HestenesStiefel {}
    }
}

impl<T> ArgminNLCGBetaUpdate<T> for HestenesStiefel
where
    T: Clone + ArgminDot<T, f64> + ArgminSub<T, T> + ArgminNorm<f64>,
{
    fn update(&self, dfk: &T, dfk1: &T, pk: &T) -> f64 {
        let d = dfk1.sub(&dfk);
        dfk1.dot(&d) / d.dot(&pk)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::send_sync_test;

    send_sync_test!(fletcher_reeves, FletcherReeves);
    send_sync_test!(polak_ribiere, PolakRibiere);
    send_sync_test!(polak_ribiere_plus, PolakRibierePlus);
    send_sync_test!(hestenes_stiefel, HestenesStiefel);
}