> > My point in (b.) is to discuss what amount to "Facades" approached in > classes/interfaces like (Store)Univariate and RealMatrix, and the idea > that there are decisions being made concerning how the "Facades are > "backed" by various implementation strategies, not to suggest that the > "Facades" themselves should go away. Right now we have some design > evolution thats going on in the math.stat package, over the last few > weeks we've experimented with Abstract Implementations, Inherited > Delegation and Static Delegation strategies, currently finding > satisfaction and dissatisfaction in various aspects of each approach. > Some cases the inheritance hierarchy got complicated (UnivariateImpl > extending AbstractStoreUnivariate), some cases the extensibility of the > implementations becomes a concern (StatUtils being static). This > discussion attempts to "draw the problem space" we are encountering here > and clarify it, Functional approaches are but one means of possibly > dealing with this problem space. >
In my utopia I would like to see these classes move away from primitives and embrace objects. The reason for this is they can not fully leverage other commons projects such as Collections and Functor because they are built to work with objects. This limits our ability to use more of the advance features found in those packages. If we moved to objects, I think the class hierarchy for univariates would be simplified tremendously. I foresee two implementations, one stored the other non-stored. For computing the statistics, I would like to see a functor type object used to compute each metric. These metric objects would be specific to the type of values it dealt with. The univariate could be decorated with these metric objects to add computational functionality. This allows the problem/user to dictate the statistics to be calculated so there is no more computing values that are never accessed. On the maintenance front, it removes the need for an ever increasing univariate interface but still allows for ever increasing functionality. An example of when this would be used is the t-test. A t-test could be use a unvariate that is decorated with three metric objects: one each for sample size, mean, and variance. The caller would add the values to the univariate and then access the statistics from the metric object instead of the univariate. We could take it a step further by allowing the functors to compute more than one metric and have them be adaptable into individual metric objects. Going back to the t-test, one functor could be used to compute all three values, possibly making use of some computational efficiencies. When the caller wants each metric, the functor could morph into the needed metric. For ease of use and the novice user, all this complexity could be hidden behind the utility methods. For the more advanced user, a set of predefined java.lang.Number metric objects could be supplied that they attach to univariates. For the power user, new metric object can be developed and attached to univariates. The last approach would be necessary when a custom data type is used that the library doesn't support. Here's a sample of what I mean: //===================== BEGIN UtopiaUnivariate.java ===================== package org.apache.commons.math.stat; import java.math.BigDecimal; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.collections.Closure; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.iterators.ArrayIterator; /** * @author Brent Worden */ public class UtopiaUnivariate { /** */ private Map metrics = new HashMap(); /** * */ public UtopiaUnivariate(){ super(); } /** * Add a value to this univariate. The univariate adds the value to each metric. */ public void addValue(final Object value) { Closure c = new Closure() { public void execute(Object source) { ((Metric)source).addValue(value); } }; CollectionUtils.forAllDo(metrics.values(), c); } /** * Adds a metric to this univariate. Each metric is notified of added values. */ public void addMetric(final Metric metric){ Closure c = new Closure() { public void execute(Object source) { metrics.put(source, metric); } }; CollectionUtils.forAllDo(metric.getMetrics(), c); } /** * Gets the metric value for the given type. */ public Object getMetric(Class type){ Object ret = null; Metric metric = (Metric)metrics.get(type); if(metric != null) { ret = metric.getMetric(type); } return ret; } /** * Novice users are isolated from the metric complexity via the convenience methods. */ public static double tStatistics(double[] x, double mu) { UtopiaUnivariate univariate = new UtopiaUnivariate(); univariate.addMetric(new SampleSizeMeanVarianceMetric()); // add the values Iterator iter = new ArrayIterator(x); while(iter.hasNext()){ univariate.addValue(iter.next()); } // get the metrics Number n = (Number)univariate.getMetric(SampleSizeMetric.class); Number m = (Number)univariate.getMetric(MeanMetric.class); Number v = (Number)univariate.getMetric(VarianceMetric.class); // compute the test statistic return (m.doubleValue() - mu) / Math.sqrt(m.doubleValue() / n.doubleValue()); } } interface Metric { /** * Collection of metric types that this metric calculates */ List getMetrics(); /** * Notifies this metric of an added value. */ void addValue(Object value); /** * Gets the metric value for the given type. */ Object getMetric(Class type); } /** * Simple tag interface. Used to register metric objects with univariates. */ interface MeanMetric { } /** * Simple tag interface. Used to register metric objects with univariates. */ interface SampleSizeMetric { } /** * Simple tag interface. Used to register metric objects with univariates. */ interface VarianceMetric { } /** * Metric that computes the mean, variance, and sample size for added values. */ class SampleSizeMeanVarianceMetric implements Metric { BigDecimal n; BigDecimal mean; BigDecimal variance; private List metrics = Arrays.asList(new Object[]{MeanMetric.class, SampleSizeMetric.class, VarianceMetric.class}); public void addValue(Object value){ BigDecimal x = new BigDecimal(((Number)value).doubleValue()); // update n, mean, and variance using our wonderful recursive algorithms. } public List getMetrics(){ return metrics; } public Object getMetric(Class type) { Object ret = null; if(metrics.contains(type)){ if(MeanMetric.class.equals(type)){ ret = mean; } else if(SampleSizeMetric.class.equals(type)){ ret = n; } else { // ASSERT: VarianceMetric.class.equals(type) ret = variance; } } return ret; } } //===================== END UtopiaUnivariate.java ===================== Brent Worden Senior Technical Consultant Perficient, Inc. - Minneapolis D: (612) 752-1625 --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]