commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Brent Worden" <brent.wor...@perficient.com>
Subject Re: [math][functor] More Design Concerns
Date Tue, 01 Jul 2003 19:02:26 GMT
>
> 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: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message