Source code for gemseo.algos.sequence_transformer.acceleration.minimum_polynomial

# Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 3 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
# Contributors:
#    INITIAL AUTHORS - initial API and implementation and/or initial
#                           documentation
#        :author: Sebastien Bocquet, Alexandre Scotto Di Perrotolo
#    OTHER AUTHORS   - MACROSCOPIC CHANGES
"""The minimum polynomial method."""

from __future__ import annotations

from typing import TYPE_CHECKING

from numpy import hstack
from scipy.linalg import lstsq

from gemseo.algos.sequence_transformer.sequence_transformer import SequenceTransformer

if TYPE_CHECKING:
    from typing import ClassVar

    from numpy.typing import NDArray


[docs] class MinimumPolynomial(SequenceTransformer): """The minimum polynomial extrapolation method. The method is introduced in: Cabay, S.; Jackson, L.W, "A polynomial extrapolation method for finding limits and antilimits of vector sequences", SIAM Journal on Numerical Analysis, (1976). """ _MINIMUM_NUMBER_OF_ITERATES: ClassVar[int] = 2 _MINIMUM_NUMBER_OF_RESIDUALS: ClassVar[int] = 2 def __init__(self, window_size: int = 5) -> None: """ Args: window_size: The maximum number of iterates to be kept. """ # noqa:D205 D212 D415 if not isinstance(window_size, int) or window_size < 1: msg = "The window size must be greater than or equal to 1." raise ValueError(msg) self.__window_size = window_size self.__d2xn_matrix = None self.__dgxn_matrix = None super().__init__() def _compute_transformed_iterate(self) -> NDArray: d2xn = (self._residuals[-1] - self._residuals[-2]).reshape(-1, 1) dgxn = (self._iterates[-1] - self._iterates[-2]).reshape(-1, 1) # If reaching up the window size, then remove the oldest element if ( self.__d2xn_matrix is not None and self.__d2xn_matrix.shape[1] == self.__window_size ): self.__d2xn_matrix = self.__d2xn_matrix[:, 1:] self.__dgxn_matrix = self.__dgxn_matrix[:, 1:] # Stack the new vectors to both matrices self.__d2xn_matrix = ( hstack([self.__d2xn_matrix, d2xn]) if self.__d2xn_matrix is not None else d2xn ) self.__dgxn_matrix = ( hstack([self.__dgxn_matrix, dgxn]) if self.__dgxn_matrix is not None else dgxn ) c, _, _, _ = lstsq(self.__d2xn_matrix, self._residuals[-1], cond=1e-16) return self._iterates[-1] - self.__dgxn_matrix @ c