# Interfaces for Fitted Models

**URL:** <https://www.rubin.community/t/interfaces-for-fitted-models/505>\
**Category:** Data Management\
**Created:** [January 27, 2016, 5:32pm UTC](https://www.rubin.community/t/interfaces-for-fitted-models/505 "2016-01-27T17:32:10Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![jbosch](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/jbosch/32/12_2.png) [@jbosch](https://www.rubin.community/u/jbosch)\
**Post date:** [January 27, 2016, 5:32pm UTC](https://www.rubin.community/t/interfaces-for-fitted-models/505/1 "2016-01-27T17:32:10Z")

</div>

One of the challenges discussed in the [Simultaneous Astrometry RFD](http://www.rubin.community/t/simultaneous-astrometry-rfd-notes/503) is the unification of `afw.geom.XYTransform` with the `Gtransfo` object introduced in `meas_simastrom`. Both of these are polymorphic base classes that represent arbitrary coordinate transforms, but they represent two different views: `XYTransform` is the interface for _consumers_ of the already-fit model, while `Gtransfo` is the interface for _fitters_. I think meeting the needs of those two different users is a generic problem in scientific software architecture, and we’ll need to deal with it in several more cases in the not-too-distant future:

- To get simultaneous photometric calibration working in `meas_simastrom`, we’ll need a fitter object (analog of `Gtransfo`) that works well with our existing consumer object (`BoundedField`).
- `Psf` and `Kernel` both currently suffer from trying to meet the needs of both consumers and fitters, and don’t do either as elegantly as they could. And we’ll have to make major changes to both of them anyway to support chromatic dependence.
- The galaxy model classes in `shapelet` and `meas_modelfit` could also benefit greatly from some refactoring.
- The background subtraction objects are also due for an interface overhaul.

Here’s what I think makes a _consumer_ interface different from a _fitter_ interface:

- A fitter interface has parameters that can be varied to change the model. It may hold these parameters as instance state, or it simply operate on external arrays that hold them, but it needs to be able to update the model given those parameters, provide mechanisms to guess initial parameters, and probably compute derivatives of the model with respect to those parameters. A consumer interface, in contrast, doesn’t care about parameters at all, and probably needs to support model implementation that were never actually fit, or were fit externally in a way that doesn’t even allow us to know what the free parameters were. It’s also important to note that a different parametrization of the same model (or a different choice as to what parameters are free and which are held fixed) may be best implemented as different derived classes for fitters, but only a single derived class for consumers, so we shouldn’t assume that there is a one-to-one relationship between fitter and consumer classes.

- Fitter classes must be mutable if they include their parameter vector as instance state, and even if they don’t, there’s no generic advantage to making them immutable. It is very helpful to make consumer classes immutable, however, because this allows these complex objects to be shared (via `shared_ptr` or Python reference counting) by multiple parts of the codebase without needing to worry about the multiple holders of the same object invalidating each other by unintentionally modifying each other’s state. Without immutability, we frequently have to do a deep-copy of a complex object to guard against this possibility, even if the actual probability of the object being modified is low. As an example, note how much implicit deep-copying of `Wcs` and `Calib` objects (both mutable) happens in `Exposure` (actually `ExposureInfo`) compared to `Psf` (which is immutable).

- A fitter class should be optimized for evaluating its model for a set of arguments that is largely fixed, as they’re the arguments of the data that is being fit. This means it’s often a good idea for a fitter object to include whatever state it can to make repeated evaluation on those particular data points more efficient, even if that makes the object larger in memory or requires a bit more work up front. In contrast, consumer objects generally aren’t evaluated repeatedly at the same point (since their parameters are fixed, it’d be more efficient just to save the result, after all), and instead should probably prefer a more lightweight memory footprint.

- It’s rarely necessary for a fitter object to be persistable; usually we just need to persist consumer objects. This doesn’t just refer to general persistence to files - it may be necessary to represent some consumer objects (e.g. galaxy models) in a single record in an output catalog.

- Consumer interfaces may need to support summary statistic calculations (e.g. FWHM for a `Psf`, or flux for a galaxy model) that aren’t needed while fitting.

There are, of course, many _more_ things that fitter and consumer objects for the same model will have in common, so the challenge is to meet the differing needs of the users without a lot of code duplication. And if we have an interface that does have distinct fitter and consumer classes, we clearly need to be able to efficiently convert one into the other (or at least create consumer objects from fitter objects).

I can imagine a lot of design patterns that could potentially do this (multiple classes with some sort of composition relationship, a single class with multiple inheritance, two class hierarchies that share a pimpl), but I haven’t really thought through any in detail. I’ll try to find some time to do that later, but I wanted to post this here now to explain why I think unifying `XYTransform` and `Gtransfo` doesn’t _necessarily_ mean merging them into one class, and to try to spur some more thought on the generic design patterns for this more general problem.

---

<div class="post-metadata">

**Author:** ![KSK](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/ksk/32/393_2.png) [@KSK](https://www.rubin.community/u/KSK)\
**Post date:** [January 27, 2016, 10:20pm UTC](https://www.rubin.community/t/interfaces-for-fitted-models/505/2 "2016-01-27T22:20:30Z")

</div>

I’d like to mention that astropy has been thinking about this: [see here](http://docs.astropy.org/en/stable/modeling/fitting.html)

They take the approach that there are models and fitters. Not all models are fittable, and not all models can be fit by all fitters. Both models and fitters should be easy to subclass.
