code: def test_karr_convention():
      # Test the Karr product convention that we want to hold.
      # See his paper "Summation in Finite Terms" for a detailed
      # reasoning why we really want exactly this definition.
      # The convention is described for sums on page 309 and
      # essentially in section 1.4, definition 3. For products
      # we can find in analogy:
      #
      # \prod_{m <= i < n} f(i) 'has the obvious meaning'      for m < n
      # \prod_{m <= i < n} f(i) = 0                            for m = n
      # \prod_{m <= i < n} f(i) = 1 / \prod_{n <= i < m} f(i)  for m > n
      #
      # It is important to note that he defines all products with
      # the upper limit being *exclusive*.
      # In contrast, SymPy and the usual mathematical notation has:
      #
      # prod_{i = a}^b f(i) = f(a) * f(a+1) * ... * f(b-1) * f(b)
      #
      # with the upper limit *inclusive*. So translating between
      # the two we find that:
      #
      # \prod_{m <= i < n} f(i) = \prod_{i = m}^{n-1} f(i)
      #
      # where we intentionally used two different ways to typeset the
      # products and its limits.
  
      i = Symbol("i", integer=True)
      k = Symbol("k", integer=True)
      j = Symbol("j", integer=True, positive=True)
  
      # A simple example with a concrete factors and symbolic limits.
  
      # The normal product: m = k and n = k + j and therefore m < n:
      m = k
      n = k + j
  
      a = m
      b = n - 1
      S1 = Product(i**2, (i, a, b)).doit()
  
      # The reversed product: m = k + j and n = k and therefore m > n:
      m = k + j
      n = k
  
      a = m
      b = n - 1
      S2 = Product(i**2, (i, a, b)).doit()
  
      assert S1 * S2 == 1
  
      # Test the empty product: m = k and n = k and therefore m = n:
      m = k
      n = k
  
      a = m
      b = n - 1
      Sz = Product(i**2, (i, a, b)).doit()
  
      assert Sz == 1
  
      # Another example this time with an unspecified factor and
      # numeric limits. (We can not do both tests in the same example.)
      f = Function("f")
  
      # The normal product with m < n:
      m = 2
      n = 11
  
      a = m
      b = n - 1
      S1 = Product(f(i), (i, a, b)).doit()
  
      # The reversed product with m > n:
      m = 11
      n = 2
  
      a = m
      b = n - 1
      S2 = Product(f(i), (i, a, b)).doit()
  
      assert simplify(S1 * S2) == 1
  
      # Test the empty product with m = n:
      m = 5
      n = 5
  
      a = m
      b = n - 1
      Sz = Product(f(i), (i, a, b)).doit()
  
      assert Sz == 1
  
imports: from sympy.concrete.products import Product, product
  from sympy.concrete.summations import Sum
  from sympy.core.function import Derivative, Function, diff
  from sympy.core.numbers import Rational, oo, pi
  from sympy.core.singleton import S
  from sympy.core.symbol import Dummy, Symbol, symbols
  from sympy.functions.combinatorial.factorials import rf, factorial
  from sympy.functions.elementary.exponential import exp, log
  from sympy.functions.elementary.miscellaneous import sqrt
  from sympy.functions.elementary.trigonometric import cos, sin
  from sympy.functions.special.tensor_functions import KroneckerDelta
  from sympy.simplify.combsimp import combsimp
  from sympy.simplify.simplify import simplify
  from sympy.testing.pytest import raises
label_desc: Use image node_id 1 for calling a global function with example usage: test_karr_convention() without return types