### Install Spectator from Crates.io Source: https://github.com/argmin-rs/argmin/blob/main/crates/spectator/README.md Install the Spectator GUI tool directly from crates.io using cargo. The --locked flag ensures reproducible builds. ```bash cargo install spectator --locked ``` -------------------------------- ### Executor Setup Before v0.6.0 Source: https://github.com/argmin-rs/argmin/blob/main/media/website/content/blog/version-v0.6.0.md Illustrates the previous method of setting up an Executor, including providing the initial parameter vector directly to the constructor. ```rust let result = Executor::new(problem, solver, initial_param) .max_iters(1000) .run()?; ``` -------------------------------- ### Executor Setup in v0.6.0 Source: https://github.com/argmin-rs/argmin/blob/main/media/website/content/blog/version-v0.6.0.md Demonstrates the new Executor setup in v0.6.0, where configuration of the internal state, including initial parameters and max iterations, is done via the `configure` method. ```rust let result = Executor::new(problem, solver) .configure(|state| state.param(initial_param).max_iters(1000)) .run()?; ``` -------------------------------- ### Build and Run Spectator from Repository Source: https://github.com/argmin-rs/argmin/blob/main/crates/spectator/README.md Clone the argmin repository, then build and run the Spectator executable. This method is useful for development or when not installing from crates.io. ```bash git clone https://github.com/argmin-rs/argmin.git cd argmin # Compile and run from the repo... cargo build -p spectator --release ./target/release/spectator # .. or directly run from the repo... cargo run -p spectator --release # ... or install locally cargo install -p spectator spectator ``` -------------------------------- ### Executor Setup with Checkpointing in v0.6.0 Source: https://github.com/argmin-rs/argmin/blob/main/media/website/content/blog/version-v0.6.0.md Shows how to configure checkpointing using the `checkpointing` method on the Executor in version 0.6.0. The `checkpoint` variable should be an instance implementing the `Checkpoint` trait. ```rust let result = Executor::new(problem, solver) .configure(|state| state.param(initial_param).max_iters(1000)) .checkpointing(checkpoint) .run()?; ``` -------------------------------- ### Configure and Activate Checkpointing with FileCheckpoint Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/checkpointing.md This snippet demonstrates how to initialize `FileCheckpoint` to save optimization states to disk. It specifies the directory, base file name, and the frequency of saving checkpoints. If a checkpoint exists, the optimization resumes from it; otherwise, it starts from scratch. ```rust # #[cfg(feature = "serde1")] let checkpoint = FileCheckpoint::new( // Directory ".checkpoints", // File base name "optim", // How often to save a checkpoint (in this case every 20 iterations) CheckpointingFrequency::Every(20) ); ``` -------------------------------- ### Implement CostFunction, Gradient, and Hessian for Rosenbrock Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/defining_optimization_problem.md Implement the CostFunction, Gradient, and Hessian traits for the Rosenbrock function. This example uses `Vec` for parameters and `f64` for cost, and `Vec>` for the Hessian. ```rust # extern crate argmin; # extern crate argmin_testfunctions; use argmin_testfunctions::{ rosenbrock, rosenbrock_derivative, rosenbrock_hessian }; use argmin::core::{Error, CostFunction, Gradient, Hessian}; /// First, we create a struct called `Rosenbrock` for your problem struct Rosenbrock {} /// Implement `CostFunction` for `Rosenbrock` /// /// First, we need to define the types which we will be using. Our parameter /// vector will be a `Vec` of `f64` values and our cost function value will /// be a 64 bit floating point value. /// This is reflected in the associated types `Param` and `Output`, respectively. /// /// The method `cost` then defines how the cost function is computed for a /// parameter vector `p`. Note that we have access to the fields `a` and `b` /// of `Rosenbrock`. impl CostFunction for Rosenbrock { /// Type of the parameter vector type Param = Vec; /// Type of the return value computed by the cost function type Output = f64; /// Apply the cost function to a parameter `p` fn cost(&self, p: &Self::Param) -> Result { // Evaluate Rosenbrock function Ok(rosenbrock(p)) } } /// Implement `Gradient` for `Rosenbrock` /// /// Similarly to `CostFunction`, we need to define the type of our parameter /// vectors and of the gradient we are computing. Since the gradient is also /// a vector, it is of type `Vec` just like `Param`. impl Gradient for Rosenbrock { /// Type of the parameter vector type Param = Vec; /// Type of the gradient type Gradient = Vec; /// Compute the gradient at parameter `p`. fn gradient(&self, p: &Self::Param) -> Result { // Compute gradient of the Rosenbrock function Ok(rosenbrock_derivative(p)) } } /// Implement `Hessian` for `Rosenbrock` /// /// Again the types of the involved parameter vector and the Hessian needs to /// be defined. Since the Hessian is a 2D matrix, we use `Vec>` here. impl Hessian for Rosenbrock { /// Type of the parameter vector type Param = Vec; /// Type of the Hessian type Hessian = Vec>; /// Compute the Hessian at parameter `p`. fn hessian(&self, p: &Self::Param) -> Result { // Compute Hessian of the Rosenbrock function Ok(rosenbrock_hessian(p)) } } ``` -------------------------------- ### Implement CostFunction, Gradient, and Hessian for Rosenbrock Source: https://context7.com/argmin-rs/argmin/llms.txt Define a struct and implement the `CostFunction`, `Gradient`, and `Hessian` traits for it to represent an optimization problem. This example uses the Rosenbrock function and its derivatives from the `argmin-testfunctions` crate. ```rust use argmin::core::{CostFunction, Gradient, Hessian, Error}; use argmin_testfunctions::{rosenbrock, rosenbrock_derivative, rosenbrock_hessian}; struct Rosenbrock {} impl CostFunction for Rosenbrock { type Param = Vec; type Output = f64; fn cost(&self, p: &Self::Param) -> Result { Ok(rosenbrock(p)) } } impl Gradient for Rosenbrock { type Param = Vec; type Gradient = Vec; fn gradient(&self, p: &Self::Param) -> Result { Ok(rosenbrock_derivative(p)) } } impl Hessian for Rosenbrock { type Param = Vec; type Hessian = Vec>; fn hessian(&self, p: &Self::Param) -> Result { Ok(rosenbrock_hessian(p)) } } ``` -------------------------------- ### Implement Custom Solver with `Solver` Trait in Rust Source: https://context7.com/argmin-rs/argmin/llms.txt Implement the `Solver` trait to integrate custom optimization algorithms. This example shows the Landweber iteration, requiring gradient information and parameter updates. ```rust use argmin::core::{ArgminFloat, Error, Gradient, IterState, KV, Problem, Solver, State}; use argmin::argmin_error_closure; use argmin_math::ArgminScaledSub; use serde::{Deserialize, Serialize}; /// Landweber iteration: x_{k+1} = x_k - ω ∇f(x_k) #[derive(Serialize, Deserialize)] pub struct Landweber { omega: F, // step length } impl Landweber { pub fn new(omega: F) -> Self { Landweber { omega } } } impl Solver> for Landweber where O: Gradient, P: Clone + ArgminScaledSub, F: ArgminFloat, { fn name(&self) -> &str { "Landweber" } fn next_iter( &mut self, problem: &mut Problem, mut state: IterState, ) -> Result<(IterState, Option), Error> { let xk = state.take_param().ok_or_else(argmin_error_closure!( NotInitialized, "Initial parameter vector required!" ))?; let grad = problem.gradient(&xk)?; let xkp1 = xk.scaled_sub(&self.omega, &grad); Ok((state.param(xkp1), None)) } } ``` -------------------------------- ### Setting up and running SteepestDescent solver Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/running_solver.md This snippet shows the complete process of setting up a SteepestDescent solver, configuring the executor with initial parameters and termination conditions, and running the optimization. It covers defining the cost function, initial parameters, line search, the solver itself, and the executor configuration. ```rust let cost = MyProblem {}; let init_param: Vec = vec![-1.2, 1.0]; let linesearch = MoreThuenteLineSearch::new(); let solver = SteepestDescent::new(linesearch); let res = Executor::new(cost, solver) .configure(|state| state .param(init_param) .max_iters(10) .target_cost(0.0) ) .run()?; ``` -------------------------------- ### Configure MathJax Inline and Display Math Source: https://github.com/argmin-rs/argmin/blob/main/media/website/templates/macros/math.html Configure MathJax to process inline and display math expressions using specified delimiters. This setup is useful for websites that embed mathematical formulas. ```javascript window.MathJax = { tex: { inlineMath: [['$', '$'], ['\\(', '\\)']], displayMath: [['$$', '$$'], ['\\\[', '\\\]']], processEscapes: true, processEnvironments: true, }, options: { skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre'], }, }; ``` -------------------------------- ### Run Spectator with Custom Host and Port Source: https://github.com/argmin-rs/argmin/blob/main/crates/spectator/README.md Launch the Spectator GUI tool, specifying a custom host and port to bind to. By default, it binds to 0.0.0.0:5498. ```bash spectator --host 127.0.0.1 --port 5498 ``` -------------------------------- ### Initialize KaTeX Rendering Source: https://github.com/argmin-rs/argmin/blob/main/crates/argmin-testfunctions/katex-header.html Renders LaTeX math expressions in the document body using KaTeX. Configure delimiters for inline and display math. ```javascript document.addEventListener("DOMContentLoaded", function() { renderMathInElement(document.body, { delimiters: [ {left: "$$", right: "$$", display: true}, {left: "$", right: "$", display: false}, ] }); }); ``` -------------------------------- ### Implement Operator trait for matrix multiplication Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/defining_optimization_problem.md Implement the Operator trait for a problem involving a 2x2 matrix multiplication. This example uses `Vec` for parameters and `Vec` for the output. ```rust # extern crate argmin; # extern crate argmin_testfunctions; use argmin::core::{Error, Operator}; struct MyProblem {} impl Operator for MyProblem { /// Type of the parameter vector type Param = Vec; /// Type of the output type Output = Vec; fn apply(&self, p: &Self::Param) -> Result { Ok(vec![4.0 * p[0] + 1.0 * p[1], 1.0 * p[0] + 3.0 * p[1]]) } } ``` -------------------------------- ### Configure Spectator Observer Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/observing.md Set up a Spectator observer to monitor optimization metrics. Configure the host, port, optimization name, and select specific metrics to be displayed. Defaults are provided for host and port if not specified. ```rust let spectator = SpectatorBuilder::new() // Optional: Defaults to 0.0.0.0 .with_host("127.0.0.1") // Optional: Defaults to 5498 .with_port(1234) // Optionally give optimization a name. // If not provided a random UUID will be used .with_name("something") // Optionally select a subset of the available metrics. // If omitted, all metrics will be selected. // Note that still all metrics are sent to spectator, // however; only those selected will be shown. // Spectator allows to select metrics in the GUI as well. .select(&["cost", "best_cost", "t"]) .build(); ``` -------------------------------- ### Configure Particle Swarm Optimization Solver in Rust Source: https://context7.com/argmin-rs/argmin/llms.txt Sets up the Particle Swarm Optimization solver with specified search bounds and swarm size. Requires a `CostFunction` implementation. Enable the `rayon` feature for parallel evaluation. ```rust use argmin::core::{CostFunction, Error, Executor}; use argmin::solver::particleswarm::ParticleSwarm; use argmin_testfunctions::himmelblau; struct Himmelblau {} impl CostFunction for Himmelblau { type Param = Vec; type Output = f64; fn cost(&self, p: &Vec) -> Result { Ok(himmelblau(&[p[0], p[1]])) } } fn main() -> Result<(), Error> { // Bounds: x ∈ [-4, 4], y ∈ [-4, 4]; 40 particles let solver = ParticleSwarm::new((vec![-4.0, -4.0], vec![4.0, 4.0]), 40); let res = Executor::new(Himmelblau {}, solver) .configure(|state| state.max_iters(100)) .run()?; println!("{res}"); // Himmelblau has four global minima at f ≈ 0: (3,2), (-2.805,3.131), (-3.779,-3.283), (3.584,-1.848) Ok(()) } ``` -------------------------------- ### Checkpointing Optimization Runs Source: https://context7.com/argmin-rs/argmin/llms.txt Configure file checkpointing to periodically save solver state for automatic resumption. Requires the `serde1` feature. ```rust use argmin::{ core:: checkpointing::CheckpointingFrequency, observers::ObserverMode, CostFunction, Error, Executor, Gradient, }, solver::landweber::Landweber, }; use argmin_checkpointing_file::FileCheckpoint; use argmin_observer_slog::SlogLogger; use argmin_testfunctions::{rosenbrock, rosenbrock_derivative}; #[derive(Default)] struct Rosenbrock {} impl CostFunction for Rosenbrock { type Param = Vec; type Output = f64; fn cost(&self, p: &Vec) -> Result { Ok(rosenbrock(p)) } } impl Gradient for Rosenbrock { type Param = Vec; type Gradient = Vec; fn gradient(&self, p: &Vec) -> Result, Error> { Ok(rosenbrock_derivative(p)) } } fn main() -> Result<(), Error> { let checkpoint = FileCheckpoint::new( ".checkpoints", // directory "rosenbrock_optim", // file base name → ".checkpoints/rosenbrock_optim.arg" CheckpointingFrequency::Every(20), // save every 20 iterations // Alternatives: CheckpointingFrequency::Always, CheckpointingFrequency::Never ); let res = Executor::new(Rosenbrock {}, Landweber::new(0.001)) .configure(|state| state.param(vec![1.2, 1.2]).max_iters(200)) .checkpointing(checkpoint) // resumes from disk if checkpoint exists .add_observer(SlogLogger::term(), ObserverMode::Always) .run()?; println!("{res}"); Ok(()) } ``` -------------------------------- ### Configure Simulated Annealing Solver in Rust Source: https://context7.com/argmin-rs/argmin/llms.txt Sets up the Simulated Annealing solver with custom temperature functions, stall detection, and reannealing parameters. Requires defining a `CostFunction` and an `Anneal` trait implementation. ```rust use argmin:: core::observers::ObserverMode, CostFunction, Error, Executor solver::simulatedannealing::{Anneal, SATempFunc, SimulatedAnnealing }; use argmin_observer_slog::SlogLogger; use argmin_testfunctions::rosenbrock; use rand::{distr::Uniform, prelude::* }; use rand_xoshiro::Xoshiro256PlusPlus; use std::sync::{Arc, Mutex }; struct Problem { lb: Vec, ub: Vec, rng: Arc> } impl Problem { fn new(lb: Vec, ub: Vec) -> Self { Self { lb, ub, rng: Arc::new(Mutex::new(Xoshiro256PlusPlus::from_os_rng())) } } } impl CostFunction for Problem { type Param = Vec; type Output = f64; fn cost(&self, p: &Vec) -> Result { Ok(rosenbrock(p)) } } impl Anneal for Problem { type Param = Vec; type Output = Vec; type Float = f64; fn anneal(&self, param: &Vec, temp: f64) -> Result, Error> { let mut p = param.clone(); let mut rng = self.rng.lock().unwrap(); let idx_d = Uniform::try_from(0..p.len())?; let val_d = Uniform::new_inclusive(-0.1, 0.1)?; for _ in 0..(temp.floor() as u64 + 1) { let idx = rng.sample(idx_d); p[idx] = (p[idx] + rng.sample(val_d)).clamp(self.lb[idx], self.ub[idx]); } Ok(p) } } fn main() -> Result<(), Error> { let solver = SimulatedAnnealing::new(15.0)? // initial temperature .with_temp_func(SATempFunc::Boltzmann) .with_stall_best(1000) .with_stall_accepted(1000) .with_reannealing_fixed(1000) .with_reannealing_best(800); let res = Executor::new(Problem::new(vec![-5.0, -5.0], vec![5.0, 5.0]), solver) .configure(|state| state.param(vec![1.0, 1.2]).max_iters(10_000).target_cost(0.0)) .add_observer(SlogLogger::term(), ObserverMode::Always) .run()?; println!("{res}"); Ok(()) } ``` -------------------------------- ### Run argmin-math crate with latest backends Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/contributing.md Execute tests for the `argmin-math` crate including default features plus the latest `ndarray`/`nalgebra` backends. This tests compatibility with the most recent versions of these common linear algebra libraries. ```bash cargo test -p argmin-math --features "latest_all" ``` -------------------------------- ### Run BFGS Solver with Executor and Logger Source: https://context7.com/argmin-rs/argmin/llms.txt Implements the full quasi-Newton BFGS method. Requires CostFunction, Gradient, and an initial inverse Hessian approximation. A logger can be added for monitoring. ```rust use argmin::{ core::{observers::ObserverMode, CostFunction, Error, Executor, Gradient}, solver::{linesearch::MoreThuenteLineSearch, quasinewton::BFGS}, }; use argmin_observer_slog::SlogLogger; use argmin_testfunctions::{rosenbrock, rosenbrock_derivative}; use ndarray::{array, Array1, Array2}; struct Rosenbrock {} impl CostFunction for Rosenbrock { type Param = Array1; type Output = f64; fn cost(&self, p: &Self::Param) -> Result { Ok(rosenbrock(&p.to_vec())) } } impl Gradient for Rosenbrock { type Param = Array1; type Gradient = Array1; fn gradient(&self, p: &Self::Param) -> Result, Error> { Ok(rosenbrock_derivative(&p.to_vec()).into()) } } fn main() -> Result<(), Error> { let solver = BFGS::new(MoreThuenteLineSearch::new().with_c(1e-4, 0.9)?); let res = Executor::new(Rosenbrock {}, solver) .configure(|state| state .param(array![-1.2, 1.0, -10.0, 2.0, 3.0, 2.0, 4.0, 10.0]) .inv_hessian(Array2::::eye(8)) // initial inverse Hessian .max_iters(60)) .add_observer(SlogLogger::term(), ObserverMode::Always) .run()?; println!("{res}"); Ok(()) } ``` -------------------------------- ### Run all features for argmin crate Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/contributing.md Execute tests for the `argmin` crate with all features enabled from the repository root. This ensures comprehensive testing across all functionalities. ```bash cargo test -p argmin --all-features ``` -------------------------------- ### Run Benchmarks with Cargo Source: https://github.com/argmin-rs/argmin/blob/main/crates/argmin-testfunctions/README.md Execute benchmarks for the argmin_testfunctions crate using Cargo. The reports will be available in `target/criterion/report/index.html`. ```bash cargo bench ``` -------------------------------- ### Run default tests for argmin-math crate Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/contributing.md Execute tests for the `argmin-math` crate with default features. This is a basic test to ensure the crate functions as expected with standard configurations. ```bash cargo test -p argmin-math ``` -------------------------------- ### Run SteepestDescent Solver with Executor Source: https://context7.com/argmin-rs/argmin/llms.txt Use Executor to pair a problem with a SteepestDescent solver. Configure initial conditions, parameters, and termination criteria. The run() method executes the optimization and returns results. ```rust use argmin::core::{CostFunction, Gradient, Error, Executor, State}; use argmin::solver::gradientdescent::SteepestDescent; use argmin::solver::linesearch::MoreThuenteLineSearch; use argmin_testfunctions::{rosenbrock, rosenbrock_derivative}; struct Rosenbrock {} impl CostFunction for Rosenbrock { type Param = Vec; type Output = f64; fn cost(&self, p: &Self::Param) -> Result { Ok(rosenbrock(p)) } } impl Gradient for Rosenbrock { type Param = Vec; type Gradient = Vec; fn gradient(&self, p: &Self::Param) -> Result, Error> { Ok(rosenbrock_derivative(p)) } } fn main() -> Result<(), Error> { let solver = SteepestDescent::new(MoreThuenteLineSearch::new()); let res = Executor::new(Rosenbrock {}, solver) .configure(|state| state .param(vec![-1.2, 1.0]) // initial parameter vector (required) .max_iters(100) // iteration budget .target_cost(1e-10)) // optional early-stop threshold .run()?; println!("{res}"); // formatted summary table // Extract results from the final state let best_param = res.state().get_best_param().unwrap(); let best_cost = res.state().get_best_cost(); let num_iters = res.state().get_iter(); let termination = res.state().get_termination_status(); let counts = res.state().get_func_counts(); // {"cost": N, "gradient": M, ...} println!("Best: {:?} cost={best_cost:.6e} iters={num_iters} status={termination:?}", best_param); println!("Function evaluations: {:?}", counts); Ok(()) } ``` -------------------------------- ### Landweber Solver Initialization Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/implementing_solver.md The `init` method for the Landweber solver. It checks if an initial parameter vector is provided in the state and returns an error if not. Otherwise, it returns the initial state. ```rust fn init( &mut self, _problem: &mut Problem, mut state: State, ) -> State { if state.current_param.is_none() { // Landweber requires an initial parameter vector. // In a real implementation, you would likely return an error here. // For simplicity, we'll just return the state as is, but this would fail later. return state; } state } ``` -------------------------------- ### HarmonicsSet Initialization (sphrs v0.1.3 vs v0.2.0) Source: https://github.com/argmin-rs/argmin/blob/main/media/website/content/blog/sphrs_v0.2.0.md Demonstrates the change in `HarmonicsSet` initialization between sphrs v0.1.3 and v0.2.0. Version 0.2.0 removes the need for type hints in generic parameters, simplifying the instantiation process. ```rust // Version 0.1.3 (required a type hint) // This will *not* compile in 0.2.0 let sh: HarmonicsSet = HarmonicsSet::new(degree, RealSHType::Spherical); // Version 0.2.0 (does not require a type hint) let sh = HarmonicsSet::new(degree, RealSHType::Spherical); ``` -------------------------------- ### Run Tests with Cargo Source: https://github.com/argmin-rs/argmin/blob/main/crates/argmin-testfunctions/README.md Execute all tests for the argmin_testfunctions crate using Cargo. ```bash cargo test ``` -------------------------------- ### Send Optimization Metrics to Spectator for Visualization Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/observing.md Integrate the `SpectatorBuilder` to send optimization metrics to the Spectator graphical visualization tool. Ensure `argmin-observer-spectator` is added as a dependency. ```rust # #![allow(unused_imports)] # extern crate argmin; # extern crate argmin_testfunctions; # use argmin::core::{Error, Executor, CostFunction, Gradient}; use argmin::core::observers::ObserverMode; use argmin_observer_spectator::SpectatorBuilder; # use argmin::solver::gradientdescent::SteepestDescent; ``` -------------------------------- ### Run L-BFGS Solver with Executor and Logger Source: https://context7.com/argmin-rs/argmin/llms.txt Utilizes the L-BFGS solver for memory-efficient optimization. Requires CostFunction, Gradient, and a line search. An optional SlogLogger can be added to observe the optimization process. ```rust use argmin::{ core::{observers::ObserverMode, CostFunction, Error, Executor, Gradient}, solver::{linesearch::MoreThuenteLineSearch, quasinewton::LBFGS}, }; use argmin_observer_slog::SlogLogger; use argmin_testfunctions::{rosenbrock, rosenbrock_derivative}; use ndarray::{array, Array1}; struct Rosenbrock {} impl CostFunction for Rosenbrock { type Param = Array1; type Output = f64; fn cost(&self, p: &Self::Param) -> Result { Ok(rosenbrock(&p.to_vec())) } } impl Gradient for Rosenbrock { type Param = Array1; type Gradient = Array1; fn gradient(&self, p: &Self::Param) -> Result, Error> { Ok(Array1::from(rosenbrock_derivative(&p.to_vec()).to_vec())) } } fn main() -> Result<(), Error> { let linesearch = MoreThuenteLineSearch::new().with_c(1e-4, 0.9)?; let solver = LBFGS::new(linesearch, 7); // history size = 7 let res = Executor::new(Rosenbrock {}, solver) .configure(|state| state.param(array![-1.2, 1.0]).max_iters(100)) .add_observer(SlogLogger::term(), ObserverMode::Always) .run()?; println!("{res}"); Ok(()) } // Expected output: converges to [1.0, 1.0] with cost ~0.0 within a few dozen iterations ``` -------------------------------- ### Add argmin and argmin-math to Cargo.toml Source: https://context7.com/argmin-rs/argmin/llms.txt Specify dependencies for argmin and choose math backend features in your Cargo.toml file. Optional crates for logging, checkpointing, and test functions can also be included. ```toml [dependencies] argmin = { version = "0.11" } # Choose which math backends to enable: argmin-math = { version = "0.5", features = ["ndarray_latest", "nalgebra_latest"] } # Optional crates: argmin-observer-slog = "0.7" # terminal/file logging argmin-checkpointing-file = "0.2" # disk checkpointing argmin_testfunctions = "0.3" # standard benchmark functions # Optional argmin features: # serde1 – enables checkpointing (requires serde) # ctrlc – clean Ctrl+C handling returning best result so far # rayon – parallel bulk evaluation (useful for PSO) # full – enables all of the above ``` -------------------------------- ### Newton's Method for Rosenbrock Function Source: https://context7.com/argmin-rs/argmin/llms.txt Implements Newton's method for optimization. Requires Gradient and Hessian implementations. Converges quadratically near the optimum for smooth functions. ```rust use argmin:: ::core::{observers::ObserverMode, Error, Executor, Gradient, Hessian}, ::solver::newton::Newton; use argmin_observer_slog::SlogLogger; use argmin_testfunctions::{rosenbrock_derivative, rosenbrock_hessian}; use ndarray::{Array, Array1, Array2}; struct Rosenbrock {} impl Gradient for Rosenbrock { type Param = Array1; type Gradient = Array1; fn gradient(&self, p: &Self::Param) -> Result, Error> { Ok(Array1::from(rosenbrock_derivative(&p.to_vec()))) } } impl Hessian for Rosenbrock { type Param = Array1; type Hessian = Array2; fn hessian(&self, p: &Self::Param) -> Result, Error> { let h: Vec = rosenbrock_hessian(&p.to_vec()).into_iter().flatten().collect(); Ok(Array::from_shape_vec((p.len(), p.len()), h)?) } } fn main() -> Result<(), Error> { let solver: Newton = Newton::new(); let res = Executor::new(Rosenbrock {}, solver) .configure(|state| state.param(Array1::from(vec![1.2, 1.2])).max_iters(10)) .add_observer(SlogLogger::term(), ObserverMode::Always) .run()?; println!("{res}"); Ok(()) } ``` -------------------------------- ### Nelder-Mead Solver for Multi-dimensional Optimization Source: https://context7.com/argmin-rs/argmin/llms.txt Use Nelder-Mead for derivative-free optimization when only a cost function is available. Requires an initial simplex of n+1 vertices for an n-dimensional problem. ```rust use argmin:: { core::observers::ObserverMode, CostFunction, Error, Executor, }; use argmin::solver::neldermead::NelderMead; use argmin_observer_slog::SlogLogger; use argmin_testfunctions::rosenbrock; use ndarray::{array, Array1}; struct Rosenbrock {} impl CostFunction for Rosenbrock { type Param = Array1; type Output = f64; fn cost(&self, p: &Self::Param) -> Result { Ok(rosenbrock(&p.to_vec())) } } fn main() -> Result<(), Error> { // 2D problem → provide 3 initial vertices let solver = NelderMead::new(vec![ array![-1.0, 3.0], array![ 2.0, 1.5], array![ 2.0,-1.0], ]) .with_sd_tolerance(0.0001)?; // standard deviation stopping criterion let res = Executor::new(Rosenbrock {}, solver) .configure(|state| state.max_iters(100)) .add_observer(SlogLogger::term(), ObserverMode::Always) .run()?; println!("{res}"); Ok(()) } ``` -------------------------------- ### Brent's Method for Univariate Optimization Source: https://context7.com/argmin-rs/argmin/llms.txt Utilize Brent's Method, a robust bracketing technique combining golden-section search and parabolic interpolation, for univariate minimization. Requires a scalar CostFunction and a search interval. ```rust use argmin:: { core::observers::ObserverMode, CostFunction, Error, Executor, }; use argmin::solver::brent::BrentOpt; use argmin_observer_slog::SlogLogger; struct TestFunc {} impl CostFunction for TestFunc { type Param = f64; type Output = f64; fn cost(&self, x: &f64) -> Result { Ok((-x).exp() - (5.0 - x / 2.0).exp()) // minimum near x ≈ -8.614 } } fn main() { let solver = BrentOpt::new(-10.0, 10.0); // search interval let res = Executor::new(TestFunc {}, solver) .configure(|state| state.max_iters(100)) .add_observer(SlogLogger::term(), ObserverMode::Always) .run() .unwrap(); println!("Result of Brent:\n{res}"); } ``` -------------------------------- ### Add argmin and argmin-math to Cargo.toml Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/using_argmin.md Include these dependencies in your Cargo.toml file to use argmin. The argmin-math dependency allows selection of math backends via features. ```toml [dependencies] argmin = { version = "0.11" } argmin-math = { version = "0.5", features = ["ndarray_latest", "nalgebra_latest"] } ``` ```toml [dependencies] argmin = { git = "https://github.com/argmin-rs/argmin" } argmin-math = { git = "https://github.com/argmin-rs/argmin", features = ["ndarray_latest", "nalgebra_latest"] } ``` -------------------------------- ### Coordinate Initialization (sphrs v0.1.3 vs v0.2.0) Source: https://github.com/argmin-rs/argmin/blob/main/media/website/content/blog/sphrs_v0.2.0.md Illustrates the change in `Coordinates` initialization between sphrs v0.1.3 and v0.2.0. Version 0.2.0 simplifies initialization by inferring the type from input arguments, removing the need for explicit type hints. ```rust // Version 0.1.3 (required a type hint) // Still compiles in 0.2.0 let p: Coordinates = Coordinates::spherical(1.0, 0.8, 0.4); // Version 0.2.0 (does not require a type hint) // The `T` of `Coordinates` will be equal to the type of the input arguments let p = Coordinates::spherical(1.0, 0.8, 0.4); ``` -------------------------------- ### Trust Region Method for Rosenbrock Function Source: https://context7.com/argmin-rs/argmin/llms.txt Implements a globally convergent second-order method using a trust region. Requires CostFunction, Gradient, and Hessian. The sub-problem can be solved with CauchyPoint, Dogleg, or Steihaug. ```rust use argmin:: ::core::{observers::ObserverMode, CostFunction, Error, Executor, Gradient, Hessian}, ::solver::trustregion::{Steihaug, TrustRegion}; use argmin_observer_slog::SlogLogger; use argmin_testfunctions::{rosenbrock, rosenbrock_derivative, rosenbrock_hessian}; use ndarray::{Array, Array1, Array2}; struct Rosenbrock {} impl CostFunction for Rosenbrock { type Param = Array1; type Output = f64; fn cost(&self, p: &Self::Param) -> Result { Ok(rosenbrock(&p.to_vec())) } } impl Gradient for Rosenbrock { type Param = Array1; type Gradient = Array1; fn gradient(&self, p: &Self::Param) -> Result, Error> { Ok(Array1::from(rosenbrock_derivative(&p.to_vec()))) } } impl Hessian for Rosenbrock { type Param = Array1; type Hessian = Array2; fn hessian(&self, p: &Self::Param) -> Result, Error> { let h: Vec = rosenbrock_hessian(&p.to_vec()).into_iter().flatten().collect(); Ok(Array::from_shape_vec((p.len(), p.len()), h)?) } } fn main() -> Result<(), Error> { let subproblem = Steihaug::new().with_max_iters(2); // Alternatives: CauchyPoint::new() or Dogleg::new() let solver = TrustRegion::new(subproblem); let res = Executor::new(Rosenbrock {}, solver) .configure(|state| state.param(Array1::from(vec![-1.2, 1.0])).max_iters(50)) .add_observer(SlogLogger::term(), ObserverMode::Always) .run()?; println!("{res}"); Ok(()) } ``` -------------------------------- ### Implement CostFunction and Gradient for a Problem Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/running_solver.md Implement the `CostFunction` and `Gradient` traits for your problem struct. This is required by solvers like SteepestDescent. Ensure the `Param` and `Output` types are correctly defined. ```rust # #![allow(unused_imports)] # extern crate argmin; # extern crate argmin_testfunctions; use argmin::core::{State, Error, Executor, CostFunction, Gradient}; use argmin::solver::gradientdescent::SteepestDescent; use argmin::solver::linesearch::MoreThuenteLineSearch; # use argmin_testfunctions::{rosenbrock, rosenbrock_derivative}; struct MyProblem {} // Implement `CostFunction` for `MyProblem` impl CostFunction for MyProblem { // [...] # /// Type of the parameter vector # type Param = Vec; # /// Type of the return value computed by the cost function # type Output = f64; # # /// Apply the cost function to a parameter `p` # fn cost(&self, p: &Self::Param) -> Result { # Ok(rosenbrock(p)) # } } // Implement `Gradient` for `MyProblem` impl Gradient for MyProblem { // [...] # /// Type of the parameter vector # type Param = Vec; # /// Type of the return value computed by the cost function # type Output = f64; # /// Type of the gradient # type Gradient = Vec; # # /// Compute the gradient at parameter `p`. # fn gradient(&self, p: &Self::Param) -> Result { # Ok(rosenbrock_derivative(p).to_vec()) # } } ``` -------------------------------- ### Bulk Evaluation for Parallel Solvers in Rust Source: https://context7.com/argmin-rs/argmin/llms.txt Implement `bulk_cost` and `bulk_gradient` for population-based solvers to evaluate multiple parameter vectors concurrently. The `parallelize()` method controls trait-level parallelization, defaulting to `true` when the `rayon` feature is enabled. ```rust use argmin::core::{CostFunction, Error, SyncAlias, SendAlias}; use argmin_testfunctions::rosenbrock; struct Rosenbrock {} impl CostFunction for Rosenbrock { type Param = Vec; type Output = f64; fn cost(&self, p: &Vec) -> Result { Ok(rosenbrock(p)) } // Override `parallelize` to disable parallelization for this trait // even when the `rayon` feature is enabled (default is `true`). fn parallelize(&self) -> bool { false // sequential evaluation for this cost function } // `bulk_cost` has a default implementation using rayon if feature is enabled. // Override only if custom batching logic is needed: fn bulk_cost<'a, P>(&self, params: &'a [P]) -> Result, Error> where P: std::borrow::Borrow + SyncAlias, Self::Output: SendAlias, Self: SyncAlias, { // Custom batch logic — e.g., chunked GPU dispatch params.iter().map(|p| self.cost(p.borrow())).collect() } } ``` -------------------------------- ### Setting a timeout for the Executor Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/running_solver.md This snippet illustrates how to set a maximum runtime for the optimization process using the `timeout` method on the `Executor`. The check for timeout occurs after each iteration, meaning the actual runtime might exceed the specified timeout. ```rust Executor::new(cost, solver) .configure(|state| state .param(init_param) .max_iters(10) .target_cost(0.0) ) .timeout(std::time::Duration::from_secs(5)) .run()?; ``` -------------------------------- ### Enable L1 Regularization in L-BFGS Source: https://github.com/argmin-rs/argmin/blob/main/media/website/content/blog/version-v0.7.0.md Use the `with_l1_regularization` method on the `LBFGS` solver to enable L1 regularization. Pass the non-negative L1 coefficient as an argument. This requires changes to `argmin-math` traits. ```rust let solver = LBFGS::new(linesearch, 7).with_l1_regularization(1.0)?; ``` -------------------------------- ### Landweber Solver Next Iteration Logic Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/implementing_solver.md Implements a single iteration of the Landweber solver. It retrieves the current parameters, computes the gradient, calculates the new parameters using the scaled subtraction, and updates the state. ```rust fn next_iter( &mut self, problem: &mut Problem, mut state: State, ) -> (State, Option>) { // Landweber requires an initial parameter vector. let xk = state.take_param().expect("Landweber requires an initial parameter vector."); // Compute gradient let grad = problem.gradient(&xk)?; // Compute new parameter vector: x_{k+1} = x_k - omega * grad let xkp1 = xk.scaled_sub(&self.omega, &grad)?; // Update state and return state.param(xkp1); (state, None) } ``` -------------------------------- ### Extracting results from the Executor state Source: https://github.com/argmin-rs/argmin/blob/main/media/book/src/running_solver.md After running the solver, this code demonstrates how to extract various pieces of information from the `Executor`'s result state, such as the best parameter vector, cost, termination status, and timing information. ```rust let best = res.state().get_best_param().unwrap(); let best_cost = res.state().get_best_cost(); let termination_status = res.state().get_termination_status(); let termination_reason = res.state().get_termination_reason(); let time_needed = res.state().get_time().unwrap(); let num_iterations = res.state().get_iter(); let num_iterations_best = res.state().get_last_best_iter(); let function_evaluation_counts = res.state().get_func_counts(); ``` -------------------------------- ### Gauss-Newton Method for Michaelis-Menten Kinetics Source: https://context7.com/argmin-rs/argmin/llms.txt Implements the Gauss-Newton method for nonlinear least-squares problems. Requires Operator (residuals) and Jacobian implementations. Minimizes the sum of squared residuals without needing a scalar cost function. ```rust use argmin:: ::core::{observers::ObserverMode, Error, Executor, Jacobian, Operator}, ::solver::gaussnewton::GaussNewton; use argmin_observer_slog::SlogLogger; use ndarray::{Array1, Array2}; struct MichaelisMenten { data: Vec<(f64, f64)> } impl Operator for MichaelisMenten { type Param = Array1; type Output = Array1; fn apply(&self, p: &Self::Param) -> Result, Error> { Ok(self.data.iter().map(|(s, r)| r - (p[0]*s)/(p[1]+s)).collect()) } } impl Jacobian for MichaelisMenten { type Param = Array1; type Jacobian = Array2; fn jacobian(&self, p: &Self::Param) -> Result, Error> { Ok(Array2::from_shape_fn((self.data.len(), 2), |(i, j)| { let s = self.data[i].0; if j == 0 { -s / (p[1]+s) } else { p[0]*s / (p[1]+s).powi(2) } })) } } fn main() -> Result<(), Error> { let problem = MichaelisMenten { data: vec![ (0.038,0.050),(0.194,0.127),(0.425,0.094),(0.626,0.2122), (1.253,0.2729),(2.5,0.2665),(3.74,0.3317), ]}; let solver: GaussNewton = GaussNewton::new(); let res = Executor::new(problem, solver) .configure(|state| state.param(Array1::from(vec![0.9, 0.2])).max_iters(10)) .add_observer(SlogLogger::term(), ObserverMode::Always) .run()?; println!("{res}"); // Converges to V_max ≈ 0.362, K_M ≈ 0.556 Ok(()) } ```