WIP: Refactor optimization code.

First pass. I tried to write it so that I only had to change the current code in one place. I'd like also to pull out the specialized code for regularization to a general `_fit_constrained` function too. Is regularized likelihood of general interest outside of the discrete models? I decided that a mix-in was going to be too heavy, but, for consideration, I started with a (private)

```
class Optimizer:
    def fit(self, ...)
        ...

    def gradient(self, ...):
        ....

    def hessian(self, ...):
        ....
```

I also answered this question for myself. Why are we doing this? It looks like we're just doing what the new scipy.optimize.minimize does. 1) I don't think we require new enough scipy. 2) we curry results in and out a bit to conform to what we need. 3) I'd like to also provide for estimation with general contraints via l-bfgs-b, sqlsqp, and, if installed cvxopt/openopt.

See discussion in #697.