1#![allow(clippy::range_plus_one)]
16
17#[macro_use]
19pub mod macros;
20mod errors;
22pub mod executor;
24mod iterstate;
26mod kv;
28mod math;
30mod nooperator;
33mod observers;
35mod opwrapper;
37mod result;
39mod serialization;
41mod termination;
43
44pub use anyhow::Error;
45pub use errors::*;
46pub use executor::*;
47pub use iterstate::*;
48pub use kv::ArgminKV;
49pub use math::*;
50pub use nooperator::*;
51use num::traits::{Float, FloatConst, FromPrimitive, ToPrimitive};
52pub use observers::*;
53pub use opwrapper::*;
54pub use result::ArgminResult;
55use serde::de::DeserializeOwned;
56use serde::Serialize;
57pub use serialization::*;
58use std::fmt::{Debug, Display};
59pub use termination::TerminationReason;
60
61pub trait ArgminFloat:
63 Float + FloatConst + FromPrimitive + ToPrimitive + Debug + Display + Serialize + DeserializeOwned
64{
65}
66impl<I> ArgminFloat for I where
67 I: Float
68 + FloatConst
69 + FromPrimitive
70 + ToPrimitive
71 + Debug
72 + Display
73 + Serialize
74 + DeserializeOwned
75{
76}
77
78pub trait ArgminOp {
85 type Param: Clone + Serialize + DeserializeOwned;
89 type Output: Clone + Serialize + DeserializeOwned;
91 type Hessian: Clone + Serialize + DeserializeOwned;
93 type Jacobian: Clone + Serialize + DeserializeOwned;
95 type Float: ArgminFloat;
97
98 fn apply(&self, _param: &Self::Param) -> Result<Self::Output, Error> {
100 Err(ArgminError::NotImplemented {
101 text: "Method `apply` of ArgminOp trait not implemented!".to_string(),
102 }
103 .into())
104 }
105
106 fn gradient(&self, _param: &Self::Param) -> Result<Self::Param, Error> {
108 Err(ArgminError::NotImplemented {
109 text: "Method `gradient` of ArgminOp trait not implemented!".to_string(),
110 }
111 .into())
112 }
113
114 fn hessian(&self, _param: &Self::Param) -> Result<Self::Hessian, Error> {
116 Err(ArgminError::NotImplemented {
117 text: "Method `hessian` of ArgminOp trait not implemented!".to_string(),
118 }
119 .into())
120 }
121
122 fn jacobian(&self, _param: &Self::Param) -> Result<Self::Jacobian, Error> {
124 Err(ArgminError::NotImplemented {
125 text: "Method `jacobian` of ArgminOp trait not implemented!".to_string(),
126 }
127 .into())
128 }
129
130 fn modify(&self, _param: &Self::Param, _extent: Self::Float) -> Result<Self::Param, Error> {
133 Err(ArgminError::NotImplemented {
134 text: "Method `modify` of ArgminOp trait not implemented!".to_string(),
135 }
136 .into())
137 }
138}
139
140pub trait Solver<O: ArgminOp>: Serialize {
144 const NAME: &'static str = "UNDEFINED";
146
147 fn next_iter(
149 &mut self,
150 op: &mut OpWrapper<O>,
151 state: &IterState<O>,
152 ) -> Result<ArgminIterData<O>, Error>;
153
154 fn init(
159 &mut self,
160 _op: &mut OpWrapper<O>,
161 _state: &IterState<O>,
162 ) -> Result<Option<ArgminIterData<O>>, Error> {
163 Ok(None)
164 }
165
166 fn terminate_internal(&mut self, state: &IterState<O>) -> TerminationReason {
176 let solver_terminate = self.terminate(state);
177 if solver_terminate.terminated() {
178 return solver_terminate;
179 }
180 if state.get_iter() >= state.get_max_iters() {
181 return TerminationReason::MaxItersReached;
182 }
183 if state.get_cost() <= state.get_target_cost() {
184 return TerminationReason::TargetCostReached;
185 }
186 TerminationReason::NotTerminated
187 }
188
189 fn terminate(&mut self, _state: &IterState<O>) -> TerminationReason {
191 TerminationReason::NotTerminated
192 }
193}
194
195#[derive(Clone, Debug, Default)]
199pub struct ArgminIterData<O: ArgminOp> {
200 param: Option<O::Param>,
202 cost: Option<O::Float>,
204 grad: Option<O::Param>,
206 hessian: Option<O::Hessian>,
208 jacobian: Option<O::Jacobian>,
210 population: Option<Vec<(O::Param, O::Float)>>,
212 termination_reason: Option<TerminationReason>,
214 kv: ArgminKV,
216}
217
218impl<O: ArgminOp> ArgminIterData<O> {
221 pub fn new() -> Self {
223 ArgminIterData {
224 param: None,
225 cost: None,
226 grad: None,
227 hessian: None,
228 jacobian: None,
229 termination_reason: None,
230 population: None,
231 kv: make_kv!(),
232 }
233 }
234
235 pub fn param(mut self, param: O::Param) -> Self {
237 self.param = Some(param);
238 self
239 }
240
241 pub fn cost(mut self, cost: O::Float) -> Self {
243 self.cost = Some(cost);
244 self
245 }
246
247 pub fn grad(mut self, grad: O::Param) -> Self {
249 self.grad = Some(grad);
250 self
251 }
252
253 pub fn hessian(mut self, hessian: O::Hessian) -> Self {
255 self.hessian = Some(hessian);
256 self
257 }
258
259 pub fn jacobian(mut self, jacobian: O::Jacobian) -> Self {
261 self.jacobian = Some(jacobian);
262 self
263 }
264
265 pub fn population(mut self, population: Vec<(O::Param, O::Float)>) -> Self {
267 self.population = Some(population);
268 self
269 }
270
271 pub fn kv(mut self, kv: ArgminKV) -> Self {
273 self.kv = kv;
274 self
275 }
276
277 pub fn termination_reason(mut self, reason: TerminationReason) -> Self {
279 self.termination_reason = Some(reason);
280 self
281 }
282
283 pub fn get_param(&self) -> Option<O::Param> {
285 self.param.clone()
286 }
287
288 pub fn get_cost(&self) -> Option<O::Float> {
290 self.cost
291 }
292
293 pub fn get_grad(&self) -> Option<O::Param> {
295 self.grad.clone()
296 }
297
298 pub fn get_hessian(&self) -> Option<O::Hessian> {
300 self.hessian.clone()
301 }
302
303 pub fn get_jacobian(&self) -> Option<O::Jacobian> {
305 self.jacobian.clone()
306 }
307
308 pub fn get_population(&self) -> Option<&Vec<(O::Param, O::Float)>> {
310 match &self.population {
311 Some(population) => Some(&population),
312 None => None,
313 }
314 }
315
316 pub fn get_termination_reason(&self) -> Option<TerminationReason> {
318 self.termination_reason
319 }
320
321 pub fn get_kv(&self) -> ArgminKV {
323 self.kv.clone()
324 }
325}
326
327pub trait ArgminLineSearch<P, F>: Serialize {
329 fn set_search_direction(&mut self, direction: P);
331
332 fn set_init_alpha(&mut self, step_length: F) -> Result<(), Error>;
334}
335
336pub trait ArgminTrustRegion<F>: Clone + Serialize {
339 fn set_radius(&mut self, radius: F);
341}
342pub trait ArgminNLCGBetaUpdate<T, F: ArgminFloat>: Serialize {
345 fn update(&self, nabla_f_k: &T, nabla_f_k_p_1: &T, p_k: &T) -> F;
350}