commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Gilles <>
Subject Re: [Math] Fluent API, inheritance and immutability
Date Wed, 14 Aug 2013 22:34:55 GMT

> > [...]
> Since the iteration counter was incremented explicitly I thought it 
> made
> sense to increment the evaluation counter explicitly.

It's indeed cleaner to have the two counters handled in a similar
fashion. Actually, the iteration counter was an afterthought: Driven
by my current usage (where an evaluation is much more time consuming
than the optimization algorithm book-keeping), I assumed that the
evaluation counter was a more objective way to limit the effort.
But if your proposal is amenable to create customized instances of
"LeastSquaresProblem" that use one or the other (or both), it starts
to look definitely interesting.

> With the interface
> based design it would be easy to create a wrapper to track 
> evaluations
> to keep the original semantics:
> public static LeastSquareProblem countEvaluations(final
> LeastSquaresProblem lsp, final Incrementor counter){
>     return new LeastSquaresProblem(){
>         /* delegate all other methods to lsp */
>         public Evaluation evaluate(double[] point){
>             counter.increment();
>             return lsp.evaluate(point);
>         }
>     };
> }

With this ...

> [...]

> I think the weights are definitely part of the "problem". I hesitate 
> if
> there should be a getWeights() method in the API. It seems to me that
> the weights could just be applied to the residuals and Jacobian and 
> the
> algorithm wouldn't know the difference. (Maybe this is naive.) The
> weight functionality could be added to the "problem" using 
> composition
> (a wrapper class) and not though explicit API support. For example,
> remove getWeigts() from LeastSquaresProblem and use the composition:
> static LeastSquaresProblem weight(LeastSquaresProblem lsp, RealMatrix
> weights) {
>     return new LeastSquaresProblem(){
>         /* delegation, apply weights ... */
>     };
> }

... and this, I now start to see the advantage of the 
It seems then that instances should indeed be created using a "Builder"
pattern; it would ultimately return a "read-only" instances as you 

> The common case of a diagonal weight matrix could have its own, 
> possible
> more efficient, composition.

If those customizations can be set up in a "LSP" factory, that would be
quite fine.

>>>   - Should the LeastSquaresProblem interface include mutators? I 
>>> think
>>> it makes sense to only include the methods that the optimization
>>> algorithm needs to "read". That would keep the API smaller and not 
>>> tie
>>> the users to a particular implementation.
>> Hmm, do you suggest here that we drop the fluent API (whose purpose 
>> is
>> indeed to mutate fields)?
> I suggest that the interface only include the "get" and "evaluate"
> methods. This is all the information the optimization algorithm 
> needs.
> It also makes composition easier. The LeastSquaresProblemImpl class
> could implement a fluent API. Then the user use new
> LeastSquaresProblemImpl().withXxx() and the LeastSquaresProblem
> interface wouldn't place more requirements than necessary on all
> implementations.

I also agree with that.

> [...]
>> Could we create an "o.a.c.m.experimental" sub-package, and put
>> "competing" designs inside it: e.g.
>>   o.a.c.m.experimental.evan
>>   o.a.c.m.experimental.gilles
>> for people to test with 3.3, and postpone a decision until we can 
>> see
>> better the differences? Maybe this would allow to pick all the 
>> better
>> features from each and merge them in a final design...
> I agree it definitely needs more testing and polishing. Let me think
> about the two development lines idea. I would hate for us to 
> duplicate
> our work and then "throw away" one person's work at the end.

At this point, I'd tend to think that creating a copy of trunk in the
Commons's "sandbox" part of the repository will be more productive.
There, we can both directly modify the code to make a point and
converge to a design while incrementally ensure that every features
turn out as imagined.
So, for me, the selling point would be the "LSP" customisation process
i.e. (unless the devil appears in the details) abstract away from the
core optimizer everything that is a user decision: counting
evaluations and/or iterations (and what to do when the counter is
exhausted), apply weights, set up callbacks (beyond the convergence
checker) that would allow to e.g. track the optimizer's search path, 


To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message