Re: Problem applying generics to my code. Is there a better solution?
On Apr 4, 4:09 pm, "Lucas" <lscha...@gmail.com> wrote:
All,
I am working on a statistical inference library and have run into a
limiting case of using generics for type safety. I hope someone is
able to suggest a more elegant solution to my problem that I currently
have.
I have a small class of static methods for computing closed-form
posterior distributions. The skeleton of the classes look like this
// This class defines a distribution over a type T. Usually Integer
or Double.
public interface Distribution<T> { ... }
// Here are some probability distributions
public class NormalDistribution implements Distribution<Double>
{ ... }
public class GammaDistribution implements Distribution<Double> { ... }
public class PoissonDistribution implements Distribution<Integer>
{ ... }
// and here are a bunch of methods to compute closed form solutions to
the posteriors
public class Posteriors {
public static NormalDistribution
normalNormalPosterior( List<Double> data, NormalDistribution
likelihood, NormalDistribution prior ) { ... }
public static GammaDistribution
poissonGammaPosterior( List<Integer> data, PoissonDistribution
likelihood, GammaDistribution prior ) { ... }
}
Now, I would like to create a generic dispatch method that I can pass
any data, likelihood and prior into and it will dispatch to the
appropriate method if it exists. The prototype looks like this
public static <T, P> Distribution<P> posterior( List<T> data,
Distribution<T> likelihood, Distribution<P> prior)
So, for type safety, I want to require that the data is compatible
with the likelihood distribution and that the posterior distribution
has the same domain as the prior -- the definition of a conjugate
prior. The problem comes in the implementation. Currently, my method
looks like this
public static <T, P> Distribution<P> posterior( List<T> data,
Distribution<T> likelihood, Distribution<P> prior)
{
if ( likelihood instanceof NormalDistribution && prior instanceof
NormalDistribution )
return (Distribution<P>) normalNormalPosterior((List<Double>)
data, (NormalDistribution) likelihood, (NormalDistribution) prior );
if ( likelihood instanceof PoissonDistribution && prior instanceof
GammaDistribution )
return (Distribution<P>) normalNormalPosterior((List<Integer>)
data, (PoissonDistribution) likelihood, (GammaDistribution) prior );
throw new UnsupportedConjugatePairException();
}
This works and, logically, I don't think I can run into any strange
run-time exceptions since, for example
1. "likelihood instanceof NormalDistribution" implies that List<T>
must be a List<Double>
2. "prior instanceof NormalDistribution" ensures that the posterior
will match the prior
The real question: Is there a way to write my posterior() method
without all the ugly casting and compiler warnings?
How about this:
public static <T, P> Distribution<P> posterior(List<Double> data,
NormalDistribution<T> likelihood, NormalDistribution<P> prior)
{
return normalNormalPosterior(data, likelihood, prior );
}
public static <T, P> Distribution<P> posterior(List<Integer> data,
PoissonDistribution<T> likelihood, GammaDistribution<P> prior)
{
return normalNormalPosterior(data, likelihood, prior);
}
Why have one method that does two things?
You might even want to make PoissonDistribution implement a method
posterior which takes a List<Integer> data, GammaDistribution<P>
prior), and likewise on the NormalDistribution.