// Copyright (c) 2016, 2017, 2018, 2019 Frank Fischer <frank-fischer@shadow-soft.de>
//
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>
//
//! A linear minorant.
use crate::{DVector, Real};
use std::borrow::Borrow;
use std::fmt;
/// An aggregatable object.
pub trait Aggregatable {
/// Return $\sum\_{i=1}\^n alpha_i m_i$.
fn combine<I, A>(aggregates: I) -> Self
where
I: IntoIterator<Item = (Real, A)>,
A: Borrow<Self>;
}
/// Implement for empty tuples.
impl Aggregatable for () {
fn combine<I, A>(_aggregates: I)
where
I: IntoIterator<Item = (Real, A)>,
A: Borrow<Self>,
{
}
}
impl Aggregatable for Real {
fn combine<I, A>(aggregates: I) -> Real
where
I: IntoIterator<Item = (Real, A)>,
A: Borrow<Self>,
{
aggregates.into_iter().map(|(alpha, y)| alpha * y.borrow()).sum()
}
}
/**
* A linear minorant of a convex function.
*
* A linear minorant of a convex function $f \colon \mathbb{R}\^n \to
* \mathbb{R}$ is a linear function of the form
*
* \\[ l \colon \mathbb{R}\^n \to \mathbb{R}, x \mapsto \langle g, x
* \rangle + c \\]
*
* such that $l(x) \le f(x)$ for all $x \in \mathbb{R}\^n$.
*/
#[derive(Clone, Debug)]
pub struct Minorant {
/// The constant term.
pub constant: Real,
/// The linear term.
pub linear: DVector,
}
impl fmt::Display for Minorant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} + y * {}", self.constant, self.linear)?;
Ok(())
}
}
impl Default for Minorant {
fn default() -> Minorant {
Minorant {
constant: 0.0,
linear: dvec![],
}
}
}
impl Minorant {
/// Return a new 0 minorant.
pub fn new(constant: Real, linear: Vec<Real>) -> Minorant {
Minorant {
constant,
linear: DVector(linear),
}
}
/**
* Evaluate minorant at some point.
*
* This function computes $c + \langle g, x \rangle$ for this minorant
* \\[\ell \colon \mathbb{R}\^n \to \mathbb{R}, x \mapsto c + \langle g, x \rangle\\]
* and the given point $x \in \mathbb{R}\^n$.
*/
pub fn eval(&self, x: &DVector) -> Real {
self.constant + self.linear.dot(x)
}
/**
* Move the center of the minorant.
*/
pub fn move_center(&mut self, alpha: Real, d: &DVector) {
self.constant += alpha * self.linear.dot(d);
}
}
impl Aggregatable for Minorant {
fn combine<I, A>(aggregates: I) -> Minorant
where
I: IntoIterator<Item = (Real, A)>,
A: Borrow<Minorant>,
{
let mut constant = 0.0;
let mut linear = dvec![];
for (i, (alpha, m)) in aggregates.into_iter().enumerate() {
let m = m.borrow();
if i == 0 {
linear.resize(m.linear.len(), 0.0);
}
constant += alpha * m.constant;
linear.add_scaled(alpha, &m.linear);
}
Minorant { constant, linear }
}
}