Comments (5)
This is an excellent suggestion, thanks a lot! This would solve many problems, in particular it would remove the ugly base
field and I suppose it will solve a problem I'm having with trait bounds. I don't mind having two structs.
I'll probably give this a try this weekend.
Good luck with your exams! :)
from argmin.
When I implemented the codegen crate I was well aware that I'm doing this mostly for vanity reasons and for my ego, but I thought it was serving at least some purpose. It wasn't. While implementing your suggestion it became clear that the old design made everything much more complicated than necessary.
Over the last week I've changed the design completely and simplified other parts along the way. Overall many problems I've had with the previous design vanished with the new design. It is still not entirely done but I think the major parts work. Therefore I've merged it into master. I will continue improving the design and documentation over the next days and I will reimplement the tests for the new design.
Thanks once again for your suggestion! If you have time and if you are interested, I'd appreciate it if you would contribute! :)
from argmin.
Hi, thanks for this comment. I was actually considering this a while ago but soon gave up, secretly hoping that someone will suggest this and therefore force me to think about it again in detail. So, thanks, I guess ;)
I do really like the builder pattern, but I see some problems with it, namely because I think the design of this crate should follow two principles:
-
Because of future plans I have, the solvers should be object safe (meaning that none of the methods in the
ArgminSolver
trait can returnSelf
). -
It should be completely transparent to the user whether a method is part of the
ArgminSolver
trait or is part ofimpl MySolver { ... }
.
Currently, a solver is implemented like this (very, very simplified):
#[derive(ArgminSolver)]
struct MySolver {
variable: f64,
base: ArgminBase,
}
impl MySolver {
pub fn new() -> Self {
MySolver {
variable: 1.0,
base: ArgminBase::new(),
}
}
pub fn set_variable(&mut self, var: f64) {
self.variable = var;
}
}
impl ArgminNextIter for MySolver {
// Not important for the purpose of this example
}
The #[derive(ArgminSolver)]
macro (which is currently rather stupid) will create something like this:
impl ArgminSolver for MySolver {
// Associated types and a bunch of methods
// example method
fn set_max_iters(iters: u64) {
self.base.set_max_iters(iters);
}
}
I have difficulty seeing where the builder should come in. If there were a MySolverBuilder
, then the user would first have to call set_variable
on the builder, build it (in order to get a MySolver
), and then call set_max_iters()
. From the point of view of a user, this makes no sense and it violates principle number 2 from above (and it isn't really a builder pattern anymore).
Currently, all the setters (which essentially act on the base
field of MySolver
) are part of the ArgminSolver
trait. If those should follow a builder pattern, they would need to return Self
and therefore could not be part of ArgminSolver
(because of object safety (principle number 1)), but instead would need to belong to another (not yet existing) trait (ArgminSolverBuilder
perhaps?). This is possible, and probably the most viable way, but then there would be two builders, one implemented via the ArgminSolverBuilder
trait (which could be derived automatically) and one by the struct MySolverBuilder
. I'm not sure how they'd work together, but I suppose it would work. It would certainly solve some of the ugliness in some of the line searches, but in general I'm not sure whether it is worth the effort.
I hope this wasn't too confusing. I'm happy to give my explanations another try if they are incomprehensible ;)
What do you think about this? Do you have any other suggestions/views?
Would you be interested in giving this a shot in a PR? This would be quite a deep dive into the codebase, but I'd obviously help as much as I can.
Greetings from the south ;)
from argmin.
This seems indeed very difficult, perhaps yet another option would be to split each solver into a struct which executes the optimization (i.e. the ArgMinBase
struct) and the actual routine with its parameters. This has the advantage that you won't need the derivation crate to emulate classes and you can implement separate builder with different return types. Obviously the API surface is more complex because you have to use at least to struct to initiate an optimization process.
...
let solver = BacktrackingLineSearch::new(operator, cond)
.set_search_direction(vec![-2.0, 0.0])
.set_rho(0.9)?
...;
let executor = Framework::new()
.with_solver(solver)
.max_iters(1000)
.add_logger(ArgminSlogLogger::term())
.run()?;
I don't know which one is more sensible, but for now I have no time because of exam time, perhaps in the middle of march :)
from argmin.
Glad I could help :)
from argmin.
Related Issues (20)
- Missing proper documentation on how to run examples
- Create inplace variants of math traits
- ParticleSwarm is not reproducible HOT 3
- More-Thuente Linesearch Algorithm Bug: "Search direction must be a descent direction" HOT 7
- BrentRoot is missing tests
- Add `faer-rs` as math backend
- Add stopping criteria based on the number of function evaluations
- Add LaTeX support to docs
- Add derivatives and Hessians to test functions in argmin_testfunctions
- Add more test functions to `argmin_testfunctions`
- Create visualization of all test functions in `argmin_testfunctions`
- `owl-qn` example does not converge HOT 4
- Observers and checkpointing are missing tests
- Enable observers to create final report
- Thoughts on future state handling
- Various non productive overhead HOT 1
- Example (lbfgs) cannot be compiled after upgrade to version 0.10 HOT 2
- rss/atom feed of the blog HOT 1
- newton and newton cg freeze rather than stopping HOT 1
- Difference between bfgs.rs and bfgs of optimtool.unconstrain.newton_quasi HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from argmin.