<commit_before>from __future__ import division, print_function, absolute_import
import numpy as np


def check_arguments(fun, y0):
    y0 = np.asarray(y0, dtype=float)

    if y0.ndim != 1:
        raise ValueError("`y0` must be 1-dimensional.")

    def fun_wrapped(t, y):
        return np.asarray(fun(t, y))

    return fun_wrapped, y0


class OdeSolver(object):
    """Base class for ODE solvers.

    In order to implement a new solver you need to follow the guidelines:

        1. A constructor must accept parameters presented in the base class
           (listed below) followed by any other parameters specific to a
           solver.
        2. A solver must implement a private method
           `_step_impl(self, max_step=np.inf)` which propagates a solver one
           step further. It must return tuple ``(success, message)``, where
           ``success`` is a boolean indicating whether a step was successful,
           and ``message`` is a string containing description of a failure if
           a step failed or None otherwise.
        3. A solver must implement a private method `_dense_output_impl(self)`
           which returns `DenseOutput` object covering the last successful
           step.
        4. A solver must have attributes listed below in Attributes section.
        5. Use `fun(self, t, y)` method for the system rhs evaluation, this
           way the number of functions evaluations (`nfev`) will be tracked
           automatically.
        6. If a solver uses Jacobian and LU decompositions, it should track
           the number of Jacobian evaluations (`njev`) and the number of LU
           factorizations (`nlu`).
        7. By convention a function evaluations used to compute a finite
           difference approximation of the Jacobian should not be counted in
           `nfev`, thus use `_fun(self, t, y)` method when computing a finite
           difference approximation of the Jacobian.

    Parameters
    ----------
    fun : callable
        Right-hand side of the system. The calling signature is ``fun(t, y)``.
        Here ``t`` is a scalar, and ``y`` is ndarray with shape (n,). It
        must return an array_like with shape (n,).
    t0 : float
        Initial time.
    y0 : array_like, shape (n,)
        Initial state.
    t_crit : float
        Boundary time --- the integration won't continue beyond it. It also
        determines the direction of the integration.

    Attributes
    ----------
    n : int
        Number of equations.
    status : string
        Current status of the solver: 'running', 'finished' or 'failed'.
    t_crit : float
        Boundary time.
    direction : float
        Integration direction: +1 or -1.
    t : float
        Current time.
    y : ndarray
        Current state.
    t_old : float
        End time of the last successful step. None if no steps were made yet.
    step_size : float
        Size of the last successful step. None if no steps were made yet.
    nfev : int
        Number of the system rhs evaluations.
    njev : int
        Number of the Jacobian evaluations.
    nlu : int
        Number of LU decompositions of the Jacobian.
    """
    TOO_SMALL_STEP = "Required step size is less than spacing between numbers."

    def __init__(self, fun, t0, y0, t_crit):
        self.t_old = None
        self.t = t0
        self._fun, self.y = check_arguments(fun, y0)
        self.t_crit = t_crit

        self.direction = np.sign(t_crit - t0) if t_crit != t0 else 1
        self.n = self.y.size
        self.status = 'running'
        self.step_size = None

        self.nfev = 0
        self.njev = 0
        self.nlu = 0

    def fun(self, t, y):
        self.nfev += 1
        return self._fun(t, y)

    def step(self):
        """Perform one integration step.

        Returns
        -------
        message : string or None
            Report from the solver. Typically a reason for the failure if
            `self.status` is 'failed' after the step was taken or None
            otherwise.
        """
        if self.status != 'running':
            raise RuntimeError("Attempt to step on a failed or finished "
                               "solver.")

        if self.n == 0 or self.t == self.t_crit:
            # Handle corner cases of empty solver and no integration
            t = self.t
            t_new = self.t_crit
            self.t_old = t
            self.t = t_new
            self.step_size = np.abs(t_new - t)

            message = None

            if not np.isfinite(self.t) or self.direction * (self.t - self.t_crit) >= 0:
                self.status = 'finished'
        else:
            t = self.t
            success, message = self._step_impl()

            if not success:
                self.status = 'failed'
            else:
                self.t_old = t
                self.step_size = np.abs(self.t - self.t_old)
                if self.direction * (self.t - self.t_crit) >= 0:
                    self.status = 'finished'

        return message

    def dense_output(self):
        """Compute a local interpolant over the last successful step.

        Returns
        -------
        sol : `DenseOutput`<commit_msg>Converted step_size to property<commit_after>from __future__ import division, print_function, absolute_import
import numpy as np


def check_arguments(fun, y0):
    y0 = np.asarray(y0, dtype=float)

    if y0.ndim != 1:
        raise ValueError("`y0` must be 1-dimensional.")

    def fun_wrapped(t, y):
        return np.asarray(fun(t, y))

    return fun_wrapped, y0


class OdeSolver(object):
    """Base class for ODE solvers.

    In order to implement a new solver you need to follow the guidelines:

        1. A constructor must accept parameters presented in the base class
           (listed below) followed by any other parameters specific to a
           solver.
        2. A solver must implement a private method
           `_step_impl(self, max_step=np.inf)` which propagates a solver one
           step further. It must return tuple ``(success, message)``, where
           ``success`` is a boolean indicating whether a step was successful,
           and ``message`` is a string containing description of a failure if
           a step failed or None otherwise.
        3. A solver must implement a private method `_dense_output_impl(self)`
           which returns `DenseOutput` object covering the last successful
           step.
        4. A solver must have attributes listed below in Attributes section.
        5. Use `fun(self, t, y)` method for the system rhs evaluation, this
           way the number of functions evaluations (`nfev`) will be tracked
           automatically.
        6. If a solver uses Jacobian and LU decompositions, it should track
           the number of Jacobian evaluations (`njev`) and the number of LU
           factorizations (`nlu`).
        7. By convention a function evaluations used to compute a finite
           difference approximation of the Jacobian should not be counted in
           `nfev`, thus use `_fun(self, t, y)` method when computing a finite
           difference approximation of the Jacobian.

    Parameters
    ----------
    fun : callable
        Right-hand side of the system. The calling signature is ``fun(t, y)``.
        Here ``t`` is a scalar, and ``y`` is ndarray with shape (n,). It
        must return an array_like with shape (n,).
    t0 : float
        Initial time.
    y0 : array_like, shape (n,)
        Initial state.
    t_crit : float
        Boundary time --- the integration won't continue beyond it. It also
        determines the direction of the integration.

    Attributes
    ----------
    n : int
        Number of equations.
    status : string
        Current status of the solver: 'running', 'finished' or 'failed'.
    t_crit : float
        Boundary time.
    direction : float
        Integration direction: +1 or -1.
    t : float
        Current time.
    y : ndarray
        Current state.
    t_old : float
        End time of the last successful step. None if no steps were made yet.
    step_size : float
        Size of the last successful step. None if no steps were made yet.
    nfev : int
        Number of the system rhs evaluations.
    njev : int
        Number of the Jacobian evaluations.
    nlu : int
        Number of LU decompositions of the Jacobian.
    """
    TOO_SMALL_STEP = "Required step size is less than spacing between numbers."

    def __init__(self, fun, t0, y0, t_crit):
        self.t_old = None
        self.t = t0
        self._fun, self.y = check_arguments(fun, y0)
        self.t_crit = t_crit

        self.direction = np.sign(t_crit - t0) if t_crit != t0 else 1
        self.n = self.y.size
        self.status = 'running'

        self.nfev = 0
        self.njev = 0
        self.nlu = 0

    @property
    def step_size(self):
        if self.t_old is None:
            return None
        else:
            return np.abs(self.t - self.t_old)

    def fun(self, t, y):
        self.nfev += 1
        return self._fun(t, y)

    def step(self):
        """Perform one integration step.

        Returns
        -------
        message : string or None
            Report from the solver. Typically a reason for the failure if
            `self.status` is 'failed' after the step was taken or None
            otherwise.
        """
        if self.status != 'running':
            raise RuntimeError("Attempt to step on a failed or finished "
                               "solver.")

        if self.n == 0 or self.t == self.t_crit:
            # Handle corner cases of empty solver and no integration
            t = self.t
            t_new = self.t_crit
            self.t_old = t
            self.t = t_new

            message = None

            if not np.isfinite(self.t) or self.direction * (self.t - self.t_crit) >= 0:
                self.status = 'finished'
        else:
            t = self.t
            success, message = self._step_impl()

            if not success:
                self.status = 'failed'
            else:
                self.t_old = t
                if self.direction * (self.t - self.t_crit) >= 0:
                    self.status = 'finished'

        return message

    def dense_output(self):
        """Compute a local interpolant over the last successful step.

        Returns
        -------
        sol : `DenseOutput`
{'fraction_non_alphanumeric': 0.07992707733640377, 'fraction_numerical': 0.0063327576280944155, 'mean_word_length': 1.8094339622641509, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6059456', 'n_tokens_mistral': 2915, 'n_tokens_neox': 2788, 'n_words': 1151}