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 grad(self, inputs, output_grads):
      _log.debug(f"grad w.r.t. inputs {hash(tuple(inputs))}")
  
      # fetch symbolic sensitivity output node from cache
      ihash = hash(tuple(inputs))
      if ihash in self._output_sensitivities:
          sens = self._output_sensitivities[ihash]
      else:
          _log.debug("No cached sensitivities found!")
          _, sens = self.__call__(*inputs, return_sens=True)
      ograds = output_grads[0]
  
      # for each parameter, multiply sensitivities with the output gradient and sum the result
      # sens is (n_times, n_states, n_p)
      # ograds is (n_times, n_states)
      grads = [pt.sum(sens[:, :, p] * ograds) for p in range(self.n_p)]
  
      # return separate gradient tensors for y0 and theta inputs
      result = pt.stack(grads[: self.n_states]), pt.stack(
          grads[self.n_states :]
      )
      return result
  
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 8 for calling the DifferentialEquation obj's underlying member method code with example usage: obj.grad(inputs, output_grads) and returns: result