[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-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org