Repository: statsmodels/statsmodels
Pull request: TST: ets: test for simple exponential smoothing convergence
- [ ] closes #6883 
- [ ] tests added / passed. 
- [ ] code/documentation is well formatted.  
- [ ] properly formatted commit message. See 
      [NumPy's guide](https://docs.scipy.org/doc/numpy-1.15.1/dev/gitwash/development_workflow.html#writing-the-commit-message). 

I added a test for the example in #6883. It works locally, PR to check if it is also working in CI.

Problem statement:
BUG: ETS_Model fails to converge for basic model.
#### Describe the bug

ETS_Model fails to converge -- or even move off starting value, in a simple model.

#### Code Sample, a copy-pastable example if possible


```python
from statsmodels.tsa.exponential_smoothing.ets import ETSModel
from statsmodels.tsa.statespace.exponential_smoothing import ExponentialSmoothing

import numpy as np
gen = np.random.default_rng(0)
e = gen.standard_normal(12000)
y = e.copy()
for i in range(1, e.shape[0]):
    y[i] = y[i-1] - 0.2 * e[i-1] + e[i]
y = y[200:]
res= ExponentialSmoothing(y).fit()
ets_res= ETSModel(y).fit()
```
<details>

**Note**: As you can see, there are many issues on our GitHub tracker, so it is very possible that your issue has been posted before. Please check first before submitting so that we do not have to handle and close duplicates.

**Note**: Please be sure you are using the latest released version of `statsmodels`, or a recent build of `master`. If your problem has been fixed in an unreleased version, you might be able to use `master` until a new release occurs. 

**Note**: If you are using a released version, have you verified that the bug exists in the master branch of this repository? It helps the limited resources if we know problems exist in the current master so that they do not need to check whether the code sample produces a bug in the next release.

</details>


#### Expected Output

Should converge like EstponentialSmoothing does. Instead see
```
C:\Anaconda\lib\site-packages\scipy\optimize\_numdiff.py:519: RuntimeWarning: invalid value encountered in true_divide
  J_transposed[i] = df / dx
c:\git\statsmodels\statsmodels\base\model.py:568: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  "Check mle_retvals", ConvergenceWarning)
```

and `summary()`

```
"""
                                 ETS Results                                  
==============================================================================
Dep. Variable:                      y   No. Observations:                11800
Model:                       ETS(ANN)   Log Likelihood              -24532.560
Date:                Mon, 13 Jul 2020   AIC                          49069.121
Time:                        17:56:06   BIC                          49083.872
Sample:                             0   HQIC                         49074.073
                              - 11800                                         
Covariance Type:               approx                                         
===================================================================================
                      coef    std err          z      P>|z|      [0.025      0.975]
-----------------------------------------------------------------------------------
smoothing_level     0.1000      0.001     79.183      0.000       0.098       0.102
initial_level       1.3786      0.843      1.635      0.102      -0.275       3.032
===================================================================================
Ljung-Box (Q):                         nan   Jarque-Bera (JB):                  nan
Prob(Q):                               nan   Prob(JB):                          nan
Heteroskedasticity (H):                nan   Skew:                              nan
Prob(H) (two-sided):                   nan   Kurtosis:                          nan
===================================================================================

Warnings:
[1] Covariance matrix calculated using numerical (complex-step) differentiation
```
#### Output of ``import statsmodels.api as sm; sm.show_versions()``

<details>

Tested against master.

</details>

Hints from issue discussion:
@s-scherrer any idea why it fails here?
I just tried running this on my machine, here it converges and the value of alpha is similar to the one obtained with `ExponentialSmoothing` (0.8049 vs 0.8050).

<details>

```
In [1]: from statsmodels.tsa.exponential_smoothing.ets import ETSModel 
   ...: from statsmodels.tsa.statespace.exponential_smoothing import Exponential
   ...: Smoothing 
   ...:  
   ...: import numpy as np 
   ...: gen = np.random.default_rng(0) 
   ...: e = gen.standard_normal(12000) 
   ...: y = e.copy() 
   ...: for i in range(1, e.shape[0]): 
   ...:     y[i] = y[i-1] - 0.2 * e[i-1] + e[i] 
   ...: y = y[200:] 
   ...: res= ExponentialSmoothing(y).fit() 
   ...: ets_res= ETSModel(y).fit()                                              
RUNNING THE L-BFGS-B CODE

           * * *

Machine precision = 2.220D-16
 N =            2     M =           10
 This problem is unconstrained.

At X0         0 variables are exactly at the bounds

At iterate    0    f=  2.07904D+00    |proj g|=  4.18003D-01

At iterate    5    f=  1.41871D+00    |proj g|=  1.52936D-04

At iterate   10    f=  1.41871D+00    |proj g|=  8.24925D-05

           * * *

Tit   = total number of iterations
Tnf   = total number of function evaluations
Tnint = total number of segments explored during Cauchy searches
Skip  = number of BFGS updates skipped
Nact  = number of active bounds at final generalized Cauchy point
Projg = norm of the final projected gradient
F     = final function value

           * * *

   N    Tit     Tnf  Tnint  Skip  Nact     Projg        F
    2     14     15      1     0     0   1.547D-06   1.419D+00
  F =   1.4187097536168372     

CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL            
RUNNING THE L-BFGS-B CODE

           * * *

Machine precision = 2.220D-16
 N =            7     M =           10

At X0         5 variables are exactly at the bounds

At iterate    0    f=  2.07903D+00    |proj g|=  8.99900D-01

At iterate    1    f=  1.43785D+00    |proj g|=  1.92631D-01

At iterate    2    f=  1.43156D+00    |proj g|=  1.58551D-01

At iterate    3    f=  1.41874D+00    |proj g|=  7.93901D-03

At iterate    4    f=  1.41871D+00    |proj g|=  5.61018D-04

At iterate    5    f=  1.41871D+00    |proj g|=  2.27596D-05

At iterate    6    f=  1.41871D+00    |proj g|=  2.27374D-05

           * * *

Tit   = total number of iterations
Tnf   = total number of function evaluations
Tnint = total number of segments explored during Cauchy searches
Skip  = number of BFGS updates skipped
Nact  = number of active bounds at final generalized Cauchy point
Projg = norm of the final projected gradient
F     = final function value

           * * *

   N    Tit     Tnf  Tnint  Skip  Nact     Projg        F
    7      6      8      7     0     5   2.274D-05   1.419D+00
  F =   1.4187126931425427     

CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH             

In [2]: ets_res.summary()                                                                                                                                                                        
Out[2]: 
<class 'statsmodels.iolib.summary.Summary'>
"""
                                 ETS Results                                  
==============================================================================
Dep. Variable:                      y   No. Observations:                11800
Model:                       ETS(ANN)   Log Likelihood              -16740.810
Date:                Mon, 13 Jul 2020   AIC                          33485.620
Time:                        20:09:03   BIC                          33500.371
Sample:                             0   HQIC                         33490.572
                              - 11800                                         
Covariance Type:               approx                                         
===================================================================================
                      coef    std err          z      P>|z|      [0.025      0.975]
-----------------------------------------------------------------------------------
smoothing_level     0.8049      0.009     90.263      0.000       0.787       0.822
initial_level       1.3787      0.981      1.406      0.160      -0.543       3.301
===================================================================================
Ljung-Box (Q):                         nan   Jarque-Bera (JB):                  nan
Prob(Q):                               nan   Prob(JB):                          nan
Heteroskedasticity (H):                nan   Skew:                              nan
Prob(H) (two-sided):                   nan   Kurtosis:                          nan
===================================================================================

Warnings:
[1] Covariance matrix calculated using numerical (complex-step) differentiation.
"""

In [3]: res.summary()                                                                                                                                                                            
Out[3]: 
<class 'statsmodels.iolib.summary.Summary'>
"""
                        Exponential Smoothing Results                         
==============================================================================
Dep. Variable:                      y   No. Observations:                11800
Model:                   ETS(A, N, N)   Log Likelihood              -16740.775
Date:                Mon, 13 Jul 2020   AIC                          33487.550
Time:                        20:10:29   BIC                          33509.678
Sample:                             0   HQIC                         33494.979
                              - 11800   Scale                            1.000
Covariance Type:                  opg                                         
===================================================================================
                      coef    std err          z      P>|z|      [0.025      0.975]
-----------------------------------------------------------------------------------
smoothing_level     0.8050      0.009     88.069      0.000       0.787       0.823
initial_level       1.6348      5.583      0.293      0.770      -9.307      12.577
===================================================================================
Ljung-Box (Q):                       31.78   Jarque-Bera (JB):                 1.52
Prob(Q):                              0.82   Prob(JB):                         0.47
Heteroskedasticity (H):               0.99   Skew:                            -0.03
Prob(H) (two-sided):                  0.73   Kurtosis:                         3.01
===================================================================================

Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).
"""
```

</details>

Output of sm.show_versions():

<details>

```
INSTALLED VERSIONS
------------------
Python: 3.8.3.final.0
OS: Linux 5.7.7-1-default #1 SMP Wed Jul 1 19:03:27 UTC 2020 (cba119b) x86_64
byteorder: little
LC_ALL: None
LANG: en_GB.UTF-8

statsmodels
===========

Installed: v0.12.0.dev0+567.g4f226bc35 (/home/samuel/Documents/OpenSource/statsmodels/statsmodels)

Required Dependencies
=====================

cython: 0.29.20 (/home/samuel/.pyenv/versions/statsmodels/lib64/python3.8/site-packages/Cython)
numpy: 1.18.5 (/home/samuel/.pyenv/versions/statsmodels/lib64/python3.8/site-packages/numpy)
scipy: 1.4.1 (/home/samuel/.pyenv/versions/statsmodels/lib64/python3.8/site-packages/scipy)
pandas: 1.0.4 (/home/samuel/.pyenv/versions/statsmodels/lib64/python3.8/site-packages/pandas)
    dateutil: 2.8.1 (/home/samuel/.pyenv/versions/statsmodels/lib/python3.8/site-packages/dateutil)
patsy: 0.5.1 (/home/samuel/.pyenv/versions/statsmodels/lib/python3.8/site-packages/patsy)

Optional Dependencies
=====================

matplotlib: 3.2.1 (/home/samuel/.pyenv/versions/statsmodels/lib64/python3.8/site-packages/matplotlib)
    backend: TkAgg 
cvxopt: Not installed
joblib: Not installed

Developer Tools
================

IPython: 7.15.0 (/home/samuel/.pyenv/versions/statsmodels/lib/python3.8/site-packages/IPython)
    jinja2: 2.11.2 (/home/samuel/.pyenv/versions/statsmodels/lib/python3.8/site-packages/jinja2)
sphinx: 3.1.0 (/home/samuel/.pyenv/versions/statsmodels/lib/python3.8/site-packages/sphinx)
    pygments: 2.6.1 (/home/samuel/.pyenv/versions/statsmodels/lib/python3.8/site-packages/pygments)
pytest: 5.4.3 (/home/samuel/.pyenv/versions/statsmodels/lib/python3.8/site-packages/pytest)
virtualenv: Not installed
```
</details>

Commit message: remove fixed parameters before fitting

Patch to review:
diff --git a/statsmodels/tsa/exponential_smoothing/_ets_smooth.pyx b/statsmodels/tsa/exponential_smoothing/_ets_smooth.pyx
index ebc77599a65..5a92c94638a 100644
--- a/statsmodels/tsa/exponential_smoothing/_ets_smooth.pyx
+++ b/statsmodels/tsa/exponential_smoothing/_ets_smooth.pyx
@@ -17,16 +17,30 @@ ctypedef fused numeric:
 cpdef _initialize_ets_smooth(
     numeric [:] params,
     numeric[:,:] xhat,
+    np.uint8_t [:] is_fixed,
+    numeric [:] fixed_values,
     bool use_beta_star=False,
     bool use_gamma_star=False,
 ):
     """Extracts parameters and initializes states xhat"""
+    cdef numeric [:] full_params
     cdef numeric alpha, beta, gamma, phi, beta_star, gamma_star
-    cdef Py_ssize_t m, n
+    cdef Py_ssize_t idx_all, idx_params, n_all, m, n
+
+    n_all = len(is_fixed)
+    full_params = np.empty_like(fixed_values)
+    idx_params = 0
+    for idx_all in range(n_all):
+        if not is_fixed[idx_all]:
+            full_params[idx_all] = params[idx_params]
+            idx_params += 1
+        else:
+            full_params[idx_all] = fixed_values[idx_all]
+
 
     # get params
-    alpha, beta, gamma, phi = params[0:4]
-    m = len(params[6:])
+    alpha, beta, gamma, phi = full_params[0:4]
+    m = len(full_params[6:])
     n = len(xhat)
 
     # calculate beta_star and gamma_star
@@ -43,7 +57,7 @@ cpdef _initialize_ets_smooth(
     # initialize states
     # l = xhat[:,0], b = xhat[:,1], s = xhat[:,2:2+m]
     # seasons are sorted such that xhat[:,2+m-1] contains s[-m]
-    xhat[n-1, :] = params[4:]
+    xhat[n-1, :] = full_params[4:]
 
     return alpha, beta_star, gamma_star, phi, m, n
 
@@ -51,6 +65,8 @@ def _ets_smooth_add_add(numeric [:] params,
                         numeric [:] y,
                         numeric [:] yhat,
                         numeric [:,:] xhat,
+                        np.uint8_t [:] is_fixed,
+                        numeric [:] fixed_values,
                         bool use_beta_star=False,
                         bool use_gamma_star=False):
     """Smoothing with additive trend and additive season"""
@@ -59,7 +75,7 @@ def _ets_smooth_add_add(numeric [:] params,
 
     # get params
     alpha, beta_star, gamma_star, phi, m, n = _initialize_ets_smooth(
-        params, xhat, use_beta_star, use_gamma_star
+        params, xhat, is_fixed, fixed_values, use_beta_star, use_gamma_star
     )
 
     # smooth
@@ -84,6 +100,8 @@ def _ets_smooth_add_mul(numeric [:] params,
                         numeric [:] y,
                         numeric [:] yhat,
                         numeric [:,:] xhat,
+                        np.uint8_t [:] is_fixed,
+                        numeric [:] fixed_values,
                         bool use_beta_star=False,
                         bool use_gamma_star=False):
     """Smoothing with additive trend and multiplicative season"""
@@ -92,7 +110,7 @@ def _ets_smooth_add_mul(numeric [:] params,
 
     # get params
     alpha, beta_star, gamma_star, phi, m, n = _initialize_ets_smooth(
-        params, xhat, use_beta_star, use_gamma_star
+        params, xhat, is_fixed, fixed_values, use_beta_star, use_gamma_star
     )
 
     # smooth
@@ -117,6 +135,8 @@ def _ets_smooth_mul_add(numeric [:] params,
                         numeric [:] y,
                         numeric [:] yhat,
                         numeric [:,:] xhat,
+                        np.uint8_t [:] is_fixed,
+                        numeric [:] fixed_values,
                         bool use_beta_star=False,
                         bool use_gamma_star=False):
     """Smoothing with multiplicative trend and additive season"""
@@ -125,7 +145,7 @@ def _ets_smooth_mul_add(numeric [:] params,
 
     # get params
     alpha, beta_star, gamma_star, phi, m, n = _initialize_ets_smooth(
-        params, xhat, use_beta_star, use_gamma_star
+        params, xhat, is_fixed, fixed_values, use_beta_star, use_gamma_star
     )
 
     # smooth
@@ -150,6 +170,8 @@ def _ets_smooth_mul_mul(numeric [:] params,
                         numeric [:] y,
                         numeric [:] yhat,
                         numeric [:,:] xhat,
+                        np.uint8_t [:] is_fixed,
+                        numeric [:] fixed_values,
                         bool use_beta_star=False,
                         bool use_gamma_star=False):
     """Smoothing with multiplicative trend and multiplicative season"""
@@ -158,7 +180,7 @@ def _ets_smooth_mul_mul(numeric [:] params,
 
     # get params
     alpha, beta_star, gamma_star, phi, m, n = _initialize_ets_smooth(
-        params, xhat, use_beta_star, use_gamma_star
+        params, xhat, is_fixed, fixed_values, use_beta_star, use_gamma_star
     )
 
     # smooth
diff --git a/statsmodels/tsa/exponential_smoothing/ets.py b/statsmodels/tsa/exponential_smoothing/ets.py
index 22a28bdc024..943a13dd565 100644
--- a/statsmodels/tsa/exponential_smoothing/ets.py
+++ b/statsmodels/tsa/exponential_smoothing/ets.py
@@ -966,7 +966,7 @@ def fit(
             internal_start_params = self._convert_and_bound_start_params(
                 start_params
             )
-            kwargs["bounds"] = self._setup_bounds()
+            bounds = self._setup_bounds()
 
             # check if we need to use the starred parameters
             use_beta_star = "smoothing_trend" not in self.bounds
@@ -976,6 +976,21 @@ def fit(
             if use_gamma_star:
                 internal_start_params[2] /= 1 - internal_start_params[0]
 
+            # check if we have fixed parameters and remove them from the
+            # parameter vector
+            is_fixed = np.zeros(self._k_params_internal, dtype=np.uint8)
+            fixed_values = np.empty_like(internal_start_params)
+            params_without_fixed = []
+            kwargs["bounds"] = []
+            for i in range(self._k_params_internal):
+                if bounds[i][0] == bounds[i][1]:
+                    is_fixed[i] = True
+                    fixed_values[i] = bounds[i][0]
+                else:
+                    params_without_fixed.append(internal_start_params[i])
+                    kwargs["bounds"].append(bounds[i])
+            params_without_fixed = np.asarray(params_without_fixed)
+
             # pre-allocate memory for smoothing results
             yhat = np.zeros(self.nobs)
             xhat = np.zeros((self.nobs, self._k_states_internal))
@@ -983,8 +998,14 @@ def fit(
             kwargs["approx_grad"] = True
             with self.use_internal_loglike():
                 mlefit = super().fit(
-                    internal_start_params,
-                    fargs=(yhat, xhat, use_beta_star, use_gamma_star),
+                    params_without_fixed,
+                    fargs=(
+                        yhat,
+                        xhat,
+                        is_fixed,
+                        fixed_values,
+                        use_beta_star,
+                        use_gamma_star),
                     method="lbfgs",
                     maxiter=maxiter,
                     full_output=full_output,
@@ -994,11 +1015,21 @@ def fit(
                     **kwargs,
                 )
             # convert params back
+            # first, insert fixed params
+            fitted_params = np.empty_like(internal_start_params)
+            idx_without_fixed = 0
+            for i in range(len(fitted_params)):
+                if is_fixed[i]:
+                    fitted_params[i] = fixed_values[i]
+                else:
+                    fitted_params[i] = mlefit.params[idx_without_fixed]
+                    idx_without_fixed += 1
+
             if use_beta_star:
-                mlefit.params[1] *= mlefit.params[0]
+                fitted_params[1] *= fitted_params[0]
             if use_gamma_star:
-                mlefit.params[2] *= 1 - mlefit.params[0]
-            final_params = self._model_params(mlefit.params)
+                fitted_params[2] *= 1 - fitted_params[0]
+            final_params = self._model_params(fitted_params)
 
         if return_params:
             return final_params
@@ -1010,7 +1041,8 @@ def fit(
             return result
 
     def _loglike_internal(
-        self, params, yhat, xhat, use_beta_star=False, use_gamma_star=False
+            self, params, yhat, xhat, is_fixed=None, fixed_values=None,
+            use_beta_star=False, use_gamma_star=False
     ):
         """
         Log-likelihood function to be called from fit to avoid reallocation of
@@ -1020,13 +1052,20 @@ def _loglike_internal(
         ----------
         params : np.ndarray of np.float
             Model parameters: (alpha, beta, gamma, phi, l[-1],
-            b[-1], s[-1], ..., s[-m]). This must be in the format of internal
-            parameters.
+            b[-1], s[-1], ..., s[-m]). If there are no fixed values this must
+            be in the format of internal parameters. Otherwise the fixed values
+            are skipped.
         yhat : np.ndarray
             Array of size (n,) where fitted values will be written to.
         xhat : np.ndarray
             Array of size (n, _k_states_internal) where fitted states will be
             written to.
+        is_fixed : np.ndarray or None
+            Boolean array indicating values which are fixed during fitting.
+            This must have the full length of internal parameters.
+        fixed_values : np.ndarray or None
+            Array of fixed values (arbitrary values for non-fixed parameters)
+            This must have the full length of internal parameters.
         use_beta_star : boolean
             Whether to internally use beta_star as parameter
         use_gamma_star : boolean
@@ -1036,8 +1075,16 @@ def _loglike_internal(
             data = np.asarray(self.endog, dtype=complex)
         else:
             data = self.endog
+
+        if is_fixed is None:
+            is_fixed = np.zeros(self._k_params_internal, dtype=np.uint8)
+            fixed_values = np.empty(
+                self._k_params_internal, dtype=params.dtype
+            )
+
         self._smoothing_func(
-            params, data, yhat, xhat, use_beta_star, use_gamma_star
+            params, data, yhat, xhat, is_fixed, fixed_values, use_beta_star,
+            use_gamma_star
         )
         res = self._residuals(yhat, data=data)
         logL = -self.nobs / 2 * (np.log(2 * np.pi * np.mean(res ** 2)) + 1)
@@ -1128,7 +1175,11 @@ def _smooth(self, params):
         internal_params = self._internal_params(params)
         yhat = np.zeros(self.nobs)
         xhat = np.zeros((self.nobs, self._k_states_internal))
-        self._smoothing_func(internal_params, self.endog, yhat, xhat)
+        is_fixed = np.zeros(self._k_params_internal, dtype=np.uint8)
+        fixed_values = np.empty(self._k_params_internal, dtype=params.dtype)
+        self._smoothing_func(
+            internal_params, self.endog, yhat, xhat, is_fixed, fixed_values
+        )
 
         # remove states that are only internal
         states = self._get_states(xhat)
@@ -1548,6 +1599,9 @@ def simulate(
         # set initial values and obtain parameters
         start_params = self._get_prediction_params(start_idx)
         x = np.zeros((nsimulations, self.model._k_states_internal))
+        # is fixed and fixed values are dummy arguments
+        is_fixed = np.zeros(len(start_params), dtype=np.uint8)
+        fixed_values = np.zeros_like(start_params)
         (
             alpha,
             beta_star,
@@ -1555,7 +1609,9 @@ def simulate(
             phi,
             m,
             _,
-        ) = smooth._initialize_ets_smooth(start_params, x)
+        ) = smooth._initialize_ets_smooth(
+            start_params, x, is_fixed, fixed_values
+        )
         beta = alpha * beta_star
         gamma = (1 - alpha) * gamma_star
         # make x a 3 dimensional matrix: first dimension is nsimulations
diff --git a/statsmodels/tsa/tests/test_exponential_smoothing.py b/statsmodels/tsa/tests/test_exponential_smoothing.py
index ffff7d8be9d..213e5c95f66 100644
--- a/statsmodels/tsa/tests/test_exponential_smoothing.py
+++ b/statsmodels/tsa/tests/test_exponential_smoothing.py
@@ -12,6 +12,7 @@
 import scipy.stats
 
 from statsmodels.tsa.exponential_smoothing.ets import ETSModel
+from statsmodels.tsa.holtwinters import ExponentialSmoothing
 
 # This contains tests for the exponential smoothing implementation in
 # tsa/exponential_smoothing/ets.py.
@@ -618,3 +619,31 @@ def test_hessian(austourists_model):
     austourists_model.hessian(
         fit.params, approx_complex_step=False, approx_centered=True,
     )
+
+
+def test_convergence_simple():
+    # issue 6883
+    gen = np.random.default_rng(0)
+    e = gen.standard_normal(12000)
+    y = e.copy()
+    for i in range(1, e.shape[0]):
+        y[i] = y[i - 1] - 0.2 * e[i - 1] + e[i]
+    y = y[200:]
+    res = ExponentialSmoothing(y).fit()
+    ets_res = ETSModel(y).fit()
+
+    # the smoothing level should be very similar, the initial state might be
+    # different as it doesn't influence the final result too much
+    assert_almost_equal(
+        res.params['smoothing_level'],
+        ets_res.smoothing_level,
+        3
+    )
+
+    # the first few values are influenced by differences in initial state, so
+    # we don't test them here
+    assert_almost_equal(
+        res.fittedvalues[10:],
+        ets_res.fittedvalues[10:],
+        3
+    )


Code review comments:
diff_hunk: @@ -17,16 +17,30 @@ ctypedef fused numeric:
 cpdef _initialize_ets_smooth(
     numeric [:] params,
     numeric[:,:] xhat,
+    np.uint8_t [:] is_fixed,
path: statsmodels/tsa/exponential_smoothing/_ets_smooth.pyx
text: @user1:
Might as well use np.long here which then maps to `dtype=int` when creating an array.  While uint8 is space-efficient, it is not any faster than using the native int type, and this mask is never large.

@author:
I used `np.long_t` in the cython code and `dtype=np.long` now. Using `np.long_t` and `dtype=int` failed on the Windows machines.

@author:
Still fails with `ValueError: Buffer dtype mismatch, expected 'long_t' but got 'long'` on the Windows machines. Any idea why?

diff_hunk: @@ -618,3 +619,31 @@ def test_hessian(austourists_model):
     austourists_model.hessian(
         fit.params, approx_complex_step=False, approx_centered=True,
     )
+
+
+def test_convergence_simple():
+    # issue 6883
+    gen = np.random.default_rng(0)
path: statsmodels/tsa/tests/test_exponential_smoothing.py
text: @user1:
Need to use np.random.RandomState(0) here since we still support very old NumPy.