Hi Gilles, ----- "Gilles Sadowski" <gil...@harfang.homelinux.org> a écrit :
> Hello. > > > [...] > > > > > > The purpose of the "BaseUnivariateRealSolver<T>" is to avoid code > > > duplication in CM. It must be general enough so that CM > developers > > > should > > > not implement an "AbstractXxxsolver" that would not inherit from > it. > > > > OK, so I think we need to introduce slight changes. > > > > [...] > > > > > > > I need access to the > > > > function and I need access to the counter. So i think I will > add > > > > some accessors for them. Does this seems reasonable to other > > > > developers ? > > > > > > In refactoring the "solvers" package, I removed a lot of > "protected" > > > fields. > > > The current design shows that they were not necessary. Also they > are > > > not > > > desirable because they break encapsulation. I'd rather find a way > to > > > avoid > > > accessors, and figure out why the new interface does not fit in > the > > > design; > > > if we can change it to fit or if we can improve the design so that > it > > > fits... > > > > I'm still trying to find a way to solve my use case without adding > these accessors, but up to now I failed. > > > > Here is my problem: we have introduced bracketed solvers that allow > to drive the solver in selecting a specific side when converging close > to a root. This is a very interesting feature as it really simplifies > lots of top level management of epsilon values and small ugly tricks > when the solver converges just on the wrong side from user point of > view. The three new secant based solvers implement this feature > autonomously, but it would be really interesting to have it available > also for other regular solvers. So I started to implement a wrapper > that would take a regular (non-bracketing) solver, use it to come > close to a root and then add some checks and post-processing to > slightly shift it to the right side in case the non-bracketing solver > happens to have chosen the wrong side. > > > > At first, I thought this could be done as follows: > > > > public class BracketingWrapperSolver<FUNC extends > UnivariateRealFunction> > > extends BaseAbstractUnivariateRealSolver<FUNC> > > implements BracketedUnivariateRealSolver<FUNC> { > > > > private final BaseUnivariateRealSolver<FUNC> solver; > > > > protected double doSolve() { > > > > // call the underlying non-bracketing solver > > double x0 = solver.solve(getMaxEvaluations(), getFunction(), > > getMin(), getMax(), getStartValue()); > > > > // create a bracketing solver for the very small neighborhood of > the root > > PegasusSolver bracketing = new > PegasusSolver(solver.getRelativeAccuracy(), > > > solver.getAbsoluteAccuracy()); > > > > // select the side > > bracketing.setAllowedSolutions(getAllowedSolutions()); > > > > // compute a safety margin > > // TODO: add a loop with incresing size and bracketing checks > > double margin = 10 * solver.getAbsoluteAccuracy(); > > > > // compute the root on the selected side > > return bracketing.solve(getMaxEvaluations() - > solver.getEvaluations(), > > getFunction(), > > x0 - margin, x0 + margin, x0); > > > > } > > > > } > > > > This does the trick, but needs access to the function thanks to a > getFunction() accessor. > > I understand the idea from the coding point-of-view. > But IIUC, I'm afraid that this whole class is rather contorted; and > you did > not show how a user would instantiate it. It seems that it would bring > the > "cumbersomeness" of generics back to the user level: > > BracketedUnivariateRealSolver<DifferentiableUnivariateRealFunction> > solver > = new > BracketingWrapperSolver<DifferentiableUnivariateRealFunction>(new > NewtonSolver()); Yes. We could also hide this by creating specialized class with empty bodies and the generic parameter already instanciated, as you did with the top level interfaces. > > If such a fine control ("AllowedSolutions") is a desirable/necessary > feature, couldn't we directly add it at the level of the base class > (and > interface)? I.e. the main "solve" method would become: > > public abstract class BaseAbstractUnivariateRealSolver<FUNC extends > UnivariateRealFunction> > implements BaseUnivariateRealSolver<FUNC> { > > // ... > > public double solve(int maxEval, FUNC f, > double min, double max, double startValue, > AllowedSolutions solutionType) { > // Initialization. > setup(maxEval, f, min, max, startValue, solutionType); > > // Perform computation. > final double baseRoot = doSolve(); > > if (solutionType == EITHER_SIDE || > this instanceof BracketedUnivariateRealSolver) { > return baseRoot; > } else { > PegasusSolver bracketing = new > PegasusSolver(relativeAccuracy, > > absoluteAccuracy); > double margin = 10 * absoluteAccuracy; > return bracketing.solve(getMaxEvaluations() - > getEvaluations(), f, > baseRoot - margin, baseRoot + > margin, > baseRoot, solutionType); > } > } > } Yes, it is a smarter solution than mine, I like it, thanks! We should be careful when documenting this method, since it allows *all* solvers to use the bracketing feature magically and without user help, even the non-bracketing ones. I hope we can explain that without causing headache to our users or raising question like "hey, but then what is the difference between bracketing and non bracketing solvers?". best regards, Luc > > > [...] > > > Best, > Gilles > > --------------------------------------------------------------------- > To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org > For additional commands, e-mail: dev-h...@commons.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org