# Path: torchdiffeq/_impl/odeint.py
# def odeint(func, y0, t, *, rtol=1e-7, atol=1e-9, method=None, options=None, event_fn=None):
#     """Integrate a system of ordinary differential equations.
# 
#     Solves the initial value problem for a non-stiff system of first order ODEs:
#         ```
#         dy/dt = func(t, y), y(t[0]) = y0
#         ```
#     where y is a Tensor or tuple of Tensors of any shape.
# 
#     Output dtypes and numerical precision are based on the dtypes of the inputs `y0`.
# 
#     Args:
#         func: Function that maps a scalar Tensor `t` and a Tensor holding the state `y`
#             into a Tensor of state derivatives with respect to time. Optionally, `y`
#             can also be a tuple of Tensors.
#         y0: N-D Tensor giving starting value of `y` at time point `t[0]`. Optionally, `y0`
#             can also be a tuple of Tensors.
#         t: 1-D Tensor holding a sequence of time points for which to solve for
#             `y`, in either increasing or decreasing order. The first element of
#             this sequence is taken to be the initial time point.
#         rtol: optional float64 Tensor specifying an upper bound on relative error,
#             per element of `y`.
#         atol: optional float64 Tensor specifying an upper bound on absolute error,
#             per element of `y`.
#         method: optional string indicating the integration method to use.
#         options: optional dict of configuring options for the indicated integration
#             method. Can only be provided if a `method` is explicitly set.
#         event_fn: Function that maps the state `y` to a Tensor. The solve terminates when
#             event_fn evaluates to zero. If this is not None, all but the first elements of
#             `t` are ignored.
# 
#     Returns:
#         y: Tensor, where the first dimension corresponds to different
#             time points. Contains the solved value of y for each desired time point in
#             `t`, with the initial value `y0` being the first element along the first
#             dimension.
# 
#     Raises:
#         ValueError: if an invalid `method` is provided.
#     """
# 
#     shapes, func, y0, t, rtol, atol, method, options, event_fn, t_is_reversed = _check_inputs(func, y0, t, rtol, atol, method, options, event_fn, SOLVERS)
# 
#     solver = SOLVERS[method](func=func, y0=y0, rtol=rtol, atol=atol, **options)
# 
#     if event_fn is None:
#         solution = solver.integrate(t)
#     else:
#         event_t, solution = solver.integrate_until_event(t[0], event_fn)
#         event_t = event_t.to(t)
#         if t_is_reversed:
#             event_t = -event_t
# 
#     if shapes is not None:
#         solution = _flat_to_shape(solution, (len(t),), shapes)
# 
#     if event_fn is None:
#         return solution
#     else:
#         return event_t, solution


import time
import numpy as np
import torch
import detest
from scipy.stats.mstats import gmean
from torchdiffeq import odeint
        self.diffeq = diffeq
        self.nfe = 0

    def __call__(self, t, y):
        self.nfe += 1
        return self.diffeq(t, y)


def main():

    sol = dict()
    for method in ['dopri5', 'adams']:
        for tol in [1e-3, 1e-6, 1e-9]:
            print('======= {} | tol={:e} ======='.format(method, tol))
            nfes = []
            times = []
            errs = []
            for c in ['A', 'B', 'C', 'D', 'E']:
                for i in ['1', '2', '3', '4', '5']:
                    diffeq, init, _ = getattr(detest, c + i)()
                    t0, y0 = init()
                    diffeq = NFEDiffEq(diffeq)

                    if not c + i in sol:
                        sol[c + i] = odeint(
                            diffeq, y0, torch.stack([t0, torch.tensor(20.)]), atol=1e-12, rtol=1e-12, method='dopri5'
                        )[1]
                        diffeq.nfe = 0

                    start_time = time.time()

# Path: torchdiffeq/_impl/odeint.py
# def odeint(func, y0, t, *, rtol=1e-7, atol=1e-9, method=None, options=None, event_fn=None):
#     """Integrate a system of ordinary differential equations.
# 
#     Solves the initial value problem for a non-stiff system of first order ODEs:
#         ```
#         dy/dt = func(t, y), y(t[0]) = y0
#         ```
#     where y is a Tensor or tuple of Tensors of any shape.
# 
#     Output dtypes and numerical precision are based on the dtypes of the inputs `y0`.
# 
#     Args:
#         func: Function that maps a scalar Tensor `t` and a Tensor holding the state `y`
#             into a Tensor of state derivatives with respect to time. Optionally, `y`
#             can also be a tuple of Tensors.
#         y0: N-D Tensor giving starting value of `y` at time point `t[0]`. Optionally, `y0`
#             can also be a tuple of Tensors.
#         t: 1-D Tensor holding a sequence of time points for which to solve for
#             `y`, in either increasing or decreasing order. The first element of
#             this sequence is taken to be the initial time point.
#         rtol: optional float64 Tensor specifying an upper bound on relative error,
#             per element of `y`.
#         atol: optional float64 Tensor specifying an upper bound on absolute error,
#             per element of `y`.
#         method: optional string indicating the integration method to use.
#         options: optional dict of configuring options for the indicated integration
#             method. Can only be provided if a `method` is explicitly set.
#         event_fn: Function that maps the state `y` to a Tensor. The solve terminates when
#             event_fn evaluates to zero. If this is not None, all but the first elements of
#             `t` are ignored.
# 
#     Returns:
#         y: Tensor, where the first dimension corresponds to different
#             time points. Contains the solved value of y for each desired time point in
#             `t`, with the initial value `y0` being the first element along the first
#             dimension.
# 
#     Raises:
#         ValueError: if an invalid `method` is provided.
#     """
# 
#     shapes, func, y0, t, rtol, atol, method, options, event_fn, t_is_reversed = _check_inputs(func, y0, t, rtol, atol, method, options, event_fn, SOLVERS)
# 
#     solver = SOLVERS[method](func=func, y0=y0, rtol=rtol, atol=atol, **options)
# 
#     if event_fn is None:
#         solution = solver.integrate(t)
#     else:
#         event_t, solution = solver.integrate_until_event(t[0], event_fn)
#         event_t = event_t.to(t)
#         if t_is_reversed:
#             event_t = -event_t
# 
#     if shapes is not None:
#         solution = _flat_to_shape(solution, (len(t),), shapes)
# 
#     if event_fn is None:
#         return solution
#     else:
#         return event_t, solution


# Path: tests/DETEST/run.py
import time
import numpy as np
import torch
import detest
from scipy.stats.mstats import gmean
from torchdiffeq import odeint

        self.diffeq = diffeq
        self.nfe = 0

    def __call__(self, t, y):
        self.nfe += 1
        return self.diffeq(t, y)


def main():

    sol = dict()
    for method in ['dopri5', 'adams']:
        for tol in [1e-3, 1e-6, 1e-9]:
            print('======= {} | tol={:e} ======='.format(method, tol))
            nfes = []
            times = []
            errs = []
            for c in ['A', 'B', 'C', 'D', 'E']:
                for i in ['1', '2', '3', '4', '5']:
                    diffeq, init, _ = getattr(detest, c + i)()
                    t0, y0 = init()
                    diffeq = NFEDiffEq(diffeq)

                    if not c + i in sol:
                        sol[c + i] = odeint(
                            diffeq, y0, torch.stack([t0, torch.tensor(20.)]), atol=1e-12, rtol=1e-12, method='dopri5'
                        )[1]
                        diffeq.nfe = 0

                    start_time = time.time()

                    est = odeint(diffeq, y0, torch.stack([t0, torch.tensor(20.)]), atol=tol, rtol=tol, method=method)