astropy/astropy — pull request #2580 by embray (2014-05-29 23:11:57+00:00)
Title: Model refactoring stage 1: "evaluate" normalization

This PR is to demonstrate one aspect of where I'm going with modeling refactoring. This PR is not entirely complete--there are some missing features, and a few models don't work with it (in particular composite models, though they are being refactored as well). This PR does not yet demonstrate the full advantage of the changes it presents. I just wanted to get it out there so interested parties could get an idea of where things are going.

The primary change demonstrated by this PR is as follows: Most model subclasses will no longer implement a `__call__` method manually. `Model.__call__` is implemented in the base class, and is not generally overridden by subclasses. There's nothing *stopping* a subclass from overriding it, but I'm trying to move things a direction where it generally won't be necessary.

Instead, when implementing a new model, developers/users must supply a method called `evaluate`. This is almost completely analogous to the existing implementation of `FittableModel` (formerly `ParametricModel`) subclasses that required implementing an `eval` method. (The name change is mostly justified by the fact that "eval" is a Python builtin, so using it confuses some syntax highlighters; also it doesn't need to be typed often so a little verbosity doesn't hurt).

The `evaluate` method may be either a normal instance method, a `classmethod`, or a `staticmethod`. Regardless, it takes a fixed set of arguments, consisting of all of the function's independent variables, followed by the functional parameters needed to evaluate the function. The parameters are always provided in a fixed order based on the order they were defined on the model class. The arguments are always assumed to by Numpy arrays that are already in the correct shape to be evaluated.

One advantage of this is that it makes it easy to swap out implementations of `evaluate` for any given model. As long as the implementation is wrapped to take arguments in the correct order it could be a Numpy implementation (like we currently use), or a function using numexpr, or written in C or Cython, or what have you. A related advantage, not yet demonstrated by this PR, is that it will make some aspects of implementing fitters simpler and, I think, more efficient. I am working on another set of changes on top of both this and #2441 that I hope will demonstrate the full advantages.

I haven't fully updated the docs yet to match the changes in this PR. If it would help, I could go ahead and do that and push the updated docs up for perusal.