use crate::cobyla::cobyla_context_t;
use argmin::core::{Problem, State, TerminationReason, TerminationStatus};
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::mem::ManuallyDrop;
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct CobylaState {
pub param: Option<Vec<f64>>,
pub prev_param: Option<Vec<f64>>,
pub best_param: Option<Vec<f64>>,
pub prev_best_param: Option<Vec<f64>>,
pub cost: Option<Vec<f64>>,
pub prev_cost: Option<Vec<f64>>,
pub best_cost: Option<Vec<f64>>,
pub prev_best_cost: Option<Vec<f64>>,
pub target_cost: f64,
pub iter: u64,
pub last_best_iter: u64,
pub max_iters: u64,
pub counts: HashMap<String, u64>,
pub time: Option<web_time::Duration>,
pub termination_status: TerminationStatus,
pub rhobeg: f64,
pub rhoend: f64,
pub iprint: i32,
pub maxfun: i32,
#[cfg_attr(feature = "serde1", serde(skip))]
pub cobyla_context: Option<ManuallyDrop<*mut cobyla_context_t>>,
}
impl CobylaState
where
Self: State<Float = f64>,
{
#[must_use]
pub fn param(mut self, param: Vec<f64>) -> Self {
std::mem::swap(&mut self.prev_param, &mut self.param);
self.param = Some(param);
self
}
#[must_use]
pub fn target_cost(mut self, target_cost: f64) -> Self {
self.target_cost = target_cost;
self
}
#[must_use]
pub fn max_iters(mut self, iters: u64) -> Self {
self.max_iters = iters;
self
}
#[must_use]
pub fn maxfun(mut self, maxfun: u64) -> Self {
self.max_iters = maxfun;
self
}
#[must_use]
pub fn iprint(mut self, iprint: i32) -> Self {
self.iprint = iprint;
self
}
#[must_use]
pub fn cost(mut self, cost: Vec<f64>) -> Self {
std::mem::swap(&mut self.prev_cost, &mut self.cost);
self.cost = Some(cost);
self
}
pub fn get_full_cost(&self) -> Option<&Vec<f64>> {
self.cost.as_ref()
}
pub fn get_full_best_cost(&self) -> Option<&Vec<f64>> {
self.best_cost.as_ref()
}
pub fn rhobeg(&self) -> f64 {
self.rhobeg
}
pub fn get_rhoend(&self) -> f64 {
self.rhoend
}
pub fn get_iprint(&self) -> i32 {
self.iprint
}
pub fn get_maxfun(&self) -> i32 {
self.max_iters as i32
}
}
impl State for CobylaState {
type Param = Vec<f64>;
type Float = f64;
fn new() -> Self {
CobylaState {
param: None,
prev_param: None,
best_param: None,
prev_best_param: None,
cost: None,
prev_cost: None,
best_cost: None,
prev_best_cost: None,
target_cost: f64::NEG_INFINITY,
iter: 0,
last_best_iter: 0,
max_iters: u64::MAX,
counts: HashMap::new(),
time: Some(web_time::Duration::new(0, 0)),
termination_status: TerminationStatus::NotTerminated,
rhobeg: 0.5,
rhoend: 1e-4,
iprint: 1,
maxfun: 2000,
cobyla_context: None,
}
}
fn update(&mut self) {
if let Some(cost) = self.cost.as_ref() {
if let Some(param) = self.param.as_ref().cloned() {
std::mem::swap(&mut self.prev_best_param, &mut self.best_param);
self.best_param = Some(param);
}
std::mem::swap(&mut self.prev_best_cost, &mut self.best_cost);
self.best_cost = Some(cost.clone());
self.last_best_iter = self.iter;
}
}
fn get_param(&self) -> Option<&Vec<f64>> {
self.param.as_ref()
}
fn get_best_param(&self) -> Option<&Vec<f64>> {
self.best_param.as_ref()
}
fn terminate_with(mut self, reason: TerminationReason) -> Self {
self.termination_status = TerminationStatus::Terminated(reason);
self
}
fn time(&mut self, time: Option<web_time::Duration>) -> &mut Self {
self.time = time;
self
}
fn get_cost(&self) -> Self::Float {
match self.cost.as_ref() {
Some(c) => *(c.first().unwrap_or(&f64::INFINITY)),
None => f64::INFINITY,
}
}
fn get_best_cost(&self) -> Self::Float {
match self.best_cost.as_ref() {
Some(c) => *(c.first().unwrap_or(&f64::INFINITY)),
None => f64::INFINITY,
}
}
fn get_target_cost(&self) -> Self::Float {
self.target_cost
}
fn get_iter(&self) -> u64 {
self.iter
}
fn get_last_best_iter(&self) -> u64 {
self.last_best_iter
}
fn get_max_iters(&self) -> u64 {
self.max_iters
}
fn get_termination_status(&self) -> &TerminationStatus {
&self.termination_status
}
fn get_termination_reason(&self) -> Option<&TerminationReason> {
match &self.termination_status {
TerminationStatus::Terminated(reason) => Some(reason),
TerminationStatus::NotTerminated => None,
}
}
fn get_time(&self) -> Option<web_time::Duration> {
self.time
}
fn increment_iter(&mut self) {
self.iter += 1;
}
fn func_counts<O>(&mut self, problem: &Problem<O>) {
for (k, &v) in problem.counts.iter() {
let count = self.counts.entry(k.to_string()).or_insert(0);
*count = v
}
}
fn get_func_counts(&self) -> &HashMap<String, u64> {
&self.counts
}
fn is_best(&self) -> bool {
self.last_best_iter == self.iter
}
}