On Thu, Jan 27, 2011 at 6:50 AM, Gilles Sadowski <gil...@harfang.homelinux.org> wrote: > Hi. > >> > I need some clarifications before embarking into the clean-up of that >> > package. >> > >> > The "integrate" method of interface "UnivariateRealIntegrator" is defined >> > as: >> > double integrate(UnivariateRealFunction f, double min, double max) >> > throws ConvergenceException, MathUserException, >> > IllegalArgumentException; >> > >> > As a comparison, a "solve" methods from the solver interface: >> > double solve(int maxEval, FUNC f, double min, double max); >> > >> > (1) Is the notion of "iteration" for the integrator similar to the number >> > of >> > evaluation for the solvers? In other words, shall we now pass the (minimal >> > and maximal) numbers of iterations as parameters of "integrate"? >> > >> I can't remember why we decided to move away from having the maximum >> number of iterations a property of the solver, [...] > > In the case of solvers, we suppose that the comparison of the efficiency of > different solvers is based on the number of calls to the function to be > solved (if the function evaluation is relatively slower than the solver code > itself). The number of iterations is only an implementation detail of the > solver code. > The maxIterations setting, like the absolute and relative accuracy settings, are things we want to be able to reuse across activations, but they are part of the configuration of the numerical problem - no different actually than the upper and lower bounds or even the function itself. The numerical problem is "find a root of the function within the designated interval in less than max iterations with stopping criteria defined by the accuracy settings." If you change any of these configuration settings you may get different results. They are all parameters of the numerical problem being solved. If, for example, you are working with a function that has many roots in the interval, changing accuracy for the solver may result in (an approximation to) a different root being returned.
>> but the same concept >> does apply to integrators. So to be consistent, we should probably >> make that change. > > Which concept? The concept of iteration up to a configured maximum number of iterations and convergence defined by the iterates getting close. > Alternative 1: > Do we have to consider only the number of evaluations, thus that > for the integrators too, the number of iterations is an implementation > detail (i.e. not allowing the user to set it)? [Change of semantics (and > interface).] The user needs to be able to set the maximum number of iterations. Given a fixed algorithm, the number of iterations is a configuration parameter. It represents the maximum number of times that the main iteration loop in the algorithm can be executed. The nature of the algorithm is documented and is part of the contract, so this is a config parameter that makes sense to expose to the user and allow the user to set. It will in general be more meaningful and easier to understand from the numerical analysis standpoint than the number of function evaluations, which while also useful to be able to control is in general harder to relate to the numerical algorithm (this really depends on the algorithm and the exact relationship will be more prone to implementation-specific variation than the number of iterations, which should in general mean the same thing in different implementations of the same algorithm). > Alternative 2: > Is the number of iterations still a user-defined property in the case of > integrators but it should be passed in the call to "integrate". [Change of > interface.] > Or did you mean yet something else? > I meant that the user needs to be able to specify it. I think the real issue here is what we are talking about above and below on object properties vs. method parameters. >> >> > (2) Should there also be a limit on the number of function evaluations? >> > >> I think that would be a good enhancement here and actually for the >> solvers as well. We need to think carefully though about the burden >> that this places on implementations. > > As reminded above, changing from an iteration-based to an evaluation-based > criterion makes it possible to uniformly set a time limit when solving or > optimizing a function. > I started that thread because I'm not so sure that it is useful for > integrators. > In other words, is it a common pattern where one would say: "I want to > compute this integral in less than n evaluations of the function." ? > Not as common as setting max iterations, but it could be useful as an optional configuration setting. I would see it working as an *additional* requirement, not replacing maxIterations - i.e., we throw ConvergenceException when either one of these constraints is violated. I need to review all of the integratiors though to make sure this is tractable (tracking function evaluations) and end-user meaningful. >> > (3) We have here an occurrence of "ConvergenceException" whereas the >> > potential problems that can actually occur are that the number of >> > iterations >> > is too low or too high. >> > I thus propose to use the existing "MaxCountExceededException" for "too >> > many >> > iterations". Shall I create a "MinCountNotReachedException" for "too few >> > iterations"? >> >> Where do we throw on too few iterations? Generally that is not an >> issue. [...] > > See the doc of "setMinimalIterationCount" in "UnivariateRealIntegrator". > >> In any case, per my previous post on ConvergenceException, I >> see MaxIterationsExceeded as logically a subclass of >> ConvergenceException. > > In reply to that post, I reminded that there exists a > "MaxCountExceededException" that is a sub-class of > "MathIllegalStateException". > "MaxCountExceededException" is thrown by the very low-level "Incrementor" > class, and so it cannot be a subclass of a high-level concept such > "ConvergenceException". > A possible way out of this dilemma could be that "ConvergenceException" > objects will wrap a "cause" exception. Hence we could have: > > public class ConvergenceException extends MathRuntimeException { > private MathRuntimeException cause; > > public ConvergenceException(MathRuntimeException cause) { > this.cause = cause; > } Or we could refactor MaxCountExceeded to be a subclass of ConvergenceException, or define a different exception altogether. Another useful thing that could be carried along in the MaximumIterationsExceeded exception is the value of the last iterate. A question to ask about MaxCountExceeded is are there uses other than converging numerical algorithms. > // ... > } > > and > > public class MaxIterationExceededException extends ConvergenceException { > private final int max; > public MaxIterationExceededException(MaxCountExceededException cause) { > super(cause); > max = cause.getMax(); > } > // ... > } > >> Another logical alternative would be to define >> an enum characterizing the failed convergence in ConvergenceException >> as diverge to +inf, diverge to -inf, diverge to NaN, max iterations >> exceeded and add a property to ConvergenceException holding this >> value. I favor separating out the subclasses because they can then >> carry more information [...] > > +1 for subclasses. > >> such as, for the divergence subclasses, the >> iteration number where the out of range value occured and for the max >> iterations exceeded what the max is. > > Indeed; cf. above for the "max" example. > >> > >> > (4) Is it OK to pass accuracy parameters as arguments to the constructors >> > (as is done for the solvers)? >> > >> Yes, but I am wondering why this is different from the maxIterations. >> Why are the accuracy properties properties of the solver and max >> iterations a method parameter? To be consistent, we should probably >> move all the way to the procedure style and pass these parameters to >> the solve/integrate methods as well. > > With this comes some subjectivity. > I tend to see the accuracy properties as tied to the solver code while the > number of function evaluations is more function-dependent. > Hence -1 for a full procedure-style (although admittedly more consistent > if we only consider syntactic uniformity). > I think I agree with you on not going all the way to full procedural style, but I am struggling with where to draw the line. One natural line for the solvers is how we used to have it - just pass the interval endpoints and have setters / constructor arguments for everything else. Then we decided it would be convenient to be able to pass the function itself and that opened the door to maxIter, and so on in method signatures. I am thinking now that what might be best is to maximize user flexibility by keeping the config settings as properties of the implementation classes, exposing constructors for all reasonable combinations of them, defaults where this makes sense, setters for all of them, and also allow all reasonable combinations to be passed - essentially overriding the configured setting -- at method activation time. For cases where "all reasonable combinations" becomes unwieldy, we could define configuration objects - e.g. RootFindingProblem (I think we have done this kind of thing in some of the optimization classes) and pass config instances as in solve(problem). I don't think we necessarily need to do that for the solvers or integrators. Phil > > --------------------------------------------------------------------- > 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