class_docstr: Superclass for Product and Sum.
  
  See Also
  ========
  
  sympy.concrete.expr_with_limits.ExprWithLimits
  sympy.concrete.products.Product
  sympy.concrete.summations.Sum
class_docstr_tok: ["Superclass","for","Product","and","Sum",".","See","Also","========","sympy.concrete.expr_with_limits.ExprWithLimits","sympy.concrete.products.Product","sympy.concrete.summations.Sum"]
docstr: Change index of a Sum or Product.
  
  Perform a linear transformation `x \mapsto a x + b` on the index variable
  `x`. For `a` the only values allowed are `\pm 1`. A new variable to be used
  after the change of index can also be specified.
  
  Explanation
  ===========
  
  ``change_index(expr, var, trafo, newvar=None)`` where ``var`` specifies the
  index variable `x` to transform. The transformation ``trafo`` must be linear
  and given in terms of ``var``. If the optional argument ``newvar`` is
  provided then ``var`` gets replaced by ``newvar`` in the final expression.
  
  Examples
  ========
  
  >>> from sympy import Sum, Product, simplify
  >>> from sympy.abc import x, y, a, b, c, d, u, v, i, j, k, l
  
  >>> S = Sum(x, (x, a, b))
  >>> S.doit()
  -a**2/2 + a/2 + b**2/2 + b/2
  
  >>> Sn = S.change_index(x, x + 1, y)
  >>> Sn
  Sum(y - 1, (y, a + 1, b + 1))
  >>> Sn.doit()
  -a**2/2 + a/2 + b**2/2 + b/2
  
  >>> Sn = S.change_index(x, -x, y)
  >>> Sn
  Sum(-y, (y, -b, -a))
  >>> Sn.doit()
  -a**2/2 + a/2 + b**2/2 + b/2
  
  >>> Sn = S.change_index(x, x+u)
  >>> Sn
  Sum(-u + x, (x, a + u, b + u))
  >>> Sn.doit()
  -a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u
  >>> simplify(Sn.doit())
  -a**2/2 + a/2 + b**2/2 + b/2
  
  >>> Sn = S.change_index(x, -x - u, y)
  >>> Sn
  Sum(-u - y, (y, -b - u, -a - u))
  >>> Sn.doit()
  -a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u
  >>> simplify(Sn.doit())
  -a**2/2 + a/2 + b**2/2 + b/2
  
  >>> P = Product(i*j**2, (i, a, b), (j, c, d))
  >>> P
  Product(i*j**2, (i, a, b), (j, c, d))
  >>> P2 = P.change_index(i, i+3, k)
  >>> P2
  Product(j**2*(k - 3), (k, a + 3, b + 3), (j, c, d))
  >>> P3 = P2.change_index(j, -j, l)
  >>> P3
  Product(l**2*(k - 3), (k, a + 3, b + 3), (l, -d, -c))
  
  When dealing with symbols only, we can make a
  general linear transformation:
  
  >>> Sn = S.change_index(x, u*x+v, y)
  >>> Sn
  Sum((-v + y)/u, (y, b*u + v, a*u + v))
  >>> Sn.doit()
  -v*(a*u - b*u + 1)/u + (a**2*u**2/2 + a*u*v + a*u/2 - b**2*u**2/2 - b*u*v + b*u/2 + v)/u
  >>> simplify(Sn.doit())
  a**2*u/2 + a/2 - b**2*u/2 + b/2
  
  However, the last result can be inconsistent with usual
  summation where the index increment is always 1. This is
  obvious as we get back the original value only for ``u``
  equal +1 or -1.
  
  See Also
  ========
  
  sympy.concrete.expr_with_intlimits.ExprWithIntLimits.index,
  reorder_limit,
  sympy.concrete.expr_with_intlimits.ExprWithIntLimits.reorder,
  sympy.concrete.summations.Sum.reverse_order,
  sympy.concrete.products.Product.reverse_order
docstr_tok: ["Change","index","of","a","Sum","or","Product",".","Perform","a","linear","transformation","`","x","\\mapsto","a","x","+","b","`","on","the","index","variable","`","x","`",".","For","`","a","`","the","only","values","allowed","are","`","\\pm","1","`",".","A","new","variable","to","be","used","after","the","change","of","index","can","also","be","specified",".","Explanation","===========","``","change_index","(","expr",",","var",",","trafo",",","newvar=None",")","``","where","``","var","``","specifies","the","index","variable","`","x","`","to","transform",".","The","transformation","``","trafo","``","must","be","linear","and","given","in","terms","of","``","var","``",".","If","the","optional","argument","``","newvar","``","is","provided","then","``","var","``","gets","replaced","by","``","newvar","``","in","the","final","expression",".","Examples","========",">",">",">","from","sympy","import","Sum",",","Product",",","simplify",">",">",">","from","sympy.abc","import","x",",","y",",","a",",","b",",","c",",","d",",","u",",","v",",","i",",","j",",","k",",","l",">",">",">","S","=","Sum","(","x",",","(","x",",","a",",","b",")",")",">",">",">","S.doit","(",")","-a","*","*","2\/2","+","a\/2","+","b","*","*","2\/2","+","b\/2",">",">",">","Sn","=","S.change_index","(","x",",","x","+","1",",","y",")",">",">",">","Sn","Sum","(","y","-","1",",","(","y",",","a","+","1",",","b","+","1",")",")",">",">",">","Sn.doit","(",")","-a","*","*","2\/2","+","a\/2","+","b","*","*","2\/2","+","b\/2",">",">",">","Sn","=","S.change_index","(","x",",","-x",",","y",")",">",">",">","Sn","Sum","(","-y",",","(","y",",","-b",",","-a",")",")",">",">",">","Sn.doit","(",")","-a","*","*","2\/2","+","a\/2","+","b","*","*","2\/2","+","b\/2",">",">",">","Sn","=","S.change_index","(","x",",","x+u",")",">",">",">","Sn","Sum","(","-u","+","x",",","(","x",",","a","+","u",",","b","+","u",")",")",">",">",">","Sn.doit","(",")","-a","*","*","2\/2","-","a","*","u","+","a\/2","+","b","*","*","2\/2","+","b","*","u","+","b\/2","-","u","*","(","-a","+","b","+","1",")","+","u",">",">",">","simplify","(","Sn.doit","(",")",")","-a","*","*","2\/2","+","a\/2","+","b","*","*","2\/2","+","b\/2",">",">",">","Sn","=","S.change_index","(","x",",","-x","-","u",",","y",")",">",">",">","Sn","Sum","(","-u","-","y",",","(","y",",","-b","-","u",",","-a","-","u",")",")",">",">",">","Sn.doit","(",")","-a","*","*","2\/2","-","a","*","u","+","a\/2","+","b","*","*","2\/2","+","b","*","u","+","b\/2","-","u","*","(","-a","+","b","+","1",")","+","u",">",">",">","simplify","(","Sn.doit","(",")",")","-a","*","*","2\/2","+","a\/2","+","b","*","*","2\/2","+","b\/2",">",">",">","P","=","Product","(","i","*","j","*","*","2",",","(","i",",","a",",","b",")",",","(","j",",","c",",","d",")",")",">",">",">","P","Product","(","i","*","j","*","*","2",",","(","i",",","a",",","b",")",",","(","j",",","c",",","d",")",")",">",">",">","P2","=","P.change_index","(","i",",","i+3",",","k",")",">",">",">","P2","Product","(","j","*","*","2","*","(","k","-","3",")",",","(","k",",","a","+","3",",","b","+","3",")",",","(","j",",","c",",","d",")",")",">",">",">","P3","=","P2.change_index","(","j",",","-j",",","l",")",">",">",">","P3","Product","(","l","*","*","2","*","(","k","-","3",")",",","(","k",",","a","+","3",",","b","+","3",")",",","(","l",",","-d",",","-c",")",")","When","dealing","with","symbols","only",",","we","can","make","a","general","linear","transformation",":",">",">",">","Sn","=","S.change_index","(","x",",","u","*","x+v",",","y",")",">",">",">","Sn","Sum","(","(","-v","+","y",")","\/u",",","(","y",",","b","*","u","+","v",",","a","*","u","+","v",")",")",">",">",">","Sn.doit","(",")","-v","*","(","a","*","u","-","b","*","u","+","1",")","\/u","+","(","a","*","*","2","*","u","*","*","2\/2","+","a","*","u","*","v","+","a","*","u\/2","-","b","*","*","2","*","u","*","*","2\/2","-","b","*","u","*","v","+","b","*","u\/2","+","v",")","\/u",">",">",">","simplify","(","Sn.doit","(",")",")","a","*","*","2","*","u\/2","+","a\/2","-","b","*","*","2","*","u\/2","+","b\/2","However",",","the","last","result","can","be","inconsistent","with","usual","summation","where","the","index","increment","is","always","1",".","This","is","obvious","as","we","get","back","the","original","value","only","for","``","u","``","equal","+1","or","-1",".","See","Also","========","sympy.concrete.expr_with_intlimits.ExprWithIntLimits.index",",","reorder_limit",",","sympy.concrete.expr_with_intlimits.ExprWithIntLimits.reorder",",","sympy.concrete.summations.Sum.reverse_order",",","sympy.concrete.products.Product.reverse_order"]
code: def change_index(self, var, trafo, newvar=None):
      r"""
      Change index of a Sum or Product.
  
      Perform a linear transformation `x \mapsto a x + b` on the index variable
      `x`. For `a` the only values allowed are `\pm 1`. A new variable to be used
      after the change of index can also be specified.
  
      Explanation
      ===========
  
      ``change_index(expr, var, trafo, newvar=None)`` where ``var`` specifies the
      index variable `x` to transform. The transformation ``trafo`` must be linear
      and given in terms of ``var``. If the optional argument ``newvar`` is
      provided then ``var`` gets replaced by ``newvar`` in the final expression.
  
      Examples
      ========
  
      >>> from sympy import Sum, Product, simplify
      >>> from sympy.abc import x, y, a, b, c, d, u, v, i, j, k, l
  
      >>> S = Sum(x, (x, a, b))
      >>> S.doit()
      -a**2/2 + a/2 + b**2/2 + b/2
  
      >>> Sn = S.change_index(x, x + 1, y)
      >>> Sn
      Sum(y - 1, (y, a + 1, b + 1))
      >>> Sn.doit()
      -a**2/2 + a/2 + b**2/2 + b/2
  
      >>> Sn = S.change_index(x, -x, y)
      >>> Sn
      Sum(-y, (y, -b, -a))
      >>> Sn.doit()
      -a**2/2 + a/2 + b**2/2 + b/2
  
      >>> Sn = S.change_index(x, x+u)
      >>> Sn
      Sum(-u + x, (x, a + u, b + u))
      >>> Sn.doit()
      -a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u
      >>> simplify(Sn.doit())
      -a**2/2 + a/2 + b**2/2 + b/2
  
      >>> Sn = S.change_index(x, -x - u, y)
      >>> Sn
      Sum(-u - y, (y, -b - u, -a - u))
      >>> Sn.doit()
      -a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u
      >>> simplify(Sn.doit())
      -a**2/2 + a/2 + b**2/2 + b/2
  
      >>> P = Product(i*j**2, (i, a, b), (j, c, d))
      >>> P
      Product(i*j**2, (i, a, b), (j, c, d))
      >>> P2 = P.change_index(i, i+3, k)
      >>> P2
      Product(j**2*(k - 3), (k, a + 3, b + 3), (j, c, d))
      >>> P3 = P2.change_index(j, -j, l)
      >>> P3
      Product(l**2*(k - 3), (k, a + 3, b + 3), (l, -d, -c))
  
      When dealing with symbols only, we can make a
      general linear transformation:
  
      >>> Sn = S.change_index(x, u*x+v, y)
      >>> Sn
      Sum((-v + y)/u, (y, b*u + v, a*u + v))
      >>> Sn.doit()
      -v*(a*u - b*u + 1)/u + (a**2*u**2/2 + a*u*v + a*u/2 - b**2*u**2/2 - b*u*v + b*u/2 + v)/u
      >>> simplify(Sn.doit())
      a**2*u/2 + a/2 - b**2*u/2 + b/2
  
      However, the last result can be inconsistent with usual
      summation where the index increment is always 1. This is
      obvious as we get back the original value only for ``u``
      equal +1 or -1.
  
      See Also
      ========
  
      sympy.concrete.expr_with_intlimits.ExprWithIntLimits.index,
      reorder_limit,
      sympy.concrete.expr_with_intlimits.ExprWithIntLimits.reorder,
      sympy.concrete.summations.Sum.reverse_order,
      sympy.concrete.products.Product.reverse_order
      """
      if newvar is None:
          newvar = var
  
      limits = []
      for limit in self.limits:
          if limit[0] == var:
              p = trafo.as_poly(var)
              if p.degree() != 1:
                  raise ValueError("Index transformation is not linear")
              alpha = p.coeff_monomial(var)
              beta = p.coeff_monomial(S.One)
              if alpha.is_number:
                  if alpha == S.One:
                      limits.append(
                          (
                              newvar,
                              alpha * limit[1] + beta,
                              alpha * limit[2] + beta,
                          )
                      )
                  elif alpha == S.NegativeOne:
                      limits.append(
                          (
                              newvar,
                              alpha * limit[2] + beta,
                              alpha * limit[1] + beta,
                          )
                      )
                  else:
                      raise ValueError(
                          "Linear transformation results in non-linear summation stepsize"
                      )
              else:
                  # Note that the case of alpha being symbolic can give issues if alpha < 0.
                  limits.append(
                      (
                          newvar,
                          alpha * limit[2] + beta,
                          alpha * limit[1] + beta,
                      )
                  )
          else:
              limits.append(limit)
  
      function = self.function.subs(var, (var - beta) / alpha)
      function = function.subs(var, newvar)
  
      return self.func(function, *limits)
  
file_path: sympy/sympy/concrete/expr_with_intlimits.py
imports: from sympy.concrete.expr_with_limits import ExprWithLimits
  from sympy.core.singleton import S
  from sympy.core.relational import Eq
label_desc: Use image node_id 1 for calling the ExprWithIntLimits obj's underlying member method code with example usage: obj.change_index(var, trafo, newvar) and returns: self