class_docstr: Specify an ordinary differential equation
  
  Due to the nature of the model (as well as included solvers), the process of ODE solution may perform slowly.  A faster alternative library based on PyMC--sunode--has implemented Adams' method and BDF (backward differentation formula).  More information about sunode is available at: https://github.com/aseyboldt/sunode.
  
  
  .. math::
      \dfrac{dy}{dt} = f(y,t,p) \quad y(t_0) = y_0
  
  Parameters
  ----------
  func : callable
      Function specifying the differential equation. Must take arguments y (n_states,), t (scalar), p (n_theta,)
  times : array
      Array of times at which to evaluate the solution of the differential equation.
  n_states : int
      Dimension of the differential equation.  For scalar differential equations, n_states=1.
      For vector valued differential equations, n_states = number of differential equations in the system.
  n_theta : int
      Number of parameters in the differential equation.
  t0 : float
      Time corresponding to the initial condition
  
  Examples
  --------
  .. code-block:: python
  
      def odefunc(y, t, p):
          #Logistic differential equation
          return p[0] * y[0] * (1 - y[0])
  
      times = np.arange(0.5, 5, 0.5)
  
      ode_model = DifferentialEquation(func=odefunc, times=times, n_states=1, n_theta=1, t0=0)
class_docstr_tok: ["Specify","an","ordinary","differential","equation","Due","to","the","nature","of","the","model","(","as","well","as","included","solvers",")",",","the","process","of","ODE","solution","may","perform","slowly",".","A","faster","alternative","library","based","on","PyMC","--","sunode","--","has","implemented","Adams","'","method","and","BDF","(","backward","differentation","formula",")",".","More","information","about","sunode","is","available","at",":","https",":","\/\/github.com\/aseyboldt\/sunode",".","..","math",":",":","\\dfrac","{","dy","}","{","dt","}","=","f","(","y",",","t",",","p",")","\\quad","y","(","t_0",")","=","y_0","Parameters","--","--","--","--","--","func",":","callable","Function","specifying","the","differential","equation",".","Must","take","arguments","y","(","n_states",",",")",",","t","(","scalar",")",",","p","(","n_theta",",",")","times",":","array","Array","of","times","at","which","to","evaluate","the","solution","of","the","differential","equation",".","n_states",":","int","Dimension","of","the","differential","equation",".","For","scalar","differential","equations",",","n_states=1",".","For","vector","valued","differential","equations",",","n_states","=","number","of","differential","equations","in","the","system",".","n_theta",":","int","Number","of","parameters","in","the","differential","equation",".","t0",":","float","Time","corresponding","to","the","initial","condition","Examples","--","--","--","--","..","code-block",":",":","python","def","odefunc","(","y",",","t",",","p",")",":","#","Logistic","differential","equation","return","p","[","0","]","*","y","[","0","]","*","(","1","-","y","[","0","]",")","times","=","np.arange","(","0.5",",","5",",","0.5",")","ode_model","=","DifferentialEquation","(","func=odefunc",",","times=times",",","n_states=1",",","n_theta=1",",","t0=0",")"]
code: def __call__(self, y0, theta, return_sens=False, **kwargs):
      if isinstance(y0, (list, tuple)) and not len(y0) == self.n_states:
          raise ShapeError(
              "Length of y0 is wrong.",
              actual=(len(y0),),
              expected=(self.n_states,),
          )
      if (
          isinstance(theta, (list, tuple))
          and not len(theta) == self.n_theta
      ):
          raise ShapeError(
              "Length of theta is wrong.",
              actual=(len(theta),),
              expected=(self.n_theta,),
          )
  
      # convert inputs to tensors (and check their types)
      y0 = pt.cast(pt.as_tensor_variable(y0), floatX)
      theta = pt.cast(pt.as_tensor_variable(theta), floatX)
      inputs = [y0, theta]
      for i, (input_val, itype) in enumerate(zip(inputs, self._itypes)):
          if not itype.is_super(input_val.type):
              raise ValueError(
                  f"Input {i} of type {input_val.type} does not have the expected type of {itype}"
              )
  
      # use default implementation to prepare symbolic outputs (via make_node)
      states, sens = super().__call__(y0, theta, **kwargs)
  
      if pytensor.config.compute_test_value != "off":
          # compute test values from input test values
          test_states, test_sens = self._simulate(
              y0=get_test_value(y0), theta=get_test_value(theta)
          )
  
          # check types of simulation result
          if not test_states.dtype == self._otypes[0].dtype:
              raise DtypeError(
                  "Simulated states have the wrong type.",
                  actual=test_states.dtype,
                  expected=self._otypes[0].dtype,
              )
          if not test_sens.dtype == self._otypes[1].dtype:
              raise DtypeError(
                  "Simulated sensitivities have the wrong type.",
                  actual=test_sens.dtype,
                  expected=self._otypes[1].dtype,
              )
  
          # check shapes of simulation result
          expected_states_shape = (self.n_times, self.n_states)
          expected_sens_shape = (self.n_times, self.n_states, self.n_p)
          if not test_states.shape == expected_states_shape:
              raise ShapeError(
                  "Simulated states have the wrong shape.",
                  test_states.shape,
                  expected_states_shape,
              )
          if not test_sens.shape == expected_sens_shape:
              raise ShapeError(
                  "Simulated sensitivities have the wrong shape.",
                  test_sens.shape,
                  expected_sens_shape,
              )
  
          # attach results as test values to the outputs
          states.tag.test_value = test_states
          sens.tag.test_value = test_sens
  
      if return_sens:
          return states, sens
      return states
  
imports: import logging
  import numpy
  import pytensor
  import pytensor.tensor
  import scipy
  from pytensor.graph.basic import Apply
  from pytensor.graph.op import Op, get_test_value
  from pytensor.tensor.type import TensorType
  from pymc.exceptions import DtypeError, ShapeError
  from pymc.ode import utils
label_desc: Use image node_id 5 for calling the DifferentialEquation obj's underlying member method code with example usage: obj.__call__(y0, theta, return_sens) and returns: states, states,  sens