use super::{
ConstraintViolationState, CountsMirror, EvaluatedGradientState,
EvaluatedState, GradientDimensionMismatch, GradientState, IncumbentRef,
IncumbentState, RawEvaluationState, SelectedState, State, ViolationReport,
};
use crate::{EvalCounts, Scalar, VectorLen};
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SelectedFirstOrderState<V, F: Scalar = f64> {
progress: SelectedState<V, F>,
gradient: Option<V>,
}
impl<V, F: Scalar> SelectedFirstOrderState<V, F> {
pub fn new(param: V) -> Self {
Self {
progress: SelectedState::new(param),
gradient: None,
}
}
pub fn reset(&mut self) {
self.progress.reset();
self.gradient = None;
}
pub fn current(&self) -> Option<(&V, F, &V, &ViolationReport<F>)> {
let (x, cost, violation) = self.progress.current()?;
Some((x, cost, self.gradient.as_ref()?, violation))
}
pub fn best(&self) -> Option<(&V, F, &ViolationReport<F>)> {
self.progress.best()
}
pub fn counts(&self) -> &EvalCounts {
self.progress.counts()
}
pub fn best_counts(&self) -> Option<&EvalCounts> {
self.progress.best_counts()
}
}
impl<V: VectorLen, F: Scalar> SelectedFirstOrderState<V, F> {
pub fn replace(
&mut self,
param: V,
cost: F,
gradient: V,
violation: ViolationReport<F>,
) -> Result<(), GradientDimensionMismatch> {
if param.vec_len() != gradient.vec_len() {
return Err(GradientDimensionMismatch {
param_len: param.vec_len(),
gradient_len: gradient.vec_len(),
});
}
self.progress.replace(param, cost, violation);
self.gradient = Some(gradient);
Ok(())
}
}
impl<V: Clone, F: Scalar> SelectedFirstOrderState<V, F> {
pub fn select_current(&mut self) -> bool {
self.progress.select_current()
}
}
impl<V: Clone, F: Scalar> State for SelectedFirstOrderState<V, F> {
type Param = V;
type Float = F;
fn iter(&self) -> u64 {
self.progress.iter()
}
fn increment_iter(&mut self) {
self.progress.increment_iter();
}
fn param(&self) -> &V {
self.progress.param()
}
fn cost(&self) -> F {
self.progress.cost()
}
fn cost_evals(&self) -> u64 {
self.progress.cost_evals()
}
fn best_param(&self) -> &V {
self.progress.best_param()
}
fn best_cost(&self) -> F {
self.progress.best_cost()
}
fn best_iter(&self) -> u64 {
self.progress.best_iter()
}
fn best_cost_evals(&self) -> u64 {
self.progress.best_cost_evals()
}
fn update_best(&mut self) {
self.progress.update_best();
}
fn reset_best(&mut self) {
self.progress.reset_best();
}
}
impl<V: Clone, F: Scalar> CountsMirror for SelectedFirstOrderState<V, F> {
fn mirror(&mut self, counts: &EvalCounts) {
self.progress.mirror(counts);
}
}
impl<V: Clone, F: Scalar> RawEvaluationState for SelectedFirstOrderState<V, F> {
fn raw_counts(&self) -> &EvalCounts {
self.counts()
}
}
impl<V: Clone, F: Scalar> EvaluatedState for SelectedFirstOrderState<V, F> {
fn current_record(&self) -> Option<(&V, F)> {
self.progress.current_record()
}
}
impl<V: Clone, F: Scalar> EvaluatedGradientState
for SelectedFirstOrderState<V, F>
{
fn current_gradient_record(&self) -> Option<(&V, F, &V)> {
self.current()
.map(|(x, cost, gradient, _)| (x, cost, gradient))
}
}
impl<V: Clone, F: Scalar> GradientState for SelectedFirstOrderState<V, F> {
fn gradient(&self) -> Option<&V> {
self.gradient.as_ref()
}
fn gradient_evals(&self) -> u64 {
self.counts().gradient_evals
}
fn best_gradient_evals(&self) -> u64 {
self.best_counts().map_or(0, |c| c.gradient_evals)
}
}
impl<V: Clone, F: Scalar> IncumbentState for SelectedFirstOrderState<V, F> {
fn incumbent_record(&self) -> Option<IncumbentRef<'_, V, F>> {
self.progress.incumbent_record()
}
}
impl<V: Clone, F: Scalar> ConstraintViolationState
for SelectedFirstOrderState<V, F>
{
fn current_violation(&self) -> Option<&ViolationReport<F>> {
self.progress.current_violation()
}
fn incumbent_violation(&self) -> Option<&ViolationReport<F>> {
self.progress.incumbent_violation()
}
}