You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Luc Maisonobe <lu...@spaceroots.org> on 2012/10/04 21:43:47 UTC

Re [Math] About the API of the optimizers

[Sorry for the strange format of this mail, but I managed to lose the
original message from Gilles, so had to recreate it by copy/paste and
adding the quotation marks by hand...]

Gilles wrote:
> Hello.
> 
> This issue https://issues.apache.org/jira/browse/MATH-872 is about a 
> workaround similar to one already existing for "SimplexOptimizer",
> i.e. having a specific method (setter) to set data that cannot be
> passed through the common API ("optimize" method) and should not be
> specified at construction (because it is of the same "nature" as the
> parameters passed through "optimize").
> 
> I was thinking of improving the situation by modifying the
> "optimize" method (in interface "BaseMultivariateOptimizer") to
> become: PointValuePair optimize(int maxEval, FUNC f, GoalType
> goalType, double[] startPoint, OptimizationData... optData);

> There is a new array argument, "optData", the elements of which are 
> instances of classes implementing a new marker interface: interface 
> OptimizationData {}

> Concrete optimizer implementations would define which kind of data
> they need (and in which order they must be supplied in the call to 
> "optimize"). ["BaseAbstractMultivariateOptimizer" would store those
> data and provide (protected) access to it (similar to
> "getStartPoint()").]

> For "SimplexOptimizer", the "data" is the "AbstractSimplex" class
> which will just have to implement the "OptimizationData" interface:
> 
> -----
> public class AbstractSimplex implements OptimizationData {
> //No changes here.
> }
> -----
>
> And, in "SimplexOptimizer", the "doOptimize" method will
> retrieve the data, check that it has the appropriate type and then
> use it as before:
> 
> -----
> private PointValuePair doOptimize() {
> // ...
> 
>   final OptimizationData[] optData = getOptimizationData();
>   if (optData == null || optData.length == 0) {
>       throw new NoDataException();
>       // Or: use default values (?).
>   }
>   if (!(optData[0] instanceof AbstractSimplex)) {
>    throw new
IllegalOptimizationDataTypeException(optData[0].getClass().getName());
>   }
>   final AbstractSimplex simplex = (AbstractSimplex) optData[0];
> 
> // etc.
> }
> -----
> We could then get rid of the "setSimplex" method that is not
> part of the optimizers common API, and the necessary input data would
> be passed with the call to "optimize", e.g. (in user code):
> 
> -----
> final SimplexOptimizer optim = new SimplexOptimizer(absTol, relTol);
> final MultivariateFunction func = ...
> final double[] init =  new double[] { 1, 2, 3, 4 };
> final PointValuePair sol = optim.optimize(2500, func,
>                 GoalType.MINIMIZE, init,
>                 new NelderMeadSimplex(init.length, 0.1));
> -----
> [Of course, one drawback is that an illegal type argument is
> detected only at runtime (but it's also an obvious programming bug
> that would probably only occur during development, and not in
> production use).]

I was ready to say just that when I first read this proposal.

> 
> One benefit is that bounds could also be considered as a kind of 
> "OptimizationData":
> 
> -----
> public class SimpleBounds implements OptimizationData {
>   private final double[] lo; private final double[] hi;
> 
>   public SimpleBounds(double[] lowerBounds, double[] upperBounds) {
>     lo = lowerBounds.clone();
>     hi = upperBounds.clone();
>   }
> 
>   public double[] getLo {
>       return lo.clone();
>   }
>   public double[] getHi {
>      return hi.clone();
>   }
> }
> -----
> We could thus get rid of the  "BaseMultivariateSimpleBoundsOptimizer"
> interface.
> 
> What do you think?

I'm not sure what to think. I don't much like these too dynamic settings
and moving checks to runtime. However, I do agree our current
implementation with dedicated method that must be called before we call
the common interface methods is not good either. So I think I just need
to get used to it and could get convinced almost easily.

What I clearly don't like in our setting is the complexity of the
hierarchy with the generics. I have the same reluctance with the solvers
hierarchy, and was directly hit by both when I needed to had a new
function type for differentials (see
<http://mail-archives.apache.org/mod_mbox/commons-dev/201209.mbox/%3C5050B2A3.2050007%40free.fr%3E>
and
<http://mail-archives.apache.org/mod_mbox/commons-dev/201208.mbox/%3C50374A8F.6040806%40spaceroots.org%3E>).
So I would be very happy if we could simplify our hierarchy here and
mainly remove the top level generics (like BaseOptimizer<PAIR> and
BaseMultivariateOptimizer<FUNC extends MultivariateFunction> extends
BaseOptimizer<PointValuePair> and simply have a set of parallel
non-generics interfaces with fixed signatures, one for each type we
need. These top level interfaces don't add much value and completely
prevent to implement several of them in one class, due to type erasuer
(something we did not notice when we designed this). Their javadoc even
states "This interface is mainly intended to enforce the internal
coherence of Commons-Math. Users of the API are advised to base their
code on the following interfaces:".

A coworker of mine asked me today which interface he should use in the
signature of a method he was writing and which should take an optimizer
as an argument. He was puzzled by our hierarchy and did not understand
which level he should use in his declaration. Even knowing the
internals, the history, the various implementations and their
differences, it took me almost an hour to answer his question. So our
hierarchy really needs to be streamlined.

best regards,
Luc

> 
> Gilles

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Re: [Math] About the API of the optimizers

Posted by Gilles Sadowski <gi...@harfang.homelinux.org>.
Hi.

> [...]

I've created MATH-874.

Let me know whether there is any objection to commit the proposed patch.

I wonder whether there should be (working) defaults for "maxEval" and
"goalType", or whether it is safer to let an exception be raised when the
user has not set it at least once.
I'd tend to think that a default is fine:
 * MAX_VALUE for the number of evaluations
 * MINIMIZE for the type of optimization
and the last value set by the user for any subsequent calls to "optimize"
where those parameters are not specified (cf. code attached in JIRA).


Regards,
Gilles

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Re: [Math] About the API of the optimizers

Posted by Sébastien Brisard <se...@m4x.org>.
Dear Gilles and Luc,
Just a quick note to say I'm sorry not to take part in this
interesting thread, but I'm not familiar enough with neither this
package, nor generics.
Having met with the same kind of problems recently with generics in
personal applications, I'm eager to read what your decision will be,
so that I can draw inspiration!
Best regards,
Sébastien


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Re: [Math] About the API of the optimizers

Posted by Luc Maisonobe <Lu...@free.fr>.
Le 05/10/2012 16:56, Gilles Sadowski a écrit :
> Hi.
> 
>>> [...]
>>>>
>>>> What I clearly don't like in our setting is the complexity of the
>>>> hierarchy with the generics. I have the same reluctance with the solvers
>>>> hierarchy, and was directly hit by both when I needed to had a new
>>>> function type for differentials (see
>>>> <http://mail-archives.apache.org/mod_mbox/commons-dev/201209.mbox/%3C5050B2A3.2050007%40free.fr%3E>
>>>> and
>>>> <http://mail-archives.apache.org/mod_mbox/commons-dev/201208.mbox/%3C50374A8F.6040806%40spaceroots.org%3E>).
>>>> So I would be very happy if we could simplify our hierarchy here and
>>>> mainly remove the top level generics (like BaseOptimizer<PAIR> and
>>>> BaseMultivariateOptimizer<FUNC extends MultivariateFunction> extends
>>>> BaseOptimizer<PointValuePair> and simply have a set of parallel
>>>> non-generics interfaces with fixed signatures, one for each type we
>>>> need.
> 
> To be clear, you are referring to the "user" interfaces which I enumerated
> below?

Yes. The user interfaces should be kept.

> 
>>>> These top level interfaces don't add much value and completely
>>>> prevent to implement several of them in one class, due to type erasuer
>>>> (something we did not notice when we designed this). Their javadoc even
>>>> states "This interface is mainly intended to enforce the internal
>>>> coherence of Commons-Math. Users of the API are advised to base their
>>>> code on the following interfaces:".
>>>
>>> I am responsible for the current hierarchy design but it was based on an
>>> earlier one, not much simpler, but with much more duplicated code.
>>> At refactoring the identified goal was to merge all the codes that could be.
>>>
>>> The point is that different algorithm have generated different based on
>>> several points:
>>>  * Univariate vs multivariate function
>>>  * Scalar vs sector function
>>>  * "optimize" return type: "PointValuePair" vs "PoinVectorValuePair"
>>>
>>> The generics were used to "summarize" all the existing flavours (and push
>>> common features one level up). [Boilerplate code in "Abstract..." classes.]
>>>
>>>> A coworker of mine asked me today which interface he should use in the
>>>> signature of a method he was writing and which should take an optimizer
>>>> as an argument. He was puzzled by our hierarchy and did not understand
>>>> which level he should use in his declaration. Even knowing the
>>>> internals, the history, the various implementations and their
>>>> differences, it took me almost an hour to answer his question. So our
>>>> hierarchy really needs to be streamlined.
>>>
>>> The user interfaces didn't change I think, and do not refer to generics.
>>
>> Yes, this is exactly my point. These interfaces are not for users, they
>> are for [math] developers.
> 
> The interfaces with a generic parameter ("T" or "FUNC") are not for users;
> those without generic parameters (but which extends a generic with a
> specific type in place of "T" ot "FUNC") are for users (those enumerated
> below). I that what you mean?

Yes, it is what I mean.

> 
>> However, they do confuse users who see them
>> and even reading the javadoc don't understand their purpose. They also
>> prevent an implementation to support two interfaces at a time and hence
>> to be smoothly upgraded as we improve our basic users interfaces.
> 
> I have mixed feelings. Indeed it is a pity that generics do not really
> create new types; it is type erasure that got in your way, not the generics.

Yes, but unfortunately the Java language was designed this way, so we
have to cope with it. Also I don't blame anybody (neither the language
designers for choosing type erasure, nor you for setting up the generics
interface, nor any other developers for not seeing this problem at that
time.

> 
> But I agree that in the end, it's not necessary to keep interfaces just for
> internal use: We should be able to avoid redundancy and keep code
> duplication just by respecting a policy. Of course, the refactoring was
> done _because_ the last statement was not true. ;-)
> 
>>
>>> They are
>>>  * DifferentiableMultivariateVectorOptimizer
>>>  * DifferentiableMultivariateOptimizer
>>>  * DifferentiableMultivariateMultiStartOptimizer
>>>  * DifferentiableMultivariateVectorMultiStartOptimizer
>>>  * MultivariateMultiStartOptimizer
>>>  * MultivariateOptimizer
>>>  * UnivariateOptimizer 
>>>
>>> [Anything whose names start with "Base..." or "Abstract..." is neither for
>>> users nor for application developers but for developers of concrete algorithms
>>> for CM.]
>>>
>>>
>>> What do you propose? Wat is streamlining a library?
>>
>> I propose to remove the generics from pure interfaces (this would have
>> to wait for 4.0, of course), and hence reduce the number of layers at
>> least by one, and if possible by more than one.
> 
> All simplifications are welcome :-).
> I think that my proposal (cf. original subject of this thread) is also
> about simplication of the API (for easier usage):
> 
> 1. Construct an optimizer.
> 2. Call the "optimize" method.
> [No intermediate calls to specific methods that are not in the general API.]

Yes, and I finally agreed with this (see my comment on MATH-874). Let's
try it.

Luc

> 
> 
> Gilles
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> For additional commands, e-mail: dev-help@commons.apache.org
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Re: [Math] About the API of the optimizers

Posted by Gilles Sadowski <gi...@harfang.homelinux.org>.
Hi.

> > [...]
> >>
> >> What I clearly don't like in our setting is the complexity of the
> >> hierarchy with the generics. I have the same reluctance with the solvers
> >> hierarchy, and was directly hit by both when I needed to had a new
> >> function type for differentials (see
> >> <http://mail-archives.apache.org/mod_mbox/commons-dev/201209.mbox/%3C5050B2A3.2050007%40free.fr%3E>
> >> and
> >> <http://mail-archives.apache.org/mod_mbox/commons-dev/201208.mbox/%3C50374A8F.6040806%40spaceroots.org%3E>).
> >> So I would be very happy if we could simplify our hierarchy here and
> >> mainly remove the top level generics (like BaseOptimizer<PAIR> and
> >> BaseMultivariateOptimizer<FUNC extends MultivariateFunction> extends
> >> BaseOptimizer<PointValuePair> and simply have a set of parallel
> >> non-generics interfaces with fixed signatures, one for each type we
> >> need.

To be clear, you are referring to the "user" interfaces which I enumerated
below?

> >> These top level interfaces don't add much value and completely
> >> prevent to implement several of them in one class, due to type erasuer
> >> (something we did not notice when we designed this). Their javadoc even
> >> states "This interface is mainly intended to enforce the internal
> >> coherence of Commons-Math. Users of the API are advised to base their
> >> code on the following interfaces:".
> > 
> > I am responsible for the current hierarchy design but it was based on an
> > earlier one, not much simpler, but with much more duplicated code.
> > At refactoring the identified goal was to merge all the codes that could be.
> > 
> > The point is that different algorithm have generated different based on
> > several points:
> >  * Univariate vs multivariate function
> >  * Scalar vs sector function
> >  * "optimize" return type: "PointValuePair" vs "PoinVectorValuePair"
> > 
> > The generics were used to "summarize" all the existing flavours (and push
> > common features one level up). [Boilerplate code in "Abstract..." classes.]
> > 
> >> A coworker of mine asked me today which interface he should use in the
> >> signature of a method he was writing and which should take an optimizer
> >> as an argument. He was puzzled by our hierarchy and did not understand
> >> which level he should use in his declaration. Even knowing the
> >> internals, the history, the various implementations and their
> >> differences, it took me almost an hour to answer his question. So our
> >> hierarchy really needs to be streamlined.
> > 
> > The user interfaces didn't change I think, and do not refer to generics.
> 
> Yes, this is exactly my point. These interfaces are not for users, they
> are for [math] developers.

The interfaces with a generic parameter ("T" or "FUNC") are not for users;
those without generic parameters (but which extends a generic with a
specific type in place of "T" ot "FUNC") are for users (those enumerated
below). I that what you mean?

> However, they do confuse users who see them
> and even reading the javadoc don't understand their purpose. They also
> prevent an implementation to support two interfaces at a time and hence
> to be smoothly upgraded as we improve our basic users interfaces.

I have mixed feelings. Indeed it is a pity that generics do not really
create new types; it is type erasure that got in your way, not the generics.

But I agree that in the end, it's not necessary to keep interfaces just for
internal use: We should be able to avoid redundancy and keep code
duplication just by respecting a policy. Of course, the refactoring was
done _because_ the last statement was not true. ;-)

> 
> > They are
> >  * DifferentiableMultivariateVectorOptimizer
> >  * DifferentiableMultivariateOptimizer
> >  * DifferentiableMultivariateMultiStartOptimizer
> >  * DifferentiableMultivariateVectorMultiStartOptimizer
> >  * MultivariateMultiStartOptimizer
> >  * MultivariateOptimizer
> >  * UnivariateOptimizer 
> > 
> > [Anything whose names start with "Base..." or "Abstract..." is neither for
> > users nor for application developers but for developers of concrete algorithms
> > for CM.]
> > 
> > 
> > What do you propose? Wat is streamlining a library?
> 
> I propose to remove the generics from pure interfaces (this would have
> to wait for 4.0, of course), and hence reduce the number of layers at
> least by one, and if possible by more than one.

All simplifications are welcome :-).
I think that my proposal (cf. original subject of this thread) is also
about simplication of the API (for easier usage):

1. Construct an optimizer.
2. Call the "optimize" method.
[No intermediate calls to specific methods that are not in the general API.]


Gilles

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Re: [Math] About the API of the optimizers

Posted by Luc Maisonobe <Lu...@free.fr>.
Hi Gilles,

Le 05/10/2012 01:15, Gilles Sadowski a écrit :
> On Thu, Oct 04, 2012 at 09:43:47PM +0200, Luc Maisonobe wrote:
>> [Sorry for the strange format of this mail, but I managed to lose the
>> original message from Gilles, so had to recreate it by copy/paste and
>> adding the quotation marks by hand...]
>>
>> Gilles wrote:
>>> Hello.
>>>
>>> This issue https://issues.apache.org/jira/browse/MATH-872 is about a 
>>> workaround similar to one already existing for "SimplexOptimizer",
>>> i.e. having a specific method (setter) to set data that cannot be
>>> passed through the common API ("optimize" method) and should not be
>>> specified at construction (because it is of the same "nature" as the
>>> parameters passed through "optimize").
>>>
>>> I was thinking of improving the situation by modifying the
>>> "optimize" method (in interface "BaseMultivariateOptimizer") to
>>> become: PointValuePair optimize(int maxEval, FUNC f, GoalType
>>> goalType, double[] startPoint, OptimizationData... optData);
>>
>>> There is a new array argument, "optData", the elements of which are 
>>> instances of classes implementing a new marker interface: interface 
>>> OptimizationData {}
>>
>>> Concrete optimizer implementations would define which kind of data
>>> they need (and in which order they must be supplied in the call to 
>>> "optimize"). ["BaseAbstractMultivariateOptimizer" would store those
>>> data and provide (protected) access to it (similar to
>>> "getStartPoint()").]
>>
>>> For "SimplexOptimizer", the "data" is the "AbstractSimplex" class
>>> which will just have to implement the "OptimizationData" interface:
>>>
>>> -----
>>> public class AbstractSimplex implements OptimizationData {
>>> //No changes here.
>>> }
>>> -----
>>>
>>> And, in "SimplexOptimizer", the "doOptimize" method will
>>> retrieve the data, check that it has the appropriate type and then
>>> use it as before:
>>>
>>> -----
>>> private PointValuePair doOptimize() {
>>> // ...
>>>
>>>   final OptimizationData[] optData = getOptimizationData();
>>>   if (optData == null || optData.length == 0) {
>>>       throw new NoDataException();
>>>       // Or: use default values (?).
>>>   }
>>>   if (!(optData[0] instanceof AbstractSimplex)) {
>>>    throw new
>> IllegalOptimizationDataTypeException(optData[0].getClass().getName());
>>>   }
>>>   final AbstractSimplex simplex = (AbstractSimplex) optData[0];
>>>
>>> // etc.
>>> }
>>> -----
>>> We could then get rid of the "setSimplex" method that is not
>>> part of the optimizers common API, and the necessary input data would
>>> be passed with the call to "optimize", e.g. (in user code):
>>>
>>> -----
>>> final SimplexOptimizer optim = new SimplexOptimizer(absTol, relTol);
>>> final MultivariateFunction func = ...
>>> final double[] init =  new double[] { 1, 2, 3, 4 };
>>> final PointValuePair sol = optim.optimize(2500, func,
>>>                 GoalType.MINIMIZE, init,
>>>                 new NelderMeadSimplex(init.length, 0.1));
>>> -----
>>> [Of course, one drawback is that an illegal type argument is
>>> detected only at runtime (but it's also an obvious programming bug
>>> that would probably only occur during development, and not in
>>> production use).]
>>
>> I was ready to say just that when I first read this proposal.
>>
>>>
>>> One benefit is that bounds could also be considered as a kind of 
>>> "OptimizationData":
>>>
>>> -----
>>> public class SimpleBounds implements OptimizationData {
>>>   private final double[] lo; private final double[] hi;
>>>
>>>   public SimpleBounds(double[] lowerBounds, double[] upperBounds) {
>>>     lo = lowerBounds.clone();
>>>     hi = upperBounds.clone();
>>>   }
>>>
>>>   public double[] getLo {
>>>       return lo.clone();
>>>   }
>>>   public double[] getHi {
>>>      return hi.clone();
>>>   }
>>> }
>>> -----
>>> We could thus get rid of the  "BaseMultivariateSimpleBoundsOptimizer"
>>> interface.
>>>
>>> What do you think?
>>
>> I'm not sure what to think. I don't much like these too dynamic settings
>> and moving checks to runtime. However, I do agree our current
>> implementation with dedicated method that must be called before we call
>> the common interface methods is not good either. So I think I just need
>> to get used to it and could get convinced almost easily.
>>
>> What I clearly don't like in our setting is the complexity of the
>> hierarchy with the generics. I have the same reluctance with the solvers
>> hierarchy, and was directly hit by both when I needed to had a new
>> function type for differentials (see
>> <http://mail-archives.apache.org/mod_mbox/commons-dev/201209.mbox/%3C5050B2A3.2050007%40free.fr%3E>
>> and
>> <http://mail-archives.apache.org/mod_mbox/commons-dev/201208.mbox/%3C50374A8F.6040806%40spaceroots.org%3E>).
>> So I would be very happy if we could simplify our hierarchy here and
>> mainly remove the top level generics (like BaseOptimizer<PAIR> and
>> BaseMultivariateOptimizer<FUNC extends MultivariateFunction> extends
>> BaseOptimizer<PointValuePair> and simply have a set of parallel
>> non-generics interfaces with fixed signatures, one for each type we
>> need. These top level interfaces don't add much value and completely
>> prevent to implement several of them in one class, due to type erasuer
>> (something we did not notice when we designed this). Their javadoc even
>> states "This interface is mainly intended to enforce the internal
>> coherence of Commons-Math. Users of the API are advised to base their
>> code on the following interfaces:".
> 
> I am responsible for the current hierarchy design but it was based on an
> earlier one, not much simpler, but with much more duplicated code.
> At refactoring the identified goal was to merge all the codes that could be.
> 
> The point is that different algorithm have generated different based on
> several points:
>  * Univariate vs multivariate function
>  * Scalar vs sector function
>  * "optimize" return type: "PointValuePair" vs "PoinVectorValuePair"
> 
> The generics were used to "summarize" all the existing flavours (and push
> common features one level up). [Boilerplate code in "Abstract..." classes.]
> 
>> A coworker of mine asked me today which interface he should use in the
>> signature of a method he was writing and which should take an optimizer
>> as an argument. He was puzzled by our hierarchy and did not understand
>> which level he should use in his declaration. Even knowing the
>> internals, the history, the various implementations and their
>> differences, it took me almost an hour to answer his question. So our
>> hierarchy really needs to be streamlined.
> 
> The user interfaces didn't change I think, and do not refer to generics.

Yes, this is exactly my point. These interfaces are not for users, they
are for [math] developers. However, they do confuse users who see them
and even reading the javadoc don't understand their purpose. They also
prevent an implementation to support two interfaces at a time and hence
to be smoothly upgraded as we improve our basic users interfaces.

> They are
>  * DifferentiableMultivariateVectorOptimizer
>  * DifferentiableMultivariateOptimizer
>  * DifferentiableMultivariateMultiStartOptimizer
>  * DifferentiableMultivariateVectorMultiStartOptimizer
>  * MultivariateMultiStartOptimizer
>  * MultivariateOptimizer
>  * UnivariateOptimizer 
> 
> [Anything whose names start with "Base..." or "Abstract..." is neither for
> users nor for application developers but for developers of concrete algorithms
> for CM.]
> 
> 
> What do you propose? Wat is streamlining a library?

I propose to remove the generics from pure interfaces (this would have
to wait for 4.0, of course), and hence reduce the number of layers at
least by one, and if possible by more than one.

Luc

> 
> Gilles
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> For additional commands, e-mail: dev-help@commons.apache.org
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Re: [Math] About the API of the optimizers

Posted by Gilles Sadowski <gi...@harfang.homelinux.org>.
On Thu, Oct 04, 2012 at 09:43:47PM +0200, Luc Maisonobe wrote:
> [Sorry for the strange format of this mail, but I managed to lose the
> original message from Gilles, so had to recreate it by copy/paste and
> adding the quotation marks by hand...]
> 
> Gilles wrote:
> > Hello.
> > 
> > This issue https://issues.apache.org/jira/browse/MATH-872 is about a 
> > workaround similar to one already existing for "SimplexOptimizer",
> > i.e. having a specific method (setter) to set data that cannot be
> > passed through the common API ("optimize" method) and should not be
> > specified at construction (because it is of the same "nature" as the
> > parameters passed through "optimize").
> > 
> > I was thinking of improving the situation by modifying the
> > "optimize" method (in interface "BaseMultivariateOptimizer") to
> > become: PointValuePair optimize(int maxEval, FUNC f, GoalType
> > goalType, double[] startPoint, OptimizationData... optData);
> 
> > There is a new array argument, "optData", the elements of which are 
> > instances of classes implementing a new marker interface: interface 
> > OptimizationData {}
> 
> > Concrete optimizer implementations would define which kind of data
> > they need (and in which order they must be supplied in the call to 
> > "optimize"). ["BaseAbstractMultivariateOptimizer" would store those
> > data and provide (protected) access to it (similar to
> > "getStartPoint()").]
> 
> > For "SimplexOptimizer", the "data" is the "AbstractSimplex" class
> > which will just have to implement the "OptimizationData" interface:
> > 
> > -----
> > public class AbstractSimplex implements OptimizationData {
> > //No changes here.
> > }
> > -----
> >
> > And, in "SimplexOptimizer", the "doOptimize" method will
> > retrieve the data, check that it has the appropriate type and then
> > use it as before:
> > 
> > -----
> > private PointValuePair doOptimize() {
> > // ...
> > 
> >   final OptimizationData[] optData = getOptimizationData();
> >   if (optData == null || optData.length == 0) {
> >       throw new NoDataException();
> >       // Or: use default values (?).
> >   }
> >   if (!(optData[0] instanceof AbstractSimplex)) {
> >    throw new
> IllegalOptimizationDataTypeException(optData[0].getClass().getName());
> >   }
> >   final AbstractSimplex simplex = (AbstractSimplex) optData[0];
> > 
> > // etc.
> > }
> > -----
> > We could then get rid of the "setSimplex" method that is not
> > part of the optimizers common API, and the necessary input data would
> > be passed with the call to "optimize", e.g. (in user code):
> > 
> > -----
> > final SimplexOptimizer optim = new SimplexOptimizer(absTol, relTol);
> > final MultivariateFunction func = ...
> > final double[] init =  new double[] { 1, 2, 3, 4 };
> > final PointValuePair sol = optim.optimize(2500, func,
> >                 GoalType.MINIMIZE, init,
> >                 new NelderMeadSimplex(init.length, 0.1));
> > -----
> > [Of course, one drawback is that an illegal type argument is
> > detected only at runtime (but it's also an obvious programming bug
> > that would probably only occur during development, and not in
> > production use).]
> 
> I was ready to say just that when I first read this proposal.
> 
> > 
> > One benefit is that bounds could also be considered as a kind of 
> > "OptimizationData":
> > 
> > -----
> > public class SimpleBounds implements OptimizationData {
> >   private final double[] lo; private final double[] hi;
> > 
> >   public SimpleBounds(double[] lowerBounds, double[] upperBounds) {
> >     lo = lowerBounds.clone();
> >     hi = upperBounds.clone();
> >   }
> > 
> >   public double[] getLo {
> >       return lo.clone();
> >   }
> >   public double[] getHi {
> >      return hi.clone();
> >   }
> > }
> > -----
> > We could thus get rid of the  "BaseMultivariateSimpleBoundsOptimizer"
> > interface.
> > 
> > What do you think?
> 
> I'm not sure what to think. I don't much like these too dynamic settings
> and moving checks to runtime. However, I do agree our current
> implementation with dedicated method that must be called before we call
> the common interface methods is not good either. So I think I just need
> to get used to it and could get convinced almost easily.
> 
> What I clearly don't like in our setting is the complexity of the
> hierarchy with the generics. I have the same reluctance with the solvers
> hierarchy, and was directly hit by both when I needed to had a new
> function type for differentials (see
> <http://mail-archives.apache.org/mod_mbox/commons-dev/201209.mbox/%3C5050B2A3.2050007%40free.fr%3E>
> and
> <http://mail-archives.apache.org/mod_mbox/commons-dev/201208.mbox/%3C50374A8F.6040806%40spaceroots.org%3E>).
> So I would be very happy if we could simplify our hierarchy here and
> mainly remove the top level generics (like BaseOptimizer<PAIR> and
> BaseMultivariateOptimizer<FUNC extends MultivariateFunction> extends
> BaseOptimizer<PointValuePair> and simply have a set of parallel
> non-generics interfaces with fixed signatures, one for each type we
> need. These top level interfaces don't add much value and completely
> prevent to implement several of them in one class, due to type erasuer
> (something we did not notice when we designed this). Their javadoc even
> states "This interface is mainly intended to enforce the internal
> coherence of Commons-Math. Users of the API are advised to base their
> code on the following interfaces:".

I am responsible for the current hierarchy design but it was based on an
earlier one, not much simpler, but with much more duplicated code.
At refactoring the identified goal was to merge all the codes that could be.

The point is that different algorithm have generated different based on
several points:
 * Univariate vs multivariate function
 * Scalar vs sector function
 * "optimize" return type: "PointValuePair" vs "PoinVectorValuePair"

The generics were used to "summarize" all the existing flavours (and push
common features one level up). [Boilerplate code in "Abstract..." classes.]

> A coworker of mine asked me today which interface he should use in the
> signature of a method he was writing and which should take an optimizer
> as an argument. He was puzzled by our hierarchy and did not understand
> which level he should use in his declaration. Even knowing the
> internals, the history, the various implementations and their
> differences, it took me almost an hour to answer his question. So our
> hierarchy really needs to be streamlined.

The user interfaces didn't change I think, and do not refer to generics.
They are
 * DifferentiableMultivariateVectorOptimizer
 * DifferentiableMultivariateOptimizer
 * DifferentiableMultivariateMultiStartOptimizer
 * DifferentiableMultivariateVectorMultiStartOptimizer
 * MultivariateMultiStartOptimizer
 * MultivariateOptimizer
 * UnivariateOptimizer 

[Anything whose names start with "Base..." or "Abstract..." is neither for
users nor for application developers but for developers of concrete algorithms
for CM.]


What do you propose? Wat is streamlining a library?

Gilles

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org