commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Luc Maisonobe <>
Subject [math] puzzled by generics in root solvers
Date Mon, 04 Jul 2011 20:16:29 GMT

I am a little puzzled by our use of generics in the analysis.solvers 

Hoping the following ASCII art will survive mail, here is a rough 
overview (simplified) of what we have.

         |                                       |
         |                                       |
  UnivariateRealSolver,         BaseAbstractUnivariateRealSolver<FUNC>
    PolynomialSolver,                            |
DifferentiableUnivariateRealSolver              |
         |                                       |
         |                                       |
            |                          |                |
AbstractUnivariate...   AbstractPolynomial... AbstractDifferentiable...
            |                          |                |
      +-----+----------+               |                |
      |                |               |                |
  BrentSolver, BaseSecantSolver   LaguerreSolver    NewtonSolver
       |              |               |
       |              |               |
       |              |               |
   Illinois      Pegasus        RegulaFalsi

At top level (lets call it level 0), there is a generified interface: 
BaseUnivariateRealSolver<FUNC extends UnivariateRealFunction>

One level below (lets call it level 1a), there are three interfaces that 
merely pin the generic type: UnivariateRealSolver for 
UnivariateRealFunction, PolynomialSolver for PolynomialFunction, 
DifferentiableUnivariateRealSolver for DifferentiableUnivariateRealFunction.

At the same level (lets call it level 1b) there is an abstract class: 
public abstract class BaseAbstractUnivariateRealSolver<FUNC extends 
UnivariateRealFunction> implements BaseUnivariateRealSolver<FUNC>.

One level below (lets call it level 2), we have three abstract classes 
that both extends BaseAbstractUnivariateRealSolver from level 1b and 
implement one of the interface from level 1a: 
AbstractUnivariateRealSolver, AbstractPolynomialSolver and 

One level below (lets call it level 3), we have a few implementations 
like BrentSolver and a bunch of others for general function, 
LaguerreSolver for polynomials and NewtonSolver for differentiable 

There are also levels 4 and 5 for the new bracketing solvers, since 
BaseSecantSolver from level 3 is itself an abstract class that has 
several implementations.

In parallel, there is the new interface BracketedUnivariateRealSolver 
which extends UnivariateRealSolver (not shown in the picture above).

I am at loss trying to create a wrapper class that would allow taking a 
non-bracketing solver and add bracketing features to it (merely by 
adding a few steps after the raw non-bracketing solver has found a root, 
in case it is not on the chosen side).

The first point is we use "UnivariateReal" both as the name of the 
topmost level type when nothing is specified (just as in the name of the 
level 0 interface and level 1b abstract class), and as the name of 
generic functions, in parallel with polynomial and differentiable 
functions. Shouldn't we have a different name for both notions ? We 
could have for example UnivariateRealFunction at top level and 
GeneralRealFunction at low level. This would help separate the meanings 
from level 1b and level 2.

The second point is I don't understand the purpose of interfaces from 
level 1a.

If on the one hand someone implements a solver by taking advantage of 
the generified BaseAbstractUnivariateRealSolver we provide, these 
interface merely force to add a redundant implement clause with 
declarations like the ones found at level 2:

   AbstractXxxsolver extends BaseAbstractXxxSolver<XxxFunction>
                     implements  XxxSolver

instead of using only

   AbstractXxxsolver extends BaseAbstractXxxSolver<XxxFunction>

If on the other hand someone implements a solver without taking 
advantage of the generified BaseAbstractXxxSolver we provide, these 
interface simply allow to write:

   AbstractXxxsolver implements  XxxSolver

instead of using only

   AbstractXxxsolver implements BaseUnivariateRealSolver<XxxFunction>

I think removing the interfaces from level 1b would simplify the 
architecture and help users understand. We would avoid the losange-shape 
inheritance between levels 0, 1a/1b and 2.

The third point is I think I messed thing when I inserted 
BracketedUnivariateRealSolver interface back in the hierarchy a few days 
ago by extending UnivariateRealSolver. I should probably have generified 
it and have it extend BaseUnivariateRealSolver<FUNC extends 
UnivariateRealSolver>, thus allowing to have bracketing solvers also for 
polynomials and differentiable functions. Do you agree with this ?

The fourth point is the generified BaseAbstractUnivariateRealSolver we 
provide (level 1b, right of the losange). It forces to implement a 
doSolve but in this method we cannot access the function itself and we 
cannot reset the evaluations: the fields are private and have no 
accessors, even protected, we can only call the function and 
incrementing the evaluation at the same time, counting from a setting 
the derived class cannot change. 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 ?

Well, sorry for this long message and the ugly picture. You have a few 
hours to read it, as I will not be able to discuss in the few next hours.

thanks for your attention ;-)


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

View raw message