|
| 1 | ++++ |
| 2 | +title = "argmin 0.8.0 and argmin-math 0.3.0 released" |
| 3 | +description = "" |
| 4 | +date = 2023-01-28T00:00:00+00:00 |
| 5 | +updated = 2023-01-28T00:00:00+00:00 |
| 6 | +draft = false |
| 7 | +template = "blog/page.html" |
| 8 | + |
| 9 | +[taxonomies] |
| 10 | +authors = ["Stefan Kroboth"] |
| 11 | + |
| 12 | +[extra] |
| 13 | ++++ |
| 14 | + |
| 15 | +<b>argmin</b> is a Rust library which offers a range of numerical optimization methods and a framework for |
| 16 | +developing optimization algorithms. <b>argmin-math</b> is a trait-based abstraction layer for mathematical operations, |
| 17 | +which makes argmin compatible with various math backends such as [ndarray](https://crates.io/crates/ndarray) and |
| 18 | +[nalgebra](https://crates.io/crates/nalgebra) (or your own backend). |
| 19 | +For details about the design of argmin and its features I suggest having a look at |
| 20 | +[the website](https://argmin-rs.org), |
| 21 | +[the book](https://argmin-rs.org/book), |
| 22 | +[Github](https://github.com/argmin-rs/argmin), |
| 23 | +[crates.io](https://crates.io/crates/argmin) and |
| 24 | +[lib.rs](https://lib.rs/crates/argmin). |
| 25 | + |
| 26 | +This is a short summary of the changes in argmin 0.8.0 and argmin-math 0.3.0. |
| 27 | +Both releases include breaking API changes; however upgrading from the previous versions should hopefully be fairly smooth. |
| 28 | +Don't hesitate [to get in touch](https://github.com/argmin-rs/argmin/issues) in case you run into problems during upgrading. |
| 29 | + |
| 30 | +## argmin 0.8.0 |
| 31 | + |
| 32 | +#### Improved termination handling |
| 33 | + |
| 34 | +The solver state contains a `TerminationReason` enum which indicates why the solver terminated. |
| 35 | +The enum variants offered in previous versions of argmin were either applicable to all solvers or were solver-specific. |
| 36 | +[@relf](https://github.com/relf) [rightfully pointed out](https://github.com/argmin-rs/argmin/issues/305) that these variants weren't ideal: |
| 37 | +For instance, it included an awkward variant `NotTerminated` and a couple of variants could be summarized as `Converged`. |
| 38 | +Whenever a `Ctrl+C` was intercepted, the reason would be `Aborted`, which is suboptimal because a solver could also abort |
| 39 | +due to other reasons. |
| 40 | +In the discussion we decided to change the `TerminationReason` enum to the following: |
| 41 | + |
| 42 | +```rust |
| 43 | +pub enum TerminationReason { |
| 44 | + /// Reached maximum number of iterations |
| 45 | + MaxItersReached, |
| 46 | + /// Reached target cost function value |
| 47 | + TargetCostReached, |
| 48 | + /// Algorithm manually interrupted with Ctrl+C |
| 49 | + KeyboardInterrupt, |
| 50 | + /// Converged |
| 51 | + SolverConverged, |
| 52 | + /// Solver exit with given reason |
| 53 | + SolverExit(String), |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +The first two are potential outcomes of two checks performed by the `Executor` for every solver. |
| 58 | +`KeyboardInterrupt` replaces `Aborted` and is only used for `Ctrl+C`. |
| 59 | +`SolverConverged` indicates a successful optimization run and `SolverExit(String)` is used for |
| 60 | +cases where the solver stopped for a solver-specific reason specified by a string. |
| 61 | + |
| 62 | +The awkward `NotTerminated` was dropped and instead a new enum `TerminationStatus` is introduced: |
| 63 | + |
| 64 | +```rust |
| 65 | +enum TerminationStatus { |
| 66 | + NotTerminated, |
| 67 | + Terminated(TerminationReason) |
| 68 | +} |
| 69 | +``` |
| 70 | + |
| 71 | +This enum is stored in the state instead of `TerminationReason`. |
| 72 | +It can be obtained from an `OptimizationResult` via the solver state: |
| 73 | + |
| 74 | +```rust |
| 75 | +// of type &TerminationStatus |
| 76 | +let status = result.state().get_termination_status(); |
| 77 | + |
| 78 | +// ... or ... |
| 79 | + |
| 80 | +// of type Option<&TerminationReason> |
| 81 | +let reason = result.state().get_termination_reason(); |
| 82 | +``` |
| 83 | + |
| 84 | +Both methods are part of the `State` trait and as such available for all available states. |
| 85 | + |
| 86 | +Note that this is a breaking change and as such you may have to adapt your code, in particular if you use the returned |
| 87 | +termination reason. |
| 88 | + |
| 89 | +Huge thanks to [@relf](https://github.com/relf) for the fruitful discussion and for doing all the heavy lifting! |
| 90 | + |
| 91 | + |
| 92 | +#### Changes to the observer interface |
| 93 | + |
| 94 | +In the past, values sent to the observers were only `dyn Display`, which means they could effectively only be turned into strings. |
| 95 | +To get the actual value one had to parse the strings into a given type, which isn't great (to put it mildly). |
| 96 | + |
| 97 | +Therefore I decided [to make the values sent to the observers typed](https://github.com/argmin-rs/argmin/pull/269) and |
| 98 | +added support for 64bit floats, signed and unsigned 64bit integer, Booleans and Strings via the `KvValue` enum: |
| 99 | + |
| 100 | +```rust |
| 101 | +pub enum KvValue { |
| 102 | + Float(f64), |
| 103 | + Int(i64), |
| 104 | + Uint(u64), |
| 105 | + Bool(bool), |
| 106 | + Str(String), |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +The actual values can be retrieved via the getters `get_float`, `get_int`, `get_uint`, `get_bool` and `get_string`, |
| 111 | +which return `Some(<inner_value>)` if the `KvValue` is of the appropriate type and `None` otherwise. |
| 112 | + |
| 113 | +The `make_kv!` macro used in solvers to construct the Key-Value store was renamed to `kv!`. |
| 114 | + |
| 115 | +These changes will only affect you if you wrote an observer or solver yourself. |
| 116 | +All observers shipped with argmin should continue to work as before. |
| 117 | + |
| 118 | +#### Other |
| 119 | + |
| 120 | +* Implementing the `Solver` trait for a solver does not require anymore that the solver implements `serde::Serialize` when the `serde1` feature is enabled. |
| 121 | +This was a remnant of an earlier design of the `Solver` trait found by [@relf](https://github.com/relf). |
| 122 | +Note that checkpointing requires solvers to be serializable! |
| 123 | +Therefore, despite lifting this requirement, it is still recommended that solvers are (de)serializable if possible. |
| 124 | +* The check whether an optional target cost is reached is now based on the best cost function value so far rather than the current cost function value ([@relf](https://github.com/relf)) |
| 125 | +* Added a `full` feature which activates all features. |
| 126 | +* Added a particle swarm optimization and L-BFGS example using the nalgebra backend. |
| 127 | +* Elapsed time is now computed using `as_secs_f64` ([@TheIronBorn](https://github.com/TheIronBorn)) |
| 128 | +* Internally uses argmin-math 0.3.0, so make sure to update both! |
| 129 | + |
| 130 | +## argmin-math 0.3.0 |
| 131 | + |
| 132 | +With this release all backends finally implement all math-related traits, meaning that every backend now works with every solver. |
| 133 | +The only exception to this is the `vec` backend, which does not implement `ArgminInv` and as such does not |
| 134 | +work with (Gauss-)Newton methods. |
| 135 | +I've spent multiple days tediously implementing all missing traits and adding tests for every implementation |
| 136 | +(eventually reaching 100% test coverage). |
| 137 | +[@hypotrochoid](https://github.com/hypotrochoid) implemented the `ArgminRandom` trait for the ndarray backend |
| 138 | +and with that kicked off this entire endeavour. Thanks! |
| 139 | + |
| 140 | +Apart from that support for nalgebra 0.32 was added and ndarray-linalg was updated from version 0.14 to 0.16 for |
| 141 | +the ndarray v0.15 backend. |
| 142 | +Therefore you may have to update ndarray-linalg as well. |
| 143 | + |
| 144 | +Upgrading to version 0.3.0 of argmin-math should be smooth for most cases. |
| 145 | + |
| 146 | +## Other news |
| 147 | + |
| 148 | +argmin is not only a collection of optimization algorithms but also aims to be a framework which facilitates |
| 149 | +the development of optimization algorithms. |
| 150 | +Solvers implemented using argmin get features such as checkpointing, observers and support for various math backends for free. |
| 151 | + |
| 152 | +However, I have not seen any use of this feature outside of argmin itself up until recently, when [@relf](https://github.com/relf) |
| 153 | +made his [egobox-ego solver](https://crates.io/crates/egobox-ego) |
| 154 | +[compatible with argmin](https://github.com/relf/egobox/pull/67). |
| 155 | +This is very exciting for me as this led to valuable feedback on the design of argmin and I hope that others will follow |
| 156 | +that example and make their solvers compatible with argmin. |
| 157 | + |
| 158 | + |
| 159 | +<br> |
| 160 | +<script async defer src="https://buttons.github.io/buttons.js"></script> |
| 161 | +<p align="center"> |
| 162 | +<a class="github-button" href="https://github.com/argmin-rs/argmin" data-icon="octicon-star" data-size="large" data-show-count="true" aria-label="Star argmin-rs/argmin on GitHub">Star</a> |
| 163 | +<a class="github-button" href="https://github.com/argmin-rs/argmin/subscription" data-icon="octicon-eye" data-size="large" data-show-count="true" aria-label="Watch argmin-rs/argmin on GitHub">Watch</a> |
| 164 | +<a class="github-button" href="https://github.com/argmin-rs/argmin/fork" data-icon="octicon-repo-forked" data-size="large" data-show-count="true" aria-label="Fork argmin-rs/argmin on GitHub">Fork</a> |
| 165 | +<a class="github-button" href="https://github.com/sponsors/stefan-k" data-icon="octicon-heart" data-size="large" aria-label="Sponsor @stefan-k on GitHub">Sponsor</a> |
| 166 | +</p> |
0 commit comments