from abc import ABC, abstractmethod
import numpy as np


class Solver(ABC):
    def __init__(self, acceleration, dt=1 / 100):
        self.acceleration = acceleration
        self.dt = dt

    def iter(self, x0, T):
        """
        x0: list of array-like
            Initial conditions for each object. Each tuple indiciates a derivative of a higher order.
            E.G. [pos, vel, acc, ...]
        """
        t = 0

        # Precondition as arraylike to save memory copies
        x = [np.array(d) for d in x0]

        while t < T - self.dt / 2:
            t = t + self.dt
            x = self.update(x)
            yield [*x]

    @abstractmethod
    def update(self, x):
        pass


class Euler(Solver):
    def update(self, x):
        a = self.acceleration(x)

        x[0] = x[0] + x[1] * self.dt
        x[1] = x[1] + a * self.dt
        return x


class LeapFrog(Solver):
    def update(self, x):

        # Update half-step
        x[0] = x[0] + x[1] * self.dt / 2

        # Acceleration with updated half-step
        a = self.acceleration(x)

        x[1] = x[1] + a * self.dt

        # Update second half-step
        x[0] = x[0] + x[1] * self.dt / 2
        return x
4382ff64e68d2201335cfc4e0f2553525ed9c022
<mask token>


class Solver(ABC):
    <mask token>
    <mask token>
    <mask token>


class Euler(Solver):

    def update(self, x):
        a = self.acceleration(x)
        x[0] = x[0] + x[1] * self.dt
        x[1] = x[1] + a * self.dt
        return x


class LeapFrog(Solver):

    def update(self, x):
        x[0] = x[0] + x[1] * self.dt / 2
        a = self.acceleration(x)
        x[1] = x[1] + a * self.dt
        x[0] = x[0] + x[1] * self.dt / 2
        return x

<mask token>


class Solver(ABC):

    def __init__(self, acceleration, dt=1 / 100):
        self.acceleration = acceleration
        self.dt = dt
    <mask token>

    @abstractmethod
    def update(self, x):
        pass


class Euler(Solver):

    def update(self, x):
        a = self.acceleration(x)
        x[0] = x[0] + x[1] * self.dt
        x[1] = x[1] + a * self.dt
        return x


class LeapFrog(Solver):

    def update(self, x):
        x[0] = x[0] + x[1] * self.dt / 2
        a = self.acceleration(x)
        x[1] = x[1] + a * self.dt
        x[0] = x[0] + x[1] * self.dt / 2
        return x

<mask token>


class Solver(ABC):

    def __init__(self, acceleration, dt=1 / 100):
        self.acceleration = acceleration
        self.dt = dt

    def iter(self, x0, T):
        """
        x0: list of array-like
            Initial conditions for each object. Each tuple indiciates a derivative of a higher order.
            E.G. [pos, vel, acc, ...]
        """
        t = 0
        x = [np.array(d) for d in x0]
        while t < T - self.dt / 2:
            t = t + self.dt
            x = self.update(x)
            yield [*x]

    @abstractmethod
    def update(self, x):
        pass


class Euler(Solver):

    def update(self, x):
        a = self.acceleration(x)
        x[0] = x[0] + x[1] * self.dt
        x[1] = x[1] + a * self.dt
        return x


class LeapFrog(Solver):

    def update(self, x):
        x[0] = x[0] + x[1] * self.dt / 2
        a = self.acceleration(x)
        x[1] = x[1] + a * self.dt
        x[0] = x[0] + x[1] * self.dt / 2
        return x

from abc import ABC, abstractmethod
import numpy as np


class Solver(ABC):

    def __init__(self, acceleration, dt=1 / 100):
        self.acceleration = acceleration
        self.dt = dt

    def iter(self, x0, T):
        """
        x0: list of array-like
            Initial conditions for each object. Each tuple indiciates a derivative of a higher order.
            E.G. [pos, vel, acc, ...]
        """
        t = 0
        x = [np.array(d) for d in x0]
        while t < T - self.dt / 2:
            t = t + self.dt
            x = self.update(x)
            yield [*x]

    @abstractmethod
    def update(self, x):
        pass


class Euler(Solver):

    def update(self, x):
        a = self.acceleration(x)
        x[0] = x[0] + x[1] * self.dt
        x[1] = x[1] + a * self.dt
        return x


class LeapFrog(Solver):

    def update(self, x):
        x[0] = x[0] + x[1] * self.dt / 2
        a = self.acceleration(x)
        x[1] = x[1] + a * self.dt
        x[0] = x[0] + x[1] * self.dt / 2
        return x

from abc import ABC, abstractmethod
import numpy as np


class Solver(ABC):
    def __init__(self, acceleration, dt=1 / 100):
        self.acceleration = acceleration
        self.dt = dt

    def iter(self, x0, T):
        """
        x0: list of array-like
            Initial conditions for each object. Each tuple indiciates a derivative of a higher order.
            E.G. [pos, vel, acc, ...]
        """
        t = 0

        # Precondition as arraylike to save memory copies
        x = [np.array(d) for d in x0]

        while t < T - self.dt / 2:
            t = t + self.dt
            x = self.update(x)
            yield [*x]

    @abstractmethod
    def update(self, x):
        pass


class Euler(Solver):
    def update(self, x):
        a = self.acceleration(x)

        x[0] = x[0] + x[1] * self.dt
        x[1] = x[1] + a * self.dt
        return x


class LeapFrog(Solver):
    def update(self, x):

        # Update half-step
        x[0] = x[0] + x[1] * self.dt / 2

        # Acceleration with updated half-step
        a = self.acceleration(x)

        x[1] = x[1] + a * self.dt

        # Update second half-step
        x[0] = x[0] + x[1] * self.dt / 2
        return x