class_docstr: A kernel that performs a generic reduction on arrays.
  
  Generate a kernel that takes a number of scalar or vector *arguments*
  (at least one vector argument), performs the *map_expr* on each entry of
  the vector argument and then the *reduce_expr* on the outcome of that.
  *neutral* serves as an initial value. *preamble* offers the possibility
  to add preprocessor directives and other code (such as helper functions)
  to be added before the actual reduction kernel code.
  
  Vectors in *map_expr* should be indexed by the variable *i*. *reduce_expr*
  uses the formal values "a" and "b" to indicate two operands of a binary
  reduction operation. If you do not specify a *map_expr*, ``in[i]`` is
  automatically assumed and treated as the only one input argument.
  
  *dtype_out* specifies the :class:`numpy.dtype` in which the reduction is
  performed and in which the result is returned. *neutral* is specified as
  float or integer formatted as string. *reduce_expr* and *map_expr* are
  specified as string formatted operations and *arguments* is specified as a
  string formatted as a C argument list. *name* specifies the name as which
  the kernel is compiled. *options* are passed unmodified to
  :meth:`pyopencl.Program.build`. *preamble* specifies a string of code that
  is inserted before the actual kernels.
  
  .. automethod:: __init__
  .. automethod:: __call__
class_docstr_tok: ["A","kernel","that","performs","a","generic","reduction","on","arrays",".","Generate","a","kernel","that","takes","a","number","of","scalar","or","vector","*","arguments","*","(","at","least","one","vector","argument",")",",","performs","the","*","map_expr","*","on","each","entry","of","the","vector","argument","and","then","the","*","reduce_expr","*","on","the","outcome","of","that",".","*","neutral","*","serves","as","an","initial","value",".","*","preamble","*","offers","the","possibility","to","add","preprocessor","directives","and","other","code","(","such","as","helper","functions",")","to","be","added","before","the","actual","reduction","kernel","code",".","Vectors","in","*","map_expr","*","should","be","indexed","by","the","variable","*","i","*",".","*","reduce_expr","*","uses","the","formal","values","``","a","''","and","``","b","''","to","indicate","two","operands","of","a","binary","reduction","operation",".","If","you","do","not","specify","a","*","map_expr","*",",","``","in","[","i","]","``","is","automatically","assumed","and","treated","as","the","only","one","input","argument",".","*","dtype_out","*","specifies","the",":","class",":","`","numpy.dtype","`","in","which","the","reduction","is","performed","and","in","which","the","result","is","returned",".","*","neutral","*","is","specified","as","float","or","integer","formatted","as","string",".","*","reduce_expr","*","and","*","map_expr","*","are","specified","as","string","formatted","operations","and","*","arguments","*","is","specified","as","a","string","formatted","as","a","C","argument","list",".","*","name","*","specifies","the","name","as","which","the","kernel","is","compiled",".","*","options","*","are","passed","unmodified","to",":","meth",":","`","pyopencl.Program.build","`",".","*","preamble","*","specifies","a","string","of","code","that","is","inserted","before","the","actual","kernels",".","..","automethod",":",":","__init__","..","automethod",":",":","__call__"]
docstr: Invoke the generated kernel.
  
  |explain-waitfor|
  
  With *out* the resulting single-entry :class:`pyopencl.array.Array` can
  be specified. Because offsets are supported one can store results
  anywhere (e.g. ``out=a[3]``).
  
  .. note::
  
      The returned :class:`pyopencl.Event` corresponds only to part of the
      execution of the reduction. It is not suitable for profiling.
  
  .. versionadded:: 2011.1
  
  .. versionchanged:: 2014.2
  
      Added *out* parameter.
  
  .. versionchanged:: 2016.2
  
      *range_* and *slice_* added.
  
  :arg range: A :class:`slice` object. Specifies the range of indices on which
      the kernel will be executed. May not be given at the same time
      as *slice*.
  :arg slice: A :class:`slice` object.
      Specifies the range of indices on which the kernel will be
      executed, relative to the first vector-like argument.
      May not be given at the same time as *range*.
  :arg return_event: a boolean flag used to return an event for the
      reduction.
  
  :return: the resulting scalar as a single-entry :class:`pyopencl.array.Array`
      if *return_event* is *False*, otherwise a tuple
      ``(scalar_array, event)``.
docstr_tok: ["Invoke","the","generated","kernel",".","|explain-waitfor|","With","*","out","*","the","resulting","single-entry",":","class",":","`","pyopencl.array.Array","`","can","be","specified",".","Because","offsets","are","supported","one","can","store","results","anywhere","(","e.g",".","``","out=a","[","3","]","``",")",".","..","note",":",":","The","returned",":","class",":","`","pyopencl.Event","`","corresponds","only","to","part","of","the","execution","of","the","reduction",".","It","is","not","suitable","for","profiling",".","..","versionadded",":",":","2011.1","..","versionchanged",":",":","2014.2","Added","*","out","*","parameter",".","..","versionchanged",":",":","2016.2","*","range_","*","and","*","slice_","*","added",".",":","arg","range",":","A",":","class",":","`","slice","`","object",".","Specifies","the","range","of","indices","on","which","the","kernel","will","be","executed",".","May","not","be","given","at","the","same","time","as","*","slice","*",".",":","arg","slice",":","A",":","class",":","`","slice","`","object",".","Specifies","the","range","of","indices","on","which","the","kernel","will","be","executed",",","relative","to","the","first","vector-like","argument",".","May","not","be","given","at","the","same","time","as","*","range","*",".",":","arg","return_event",":","a","boolean","flag","used","to","return","an","event","for","the","reduction",".",":","return",":","the","resulting","scalar","as","a","single-entry",":","class",":","`","pyopencl.array.Array","`","if","*","return_event","*","is","*","False","*",",","otherwise","a","tuple","``","(","scalar_array",",","event",")","``","."]
code: def __call__(self, *args: Any, **kwargs: Any) -> cl.Event:
      """Invoke the generated kernel.
  
      |explain-waitfor|
  
      With *out* the resulting single-entry :class:`pyopencl.array.Array` can
      be specified. Because offsets are supported one can store results
      anywhere (e.g. ``out=a[3]``).
  
      .. note::
  
          The returned :class:`pyopencl.Event` corresponds only to part of the
          execution of the reduction. It is not suitable for profiling.
  
      .. versionadded:: 2011.1
  
      .. versionchanged:: 2014.2
  
          Added *out* parameter.
  
      .. versionchanged:: 2016.2
  
          *range_* and *slice_* added.
  
      :arg range: A :class:`slice` object. Specifies the range of indices on which
          the kernel will be executed. May not be given at the same time
          as *slice*.
      :arg slice: A :class:`slice` object.
          Specifies the range of indices on which the kernel will be
          executed, relative to the first vector-like argument.
          May not be given at the same time as *range*.
      :arg return_event: a boolean flag used to return an event for the
          reduction.
  
      :return: the resulting scalar as a single-entry :class:`pyopencl.array.Array`
          if *return_event* is *False*, otherwise a tuple
          ``(scalar_array, event)``.
      """
  
      queue = kwargs.pop("queue", None)
      allocator = kwargs.pop("allocator", None)
      wait_for = kwargs.pop("wait_for", None)
      return_event = kwargs.pop("return_event", False)
      out = kwargs.pop("out", None)
  
      range_ = kwargs.pop("range", None)
      slice_ = kwargs.pop("slice", None)
  
      if kwargs:
          raise TypeError(
              "invalid keyword argument to reduction kernel"
          )
  
      if wait_for is None:
          wait_for = []
      else:
          # We'll be modifying it below.
          wait_for = list(wait_for)
  
      from pyopencl.array import empty
  
      stage_inf = self.stage_1_inf
      stage1_args = args
  
      while True:
          invocation_args = []
          vectors = []
  
          array_empty = empty
  
          from pyopencl.tools import VectorArg
  
          for arg, arg_tp in zip(args, stage_inf.arg_types):
              if isinstance(arg_tp, VectorArg):
                  array_empty = arg.__class__
                  if not arg.flags.forc:
                      raise RuntimeError(
                          f"{type(self).__name__} cannot deal with "
                          "non-contiguous arrays"
                      )
  
                  vectors.append(arg)
                  invocation_args.append(arg.base_data)
                  if arg_tp.with_offset:
                      invocation_args.append(arg.offset)
                  wait_for.extend(arg.events)
              else:
                  invocation_args.append(arg)
  
          if vectors:
              repr_vec = vectors[0]
          else:
              repr_vec = None
  
          # {{{ range/slice processing
  
          if range_ is not None:
              if slice_ is not None:
                  raise TypeError(
                      "may not specify both range and slice "
                      "keyword arguments"
                  )
  
          else:
              if slice_ is None:
                  slice_ = slice(None)
  
              if repr_vec is None:
                  raise TypeError(
                      "must have vector argument when range is not specified"
                  )
  
              range_ = slice(*slice_.indices(repr_vec.size))
  
          assert range_ is not None
  
          start = range_.start
          if start is None:
              start = 0
          if range_.step is None:
              step = 1
          else:
              step = range_.step
          sz = abs(range_.stop - start) // step
  
          # }}}
  
          if queue is not None:
              use_queue = queue
          else:
              if repr_vec is None:
                  raise TypeError(
                      "must specify queue argument when no vector argument present"
                  )
  
              use_queue = repr_vec.queue
  
          if allocator is None:
              if repr_vec is None:
                  from pyopencl.tools import DeferredAllocator
  
                  allocator = DeferredAllocator(queue.context)
              else:
                  allocator = repr_vec.allocator
  
          if sz == 0:
              result = array_empty(
                  use_queue, (), self.dtype_out, allocator=allocator
              )
              group_count = 1
              seq_count = 0
  
          elif (
              sz
              <= stage_inf.group_size
              * _SMALL_SEQ_COUNT
              * _MAX_GROUP_COUNT
          ):
              total_group_size = _SMALL_SEQ_COUNT * stage_inf.group_size
              group_count = (
                  sz + total_group_size - 1
              ) // total_group_size
              seq_count = _SMALL_SEQ_COUNT
  
          else:
              group_count = _MAX_GROUP_COUNT
              macrogroup_size = group_count * stage_inf.group_size
              seq_count = (sz + macrogroup_size - 1) // macrogroup_size
  
          size_args = [start, step, range_.stop, seq_count, sz]
  
          if group_count == 1 and out is not None:
              result = out
          elif group_count == 1:
              result = array_empty(
                  use_queue, (), self.dtype_out, allocator=allocator
              )
          else:
              result = array_empty(
                  use_queue,
                  (group_count,),
                  self.dtype_out,
                  allocator=allocator,
              )
  
          last_evt = stage_inf.kernel(
              use_queue,
              (group_count * stage_inf.group_size,),
              (stage_inf.group_size,),
              *(
                  [result.base_data, result.offset]
                  + invocation_args
                  + size_args
              ),
              wait_for=wait_for,
          )
          wait_for = [last_evt]
  
          result.add_event(last_evt)
  
          if group_count == 1:
              if return_event:
                  return result, last_evt
              else:
                  return result
          else:
              stage_inf = self.stage_2_inf
              args = (result,) + stage1_args
  
              range_ = slice_ = None
  
imports: from dataclasses import dataclass
  from typing import Any, List, Optional, Tuple, Union
  import numpy
  import pyopencl
  from pyopencl.tools import DtypedArgument, KernelTemplateBase, context_dependent_memoize, dtype_to_ctype, _process_code_for_macro
label_desc: Use image node_id 2 for calling the ReductionKernel obj's underlying member method code with example usage: obj.__call__() and returns: result,  last_evt, result