Question: If n is even, n**2/2 should also be even The following: should return , but it returns (of course, this is also an enhancement). That makes me think that perhaps symbolic integers should keep a more complex "assumptions" method, which generalizes "iseven" and "isodd" to instead contain a dictionary of primes that are known to divide that integer, mapping to minimum and maximum known multiplicity. I would like to think about it and post a proposition/plan, but I am not sure what is the correct github way of doing this. Updated evalisodd to handle more complex inputs Changed the function evalisodd to handle integer inputs that have a denominator, such as The example expression x is recognized by SymPy as an integer, but can be decomposed into n,m,and 1/2. My new function evaluates the oddness of each part and uses this to calculate the oddness of the entire integer. Addresses issue

if not denominators:             return True         odd = lambda ints: all(i.is_odd for i in ints)        even = lambda ints: any(i.is_even for i in ints)        allodd = lambda x: all(i.is_odd for i in x)        alleven = lambda x: all(i.is_even for i in x)        anyeven = lambda x: any(i.is_even for i in x)         if odd(numerators) and even(denominators):        if allodd(numerators) and anyeven(denominators):             return False        elif even(numerators) and denominators == [2]:        elif anyeven(numerators) and denominators == [2]:             return True        elif alleven(numerators) and allodd(denominators                ) and (Mul(*denominators, evaluate=False) - 1                ).is_positive:            return False        if len(denominators) == 1:            d = denominators[0]            if d.is_Integer and d.is_even:                # if minimal power of 2 in num vs den is not                # negative then we have an integer                if (Add(*[i.as_base_exp()[1] for i in                        numerators if i.is_even]) - trailing(d.p)                        ).is_nonnegative:                    return True        if len(numerators) == 1:            n = numerators[0]            if n.is_Integer and n.is_even:                # if minimal power of 2 in den vs num is positive                # then we have have a non-integer                if (Add(*[i.as_base_exp()[1] for i in                        denominators if i.is_even]) - trailing(n.p)                        ).is_positive:                    return False      def _eval_is_polar(self):         has_polar = any(arg.is_polar for arg in self.args)


Question: If n is even, n**2/2 should also be even The following: should return , but it returns (of course, this is also an enhancement). That makes me think that perhaps symbolic integers should keep a more complex "assumptions" method, which generalizes "iseven" and "isodd" to instead contain a dictionary of primes that are known to divide that integer, mapping to minimum and maximum known multiplicity. I would like to think about it and post a proposition/plan, but I am not sure what is the correct github way of doing this. Updated evalisodd to handle more complex inputs Changed the function evalisodd to handle integer inputs that have a denominator, such as The example expression x is recognized by SymPy as an integer, but can be decomposed into n,m,and 1/2. My new function evaluates the oddness of each part and uses this to calculate the oddness of the entire integer. Addresses issue

return self._eval_pos_neg(-1)      def _eval_is_odd(self):        from sympy import trailing, fraction         is_integer = self.is_integer         if is_integer:            if self.is_zero:                return False            n, d = fraction(self)            if d.is_Integer and d.is_even:                # if minimal power of 2 in num vs den is                # positive then we have an even number                if (Add(*[i.as_base_exp()[1] for i in                        Mul.make_args(n) if i.is_even]) - trailing(d.p)                        ).is_positive:                    return False                return             r, acc = True, 1             for t in self.args:                if not t.is_integer:                    return None                elif t.is_even:                if abs(t) is S.One:                    continue                assert t.is_integer                if t.is_even:                    return False                if r is False:                    pass                elif acc != 1 and (acc + t).is_odd:                     r = False                elif t.is_integer:                    if r is False:                        pass                    elif acc != 1 and (acc + t).is_odd:                        r = False                    elif t.is_odd is None:                        r = None                elif t.is_even is None:                    r = None                 acc = t             return r        # !integer -> !odd        elif is_integer is False:            return False        return is_integer # !integer -> !odd      def _eval_is_even(self):        from sympy import trailing, fraction         is_integer = self.is_integer          if is_integer:             return fuzzy_not(self.is_odd)         elif is_integer is False:            return False        n, d = fraction(self)        if n.is_Integer and n.is_even:            # if minimal power of 2 in den vs num is not            # negative then this is not an integer and            # can't be even            if (Add(*[i.as_base_exp()[1] for i in                    Mul.make_args(d) if i.is_even]) - trailing(n.p)                    ).is_nonnegative:                return False        return is_integer      def _eval_is_composite(self):         """diff --git a/sympy/core/numbers.py b/sympy/core/numbers.py-- a/sympy/core/numbers.py++ b/sympy/core/numbers.py


Question: If n is even, n**2/2 should also be even The following: should return , but it returns (of course, this is also an enhancement). That makes me think that perhaps symbolic integers should keep a more complex "assumptions" method, which generalizes "iseven" and "isodd" to instead contain a dictionary of primes that are known to divide that integer, mapping to minimum and maximum known multiplicity. I would like to think about it and post a proposition/plan, but I am not sure what is the correct github way of doing this. Updated evalisodd to handle more complex inputs Changed the function evalisodd to handle integer inputs that have a denominator, such as The example expression x is recognized by SymPy as an integer, but can be decomposed into n,m,and 1/2. My new function evaluates the oddness of each part and uses this to calculate the oddness of the entire integer. Addresses issue

>>> r.p/r.q     0.75 <ins>    If an unevaluated Rational is desired, ``gcd=1`` can be passed and    this will keep common divisors of the numerator and denominator    from being eliminated. It is not possible, however, to leave a    negative value in the denominator.    >>> Rational(2, 4, gcd=1)    2/4    >>> Rational(2, -4, gcd=1).q    4</ins>     See Also     ========     sympy.core.sympify.sympify, sympy.simplify.simplify.nsimplify


Question: Mod function lambdify bug Description: When lambdifying any function of structure like sympy moves the multiplier into the first argument of Mod, like , WHEN we specify This is an example from Sympy online shell

from sympy.core.mul import _keep_coeff from sympy.core.symbol import Symbol from sympy.printing.str import StrPrinterfrom sympy.printing.precedence import precedencefrom sympy.printing.precedence import precedence, PRECEDENCE   class requires:


Question: Mod function lambdify bug Description: When lambdifying any function of structure like sympy moves the multiplier into the first argument of Mod, like , WHEN we specify This is an example from Sympy online shell

a = a or [S.One]         a_str = [self.parenthesize(x, prec) for x in a]        if len(a) == 1 and sign == "-":            # Unary minus does not have a SymPy class, and hence there's no            # precedence weight associated with it, Python's unary minus has            # an operator precedence between multiplication and exponentiation,            # so we use this to compute a weight.            a_str = [self.parenthesize(a[0], 0.5*(PRECEDENCE["Pow"]+PRECEDENCE["Mul"]))]        else:            a_str = [self.parenthesize(x, prec) for x in a]         b_str = [self.parenthesize(x, prec) for x in b]          # To parenthesize Pow with exp = -1 and having more than one Symboldiff --git a/sympy/printing/precedence.py b/sympy/printing/precedence.py-- a/sympy/printing/precedence.py++ b/sympy/printing/precedence.py


Question: Mod function lambdify bug Description: When lambdifying any function of structure like sympy moves the multiplier into the first argument of Mod, like , WHEN we specify This is an example from Sympy online shell

"MatAdd": PRECEDENCE["Add"],     "MatPow": PRECEDENCE["Pow"],     "MatrixSolve": PRECEDENCE["Mul"],<ins>    "Mod": PRECEDENCE["Mul"],</ins>     "TensAdd": PRECEDENCE["Add"],     # As soon as `TensMul` is a subclass of `Mul`, remove this:     "TensMul": PRECEDENCE["Mul"],


Question: parse_expr partially evaluates under sqrt with evaluate=False Python 3.8.5 (default, Jul 28 2020, 12:59:40) [GCC 9.3.0] on linux with sympy v1.7 I was expecting to get: does not seem to propagate correctly, since the used sympy functions support on their own:

_singularities = True      def doit(self, **hints):        if self.args[0].is_zero is False:        s = super().doit()        if s == self and self.args[0].is_zero is False:             return self.args[0] / Abs(self.args[0])        return self        return s      @classmethod     def eval(cls, arg):diff --git a/sympy/parsing/sympy_parser.py b/sympy/parsing/sympy_parser.py-- a/sympy/parsing/sympy_parser.py++ b/sympy/parsing/sympy_parser.py


Question: parse_expr partially evaluates under sqrt with evaluate=False Python 3.8.5 (default, Jul 28 2020, 12:59:40) [GCC 9.3.0] on linux with sympy v1.7 I was expecting to get: does not seem to propagate correctly, since the used sympy functions support on their own:

ast.BitAnd: 'And',         ast.BitXor: 'Not',     }<ins>    functions = (        'Abs', 'im', 're', 'sign', 'arg', 'conjugate',        'acos', 'acot', 'acsc', 'asec', 'asin', 'atan',        'acosh', 'acoth', 'acsch', 'asech', 'asinh', 'atanh',        'cos', 'cot', 'csc', 'sec', 'sin', 'tan',        'cosh', 'coth', 'csch', 'sech', 'sinh', 'tanh',        'exp', 'ln', 'log', 'sqrt', 'cbrt',    )</ins>      def flatten(self, args, func):         result = []


Question: parse_expr partially evaluates under sqrt with evaluate=False Python 3.8.5 (default, Jul 28 2020, 12:59:40) [GCC 9.3.0] on linux with sympy v1.7 I was expecting to get: does not seem to propagate correctly, since the used sympy functions support on their own:

return new_node         return node<ins>    def visit_Call(self, node):        new_node = self.generic_visit(node)        if isinstance(node.func, ast.Name) and node.func.id in self.functions:            new_node.keywords.append(ast.keyword(arg='evaluate', value=ast.NameConstant(value=False, ctx=ast.Load())))        return new_node</ins>


Question: maint(ci): drop testing for Python 3.6 <!-- Your title above should be a short description of what was changed. Do not include the issue number in the title. --<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact format, e.g. " (see for more information). Also, please write a comment on that issue linking back to this pull request once it is open. -- describes adopting NEP 29 which would mean dropping support for Python 3.6 now. Drop testing in CI for Python 3.6 and PyPy 3.6 <!-- Write the release notes for this release below between the BEGIN and END statements. The basic format is a bulleted list with the name of the subpackage and the release note for this PR. For example: solvers Added a new solver for logarithmic equations. functions Fixed a bug with log of integers. or if no release note(s) should be included use: NO ENTRY See for more information on how to write release notes. The bot will check your release notes automatically to see if they are formatted correctly. --<!-- BEGIN RELEASE NOTES --NO ENTRY <!-- END RELEASE NOTES --

import os  if sys.version_info < (3, 6):    sys.exit("This script requires Python 3.6 or newer")if sys.version_info < (3, 7):    sys.exit("This script requires Python 3.7 or newer")  from subprocess import run, PIPE from sympy.external.importtools import version_tuplediff --git a/bin/mailmap_update.py b/bin/mailmap_update.py-- a/bin/mailmap_update.py++ b/bin/mailmap_update.py


Question: maint(ci): drop testing for Python 3.6 <!-- Your title above should be a short description of what was changed. Do not include the issue number in the title. --<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact format, e.g. " (see for more information). Also, please write a comment on that issue linking back to this pull request once it is open. -- describes adopting NEP 29 which would mean dropping support for Python 3.6 now. Drop testing in CI for Python 3.6 and PyPy 3.6 <!-- Write the release notes for this release below between the BEGIN and END statements. The basic format is a bulleted list with the name of the subpackage and the release note for this PR. For example: solvers Added a new solver for logarithmic equations. functions Fixed a bug with log of integers. or if no release note(s) should be included use: NO ENTRY See for more information on how to write release notes. The bot will check your release notes automatically to see if they are formatted correctly. --<!-- BEGIN RELEASE NOTES --NO ENTRY <!-- END RELEASE NOTES --

import os  if sys.version_info < (3, 6):    sys.exit("This script requires Python 3.6 or newer")if sys.version_info < (3, 7):    sys.exit("This script requires Python 3.7 or newer")  from subprocess import run, PIPE from sympy.external.importtools import version_tuplediff --git a/setup.py b/setup.py-- a/setup.py++ b/setup.py


Question: maint(ci): drop testing for Python 3.6 <!-- Your title above should be a short description of what was changed. Do not include the issue number in the title. --<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact format, e.g. " (see for more information). Also, please write a comment on that issue linking back to this pull request once it is open. -- describes adopting NEP 29 which would mean dropping support for Python 3.6 now. Drop testing in CI for Python 3.6 and PyPy 3.6 <!-- Write the release notes for this release below between the BEGIN and END statements. The basic format is a bulleted list with the name of the subpackage and the release note for this PR. For example: solvers Added a new solver for logarithmic equations. functions Fixed a bug with log of integers. or if no release note(s) should be included use: NO ENTRY See for more information on how to write release notes. The bot will check your release notes automatically to see if they are formatted correctly. --<!-- BEGIN RELEASE NOTES --NO ENTRY <!-- END RELEASE NOTES --

% min_mpmath_version)         sys.exit(-1) if sys.version_info < (3, 6):    print("SymPy requires Python 3.6 or newer. Python %d.%d detected"if sys.version_info < (3, 7):    print("SymPy requires Python 3.7 or newer. Python %d.%d detected"           % sys.version_info[:2])     sys.exit(-1)


Question: maint(ci): drop testing for Python 3.6 <!-- Your title above should be a short description of what was changed. Do not include the issue number in the title. --<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact format, e.g. " (see for more information). Also, please write a comment on that issue linking back to this pull request once it is open. -- describes adopting NEP 29 which would mean dropping support for Python 3.6 now. Drop testing in CI for Python 3.6 and PyPy 3.6 <!-- Write the release notes for this release below between the BEGIN and END statements. The basic format is a bulleted list with the name of the subpackage and the release note for this PR. For example: solvers Added a new solver for logarithmic equations. functions Fixed a bug with log of integers. or if no release note(s) should be included use: NO ENTRY See for more information on how to write release notes. The bot will check your release notes automatically to see if they are formatted correctly. --<!-- BEGIN RELEASE NOTES --NO ENTRY <!-- END RELEASE NOTES --

'antlr': antlr,                     'sdist': sdist_sympy,                     },          python_requires='>=3.6',          python_requires='>=3.7',           classifiers=[             'License :: OSI Approved :: BSD License',             'Operating System :: OS Independent',


Question: maint(ci): drop testing for Python 3.6 <!-- Your title above should be a short description of what was changed. Do not include the issue number in the title. --<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact format, e.g. " (see for more information). Also, please write a comment on that issue linking back to this pull request once it is open. -- describes adopting NEP 29 which would mean dropping support for Python 3.6 now. Drop testing in CI for Python 3.6 and PyPy 3.6 <!-- Write the release notes for this release below between the BEGIN and END statements. The basic format is a bulleted list with the name of the subpackage and the release note for this PR. For example: solvers Added a new solver for logarithmic equations. functions Fixed a bug with log of integers. or if no release note(s) should be included use: NO ENTRY See for more information on how to write release notes. The bot will check your release notes automatically to see if they are formatted correctly. --<!-- BEGIN RELEASE NOTES --NO ENTRY <!-- END RELEASE NOTES --

'Topic :: Scientific/Engineering :: Mathematics',             'Topic :: Scientific/Engineering :: Physics',             'Programming Language :: Python :: 3',            'Programming Language :: Python :: 3.6',             'Programming Language :: Python :: 3.7',             'Programming Language :: Python :: 3.8',            'Programming Language :: Python :: 3.9',             'Programming Language :: Python :: 3 :: Only',             'Programming Language :: Python :: Implementation :: CPython',             'Programming Language :: Python :: Implementation :: PyPy',diff --git a/sympy/__init__.py b/sympy/__init__.py-- a/sympy/__init__.py++ b/sympy/__init__.py


Question: maint(ci): drop testing for Python 3.6 <!-- Your title above should be a short description of what was changed. Do not include the issue number in the title. --<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact format, e.g. " (see for more information). Also, please write a comment on that issue linking back to this pull request once it is open. -- describes adopting NEP 29 which would mean dropping support for Python 3.6 now. Drop testing in CI for Python 3.6 and PyPy 3.6 <!-- Write the release notes for this release below between the BEGIN and END statements. The basic format is a bulleted list with the name of the subpackage and the release note for this PR. For example: solvers Added a new solver for logarithmic equations. functions Fixed a bug with log of integers. or if no release note(s) should be included use: NO ENTRY See for more information on how to write release notes. The bot will check your release notes automatically to see if they are formatted correctly. --<!-- BEGIN RELEASE NOTES --NO ENTRY <!-- END RELEASE NOTES --

import sysif sys.version_info < (3, 6):    raise ImportError("Python version 3.6 or above is required for SymPy.")if sys.version_info < (3, 7):    raise ImportError("Python version 3.7 or above is required for SymPy.") del sys  diff --git a/sympy/core/numbers.py b/sympy/core/numbers.py-- a/sympy/core/numbers.py++ b/sympy/core/numbers.py


Question: maint(ci): drop testing for Python 3.6 <!-- Your title above should be a short description of what was changed. Do not include the issue number in the title. --<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact format, e.g. " (see for more information). Also, please write a comment on that issue linking back to this pull request once it is open. -- describes adopting NEP 29 which would mean dropping support for Python 3.6 now. Drop testing in CI for Python 3.6 and PyPy 3.6 <!-- Write the release notes for this release below between the BEGIN and END statements. The basic format is a bulleted list with the name of the subpackage and the release note for this PR. For example: solvers Added a new solver for logarithmic equations. functions Fixed a bug with log of integers. or if no release note(s) should be included use: NO ENTRY See for more information on how to write release notes. The bot will check your release notes automatically to see if they are formatted correctly. --<!-- BEGIN RELEASE NOTES --NO ENTRY <!-- END RELEASE NOTES --

if isinstance(num, str):             # Float accepts spaces as digit separators             num = num.replace(' ', '').lower()<del>            # in Py 3.6            # underscores are allowed. In anticipation of that, we ignore            # legally placed underscores            if '_' in num:                parts = num.split('_')                if not (all(parts) and                        all(parts[i][-1].isdigit()                            for i in range(0, len(parts), 2)) and                        all(parts[i][0].isdigit()                            for i in range(1, len(parts), 2))):                    # copy Py 3.6 error                    raise ValueError("could not convert string to float: '%s'" % num)                num = ''.join(parts)</del>             if num.startswith('.') and len(num) > 1:                 num = '0' + num             elif num.startswith('-.') and len(num) > 2:


Question: Argument invariance of String Currently, the class does not support argument invariance like: , but instead uses the invariance . The former should hold for any subclass, which is.

from sympy.core.relational import (Ge, Gt, Le, Lt) from sympy.core import Symbol, Tuple, Dummy from sympy.core.basic import Basicfrom sympy.core.expr import Exprfrom sympy.core.expr import Expr, Atom from sympy.core.numbers import Float, Integer, oo from sympy.core.sympify import _sympify, sympify, SympifyError from sympy.utilities.iterables import (iterable, topological_sort,


Question: Argument invariance of String Currently, the class does not support argument invariance like: , but instead uses the invariance . The former should hold for any subclass, which is.

else:             return kwargs <del></del> class BreakToken(Token):     """ Represents 'break' in C/Python ('exit' in Fortran).


Question: Argument invariance of String Currently, the class does not support argument invariance like: , but instead uses the invariance . The former should hold for any subclass, which is.

return _sympify(itr)  class String(Token):class String(Atom, Token):     """ SymPy object representing a string.      Atomic object which is not an expression (as opposed to Symbol).


Question: Argument invariance of String Currently, the class does not support argument invariance like: , but instead uses the invariance . The former should hold for any subclass, which is.

def _sympystr(self, printer, *args, **kwargs):         return self.text <ins>    def kwargs(self, exclude = (), apply = None):        return {}    #to be removed when Atom is given a suitable func    @property    def func(self):        return lambda: self</ins>  class QuotedString(String):     """ Represents a string which should be printed with quotes. """


Question: IndexError in StrPrinter for UnevaluatedMul gives if coeffisneg(n[0]): IndexError: list index out of range

e = Mul._from_args(dargs)                 d[i] = Pow(di.base, e, evaluate=False) if e - 1 else di.base             pre = []             # don't parenthesize first factor if negative            if n[0].could_extract_minus_sign():            if n and n[0].could_extract_minus_sign():                 pre = [str(n.pop(0))]            else:                pre = []             nfactors = pre + [self.parenthesize(a, prec, strict=False)                 for a in n]            if not nfactors:                nfactors = ['1']              # don't parenthesize first of denominator unless singleton             if len(d) > 1 and d[0].could_extract_minus_sign():


Question: simpify gives with evaluate(False) crashes unexpectedly with However, it works without . Both of following commands work

'warn' or 'ignore'.'''))         if any(coords[dim:]):             raise ValueError('Nonzero coordinates cannot be removed.')        if any(a.is_number and im(a) for a in coords):        if any(a.is_number and im(a).is_zero is False for a in coords):             raise ValueError('Imaginary coordinates are not permitted.')         if not all(isinstance(a, Expr) for a in coords):             raise TypeError('Coordinates must be valid SymPy expressions.')


Question: lambdifying Heaviside(Min(x, y)) not working When the original issue in , the following becomes a problem leads to Seems like there is a problem having/generating select inside of select. leads to which causes a similar error gets rid of the in the Piecewise and works. Hence, it probably makes sense to try to detect the ITE in the Piecewise and if so, rewrite it as And and/or simplify/simplify_logic. Related to While writing this issue, I figured out the solution. Will keep this to not have to explain in the PR why I did what I did...

def _print_Piecewise(self, expr):         "Piecewise function printer"        from sympy.logic.boolalg import ITE, simplify_logic        def print_cond(cond):            """ Problem having an ITE in the cond. """            if cond.has(ITE):                return self._print(simplify_logic(cond))            else:                return self._print(cond)         exprs = '[{}]'.format(','.join(self._print(arg.expr) for arg in expr.args))        conds = '[{}]'.format(','.join(self._print(arg.cond) for arg in expr.args))        conds = '[{}]'.format(','.join(print_cond(arg.cond) for arg in expr.args))         # If [default_value, True] is a (expr, cond) sequence in a Piecewise object         #     it will behave the same as passing the 'default' kwarg to select()         #     *as long as* it is the last element in expr.args.


Question: lambdifying Heaviside(Min(x, y)) not working When the original issue in , the following becomes a problem leads to Seems like there is a problem having/generating select inside of select. leads to which causes a similar error gets rid of the in the Piecewise and works. Hence, it probably makes sense to try to detect the ITE in the Piecewise and if so, rewrite it as And and/or simplify/simplify_logic. Related to While writing this issue, I figured out the solution. Will keep this to not have to explain in the PR why I did what I did...

def _print_ArrayAdd(self, expr):         return self._expand_fold_binary_op(self._module + '.add', expr.args) <ins>    def _print_NDimArray(self, expr):        if len(expr.shape) == 1:            return self._module + '.array(' + self._print(expr.args[0]) + ')'        if len(expr.shape) == 2:            return self._print(expr.tomatrix())        # Should be possible to extend to more dimensions        return CodePrinter._print_not_supported(self, expr)</ins>     _print_lowergamma = CodePrinter._print_not_supported     _print_uppergamma = CodePrinter._print_not_supported     _print_fresnelc = CodePrinter._print_not_supported


Question: cse() has strange behaviour for MatrixSymbol indexing Example: This gives the following output: and are just copies of the matrices and , respectively.

Substitutions containing any Symbol from ``ignore`` will be ignored.     """     from sympy.matrices.expressions import MatrixExpr, MatrixSymbol, MatMul, MatAdd<ins>    from sympy.matrices.expressions.matexpr import MatrixElement</ins>     from sympy.polys.rootoftools import RootOf      if opt_subs is None:


Question: cse() has strange behaviour for MatrixSymbol indexing Example: This gives the following output: and are just copies of the matrices and , respectively.

if isinstance(expr, RootOf):             return         if isinstance(expr, Basic) and (expr.is_Atom or expr.is_Order):        if isinstance(expr, Basic) and (                expr.is_Atom or                expr.is_Order or                isinstance(expr, (MatrixSymbol, MatrixElement))):             if expr.is_Symbol:                 excluded_symbols.add(expr)             return


Question: PythonCodePrinter doesn't support Min and Max We can't generate python code for the sympy function Min and Max. For example: the output is: Similar to issue , we should add following methods to PythonCodePrinter:

_known_functions = {     'Abs': 'abs',<ins>    'Min': 'min',    'Max': 'max',</ins> } _known_functions_math = {     'acos': 'acos',


Question: x not in QQ.frac_field(1/x) Again, probably it should.

return mapping.get(gen)**int(e/eg)                 if e.is_Integer and e is not S.One:                     return _rebuild(b)**int(e)<ins>            elif mapping.get(1/expr) is not None:                return 1/mapping.get(1/expr)</ins>              try:                 return domain.convert(expr)


Question: Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas

z : the distance to waist, and     w : the waist, or     z_r : the rayleigh range.<ins>    n : the refractive index of medium.</ins>      Examples     ========


Question: Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas

# subclass it. See:     # https://groups.google.com/d/topic/sympy/7XkU07NRBEs/discussion     def __new__(cls, wavelen, z, z_r=None, w=None):    def __new__(cls, wavelen, z, z_r=None, w=None, n=1):         wavelen = sympify(wavelen)         z = sympify(z)        n = sympify(n)          if z_r is not None and w is None:             z_r = sympify(z_r)         elif w is not None and z_r is None:            z_r = waist2rayleigh(sympify(w), wavelen)        else:            raise ValueError('Constructor expects exactly one named argument.')            z_r = waist2rayleigh(sympify(w), wavelen, n)        elif z_r is None and w is None:            raise ValueError('Must specify one of w and z_r.')         return Expr.__new__(cls, wavelen, z, z_r)        return Expr.__new__(cls, wavelen, z, z_r, n)      @property     def wavelen(self):


Question: Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas

def z_r(self):         return self.args[2] <ins>    @property    def n(self):        return self.args[3]</ins>     @property     def q(self):         """


Question: Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas

@property     def w(self):         """        The beam radius at `1/e^2` intensity.        The radius of the beam w(z), at any position z along the beam.        The beam radius at `1/e^2` intensity (axial value).          See Also         ========


Question: Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas

@property     def w_0(self):         """        The beam waist (minimal radius).         The minimal radius of beam at `1/e^2` intensity (peak value).          See Also         ========         w : the beam radius at `1/e^2` intensity        w : the beam radius at `1/e^2` intensity (axial value).          Examples         ========


Question: Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas

>>> p.w_0         0.00100000000000000         """        return sqrt(self.z_r/pi*self.wavelen)        return sqrt(self.z_r/(pi*self.n)*self.wavelen)      @property     def divergence(self):


Question: Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas

# Utilities ### def waist2rayleigh(w, wavelen):def waist2rayleigh(w, wavelen, n=1):     """     Calculate the rayleigh range from the waist of a gaussian beam.


Question: Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas Gaussian Optics / Refractive index not considered Dear sympy maintainers, please correct me, if I am wrong, but I fear that the beam waist in class is not correctly computed. From the source: def w0(self): """ The beam waist (minimal radius). See Also w : the beam radius at intensity Examples from import BeamParameter p = BeamParameter(530e-9, 1, w=1e-3) p.w0 0. """ return sqrt() After transmission through a surface with the refractive index changing, the Rayleigh length zr would change, while wavelength stays the same. According to this implementation, w0 changes, which is not physical. If I might help to solve this, I would be happy to contribute. However, I have not a very good understanding of sympy, and this code is interfaced of course with sympy. Best regards, Lukas

pi*w**2/wavelen     """     w, wavelen = map(sympify, (w, wavelen))    return w**2*pi/wavelen    return w**2*n*pi/wavelen   def rayleigh2waist(z_r, wavelen):


Question: decompogen doesn't like Min/Max perhaps related to and Add Min/Max support for decompogen <!-- Your title above should be a short description of what was changed. Do not include the issue number in the title. --<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact format, e.g. " (see for more information). Also, please write a comment on that issue linking back to this pull request once it is open. -- Before addition --- After addition --- <!-- Write the release notes for this release below. See for more information on how to write release notes. The bot will check your release notes automatically to see if they are formatted correctly. --<!-- BEGIN RELEASE NOTES --solvers Added / support for . <!-- END RELEASE NOTES --

from sympy.core.singleton import S from sympy.polys import Poly, decompose from sympy.utilities.misc import func_name<ins>from sympy.functions.elementary.miscellaneous import Min, Max</ins>   def decompogen(f, symbol):


Question: decompogen doesn't like Min/Max perhaps related to and Add Min/Max support for decompogen <!-- Your title above should be a short description of what was changed. Do not include the issue number in the title. --<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact format, e.g. " (see for more information). Also, please write a comment on that issue linking back to this pull request once it is open. -- Before addition --- After addition --- <!-- Write the release notes for this release below. See for more information on how to write release notes. The bot will check your release notes automatically to see if they are formatted correctly. --<!-- BEGIN RELEASE NOTES --solvers Added / support for . <!-- END RELEASE NOTES --

if symbol not in f.free_symbols:         return [f] <del>    result = []</del>      # ===== Simple Functions ===== #     if isinstance(f, (Function, Pow)):


Question: decompogen doesn't like Min/Max perhaps related to and Add Min/Max support for decompogen <!-- Your title above should be a short description of what was changed. Do not include the issue number in the title. --<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact format, e.g. " (see for more information). Also, please write a comment on that issue linking back to this pull request once it is open. -- Before addition --- After addition --- <!-- Write the release notes for this release below. See for more information on how to write release notes. The bot will check your release notes automatically to see if they are formatted correctly. --<!-- BEGIN RELEASE NOTES --solvers Added / support for . <!-- END RELEASE NOTES --

arg = f.args[0]         if arg == symbol:             return [f]        result += [f.subs(arg, symbol)] + decompogen(arg, symbol)        return result        return [f.subs(arg, symbol)] + decompogen(arg, symbol)    # ===== Min/Max Functions ===== #    if isinstance(f, (Min, Max)):        args = list(f.args)        d0 = None        for i, a in enumerate(args):            if not a.has_free(symbol):                continue            d = decompogen(a, symbol)            if len(d) == 1:                d = [symbol] + d            if d0 is None:                d0 = d[1:]            elif d[1:] != d0:                # decomposition is not the same for each arg:                # mark as having no decomposition                d = [symbol]                break            args[i] = d[0]        if d[0] == symbol:            return [f]        return [f.func(*args)] + d0      # ===== Convert to Polynomial ===== #     fp = Poly(f)


Question: decompogen doesn't like Min/Max perhaps related to and Add Min/Max support for decompogen <!-- Your title above should be a short description of what was changed. Do not include the issue number in the title. --<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact format, e.g. " (see for more information). Also, please write a comment on that issue linking back to this pull request once it is open. -- Before addition --- After addition --- <!-- Write the release notes for this release below. See for more information on how to write release notes. The bot will check your release notes automatically to see if they are formatted correctly. --<!-- BEGIN RELEASE NOTES --solvers Added / support for . <!-- END RELEASE NOTES --

if len(gens) == 1 and gens[0] != symbol:         f1 = f.subs(gens[0], symbol)         f2 = gens[0]        result += [f1] + decompogen(f2, symbol)        return result        return [f1] + decompogen(f2, symbol)      # ===== Polynomial decompose() ====== #     try:        result += decompose(f)        return result        return decompose(f)     except ValueError:         return [f]


Question: sympy.Array([]) fails, while sympy.Matrix([]) works SymPy 1.4 does not allow to construct empty Array (see code below). Is this the intended behavior?

def _parse_index(self, index):         if isinstance(index, (SYMPY_INTS, Integer)):            raise ValueError("Only a tuple index is accepted")            if index >= self._loop_size:                raise ValueError("Only a tuple index is accepted")            return index          if self._loop_size == 0:            raise ValueError("Index not valide with an empty array")            raise ValueError("Index not valid with an empty array")          if len(index) != self._rank:             raise ValueError('Wrong number of array axes')


Question: sympy.Array([]) fails, while sympy.Matrix([]) works SymPy 1.4 does not allow to construct empty Array (see code below). Is this the intended behavior?

if not isinstance(pointer, Iterable):                 return [pointer], () <ins>            if len(pointer) == 0:                return [], (0,)</ins>             result = []             elems, shapes = zip(*[f(i) for i in pointer])             if len(set(shapes)) != 1:


Question: sympy.Array([]) fails, while sympy.Matrix([]) works SymPy 1.4 does not allow to construct empty Array (see code below). Is this the intended behavior?

def _check_index_for_getitem(self, index):         if isinstance(index, (SYMPY_INTS, Integer, slice)):            index = (index, )            index = (index,)          if len(index) < self.rank():            index = tuple([i for i in index] + \                          [slice(None) for i in range(len(index), self.rank())])            index = tuple(index) + \                          tuple(slice(None) for i in range(len(index), self.rank()))          if len(index) > self.rank():             raise ValueError('Dimension of index greater than rank of array')


Question: polytopeintegrate and maxdegree Trying to build on the examples as ` works but fails: Is that the expected behavior? Why? Thanks!

from sympy.core import S, diff, Expr, Symbol from sympy.core.sympify import _sympify from sympy.geometry import Segment2D, Polygon, Point, Point2Dfrom sympy.polys.polytools import LC, gcd_list, degree_listfrom sympy.polys.polytools import LC, gcd_list, degree_list, Poly from sympy.simplify.simplify import nsimplify


Question: polytopeintegrate and maxdegree Trying to build on the examples as ` works but fails: Is that the expected behavior? Why? Thanks!

if max_degree is None:             if expr is None:                raise TypeError('Input expression be must'                                'be a valid SymPy expression')                raise TypeError('Input expression must be a valid SymPy expression')             return main_integrate3d(expr, facets, vertices, hp_params)      if max_degree is not None:         result = {}        if expr is not None:            f_expr = []            for e in expr:                _ = decompose(e)                if len(_) == 1 and not _.popitem()[0]:                    f_expr.append(e)                elif Poly(e).total_degree() <= max_degree:                    f_expr.append(e)            expr = f_expr         if not isinstance(expr, list) and expr is not None:             raise TypeError('Input polynomials must be list of expressions')


Question: polytopeintegrate and maxdegree Trying to build on the examples as ` works but fails: Is that the expected behavior? Why? Thanks!

return result      if expr is None:        raise TypeError('Input expression be must'                        'be a valid SymPy expression')        raise TypeError('Input expression must be a valid SymPy expression')      return main_integrate(expr, facets, hp_params)


Question: polytopeintegrate and maxdegree Trying to build on the examples as ` works but fails: Is that the expected behavior? Why? Thanks!

coeff = LC(monom)         return coeff, monom / coeff <ins>def _polynomial_integrate(polynomials, facets, hp_params):    dims = (x, y)    dim_length = len(dims)    integral_value = S.Zero    for deg in polynomials:        poly_contribute = S.Zero        facet_count = 0        for hp in hp_params:            value_over_boundary = integration_reduction(facets,                                                        facet_count,                                                        hp[0], hp[1],                                                        polynomials[deg],                                                        dims, deg)            poly_contribute += value_over_boundary * (hp[1] / norm(hp[0]))            facet_count += 1        poly_contribute /= (dim_length + deg)        integral_value += poly_contribute    return integral_value</ins>  def main_integrate3d(expr, facets, vertices, hp_params, max_degree=None):     """Function to translate the problem of integrating uni/bi/tri-variate


Question: polytopeintegrate and maxdegree Trying to build on the examples as ` works but fails: Is that the expected behavior? Why? Thanks!

dims = (x, y)     dim_length = len(dims)     result = {}<del>    integral_value = S.Zero</del>      if max_degree:         grad_terms = [[0, 0, 0, 0]] + gradient_terms(max_degree)


Question: polytopeintegrate and maxdegree Trying to build on the examples as ` works but fails: Is that the expected behavior? Why? Thanks!

(b / norm(a)) / (dim_length + degree)         return result     else:        polynomials = decompose(expr)        for deg in polynomials:            poly_contribute = S.Zero            facet_count = 0            for hp in hp_params:                value_over_boundary = integration_reduction(facets,                                                            facet_count,                                                            hp[0], hp[1],                                                            polynomials[deg],                                                            dims, deg)                poly_contribute += value_over_boundary * (hp[1] / norm(hp[0]))                facet_count += 1            poly_contribute /= (dim_length + deg)            integral_value += poly_contribute    return integral_value        if not isinstance(expr, list):            polynomials = decompose(expr)            return _polynomial_integrate(polynomials, facets, hp_params)        else:            return {e: _polynomial_integrate(decompose(e), facets, hp_params) for e in expr}   def polygon_integrate(facet, hp_param, index, facets, vertices, expr, degree):


Question: display bug while using pretty_print with object in the terminal The following code jumbles some of the outputs in the terminal, essentially by inserting the unit vector in the middle - Output:

if '\n' in partstr:                 tempstr = partstr                 tempstr = tempstr.replace(vectstrs[i], '')                if '\N{right parenthesis extension}' in tempstr:   # If scalar is a fraction                if '\N{RIGHT PARENTHESIS EXTENSION}' in tempstr:   # If scalar is a fraction                     for paren in range(len(tempstr)):                         flag[i] = 1                        if tempstr[paren] == '\N{right parenthesis extension}':                            tempstr = tempstr[:paren] + '\N{right parenthesis extension}'\                        if tempstr[paren] == '\N{RIGHT PARENTHESIS EXTENSION}' and tempstr[paren + 1] == '\n':                            # We want to place the vector string after all the right parentheses, because                            # otherwise, the vector will be in the middle of the string                            tempstr = tempstr[:paren] + '\N{RIGHT PARENTHESIS EXTENSION}'\                                          + ' '  + vectstrs[i] + tempstr[paren + 1:]                             break                 elif '\N{RIGHT PARENTHESIS LOWER HOOK}' in tempstr:                    flag[i] = 1                    tempstr = tempstr.replace('\N{RIGHT PARENTHESIS LOWER HOOK}',                                        '\N{RIGHT PARENTHESIS LOWER HOOK}'                                        + ' ' + vectstrs[i])                else:                    tempstr = tempstr.replace('\N{RIGHT PARENTHESIS UPPER HOOK}',                                        '\N{RIGHT PARENTHESIS UPPER HOOK}'                                        + ' ' + vectstrs[i])                    # We want to place the vector string after all the right parentheses, because                    # otherwise, the vector will be in the middle of the string. For this reason,                    # we insert the vector string at the rightmost index.                    index = tempstr.rfind('\N{RIGHT PARENTHESIS LOWER HOOK}')                    if index != -1: # then this character was found in this string                        flag[i] = 1                        tempstr = tempstr[:index] + '\N{RIGHT PARENTHESIS LOWER HOOK}'\                                     + ' '  + vectstrs[i] + tempstr[index + 1:]                 o1[i] = tempstr          o1 = [x.split('\n') for x in o1]


Question: Python code printer not respecting tuple with one element Hi, Thanks for the recent updates in SymPy! I'm trying to update my code to use SymPy 1.10 but ran into an issue with the Python code printer. MWE: SymPy 1.9 and under outputs: But SymPy 1.10 gives Note the missing comma after that causes an integer to be returned instead of a tuple. For tuples with two or more elements, the generated code is correct: In SymPy 1.10 and under, outputs: This result is expected. Not sure if this is a regression. As this breaks my program which assumes the return type to always be a tuple, could you suggest a workaround from the code generation side? Thank you.

return doprint(arg)     elif iterable(arg):         if isinstance(arg, list):            left, right = "[]"            left, right = "[", "]"         elif isinstance(arg, tuple):            left, right = "()"            left, right = "(", ",)"         else:             raise NotImplementedError("unhandled type: %s, %s" % (type(arg), arg))         return left +', '.join(_recursive_to_string(doprint, e) for e in arg) + right


Question: Dimensionless number in exponent not recognized as dimensionless in collectfactoranddimension The following raises an error: returns: Using does not raise an error here: Added fix for wrong dimension calculations in case of some mathematical functions …al functions <!-- Your title above should be a short description of what was changed. Do not include the issue number in the title. --<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact format, e.g. " (see for more information). Also, please write a comment on that issue linking back to this pull request once it is open. -- Fixed the return value for the function collectfactorand_dimension(). Previous return value led to wrong dimensional evaluation for expressions containing predefined mathematical functions. <!-- Write the release notes for this release below. See for more information on how to write release notes. The bot will check your release notes automatically to see if they are formatted correctly. --<!-- BEGIN RELEASE NOTES -- Fixed dimensional evaluation for expressions containing predefined mathematical functions. <!-- END RELEASE NOTES --

fds = [self._collect_factor_and_dimension(                 arg) for arg in expr.args]             return (expr.func(*(f[0] for f in fds)),                    expr.func(*(d[1] for d in fds)))                    *(d[1] for d in fds))         elif isinstance(expr, Dimension):             return S.One, expr         else:


Question: bug with HNF removing rows I expect to give but instead I get It seems to be falsely identifying my matrix as rank-deficient and removing the row when I try to achieve a row-style HNF using flips and transposes.

if not A.domain.is_ZZ:         raise DMDomainError('Matrix must be over domain ZZ.')     # We work one row at a time, starting from the bottom row, and working our    # way up. The total number of rows we will consider is min(m, n), where    # A is an m x n matrix.    # way up.     m, n = A.shape    rows = min(m, n)     A = A.to_dense().rep.copy()     # Our goal is to put pivot entries in the rightmost columns.     # Invariant: Before processing each row, k should be the index of the     # leftmost column in which we have so far put a pivot.     k = n    for i in range(m - 1, m - 1 - rows, -1):    for i in range(m - 1, -1, -1):        if k == 0:            # This case can arise when n < m and we've already found n pivots.            # We don't need to consider any more rows, because this is already            # the maximum possible number of pivots.            break         k -= 1         # k now points to the column in which we want to put a pivot.         # We want zeros in all entries to the left of the pivot column.


Question: Using symbols to create functions doesn't work if there is an extra layer of parentheses Sympy version == 1.10.1 Using to create symbol-like objects like instances of as shown in the creates objects of class instead of if there is an extra layer of parentheses. The extra layer of parentheses are necessary to deconstruct the output as separate tuples. Running the code: <class ''<class ''

return tuple(result)     else:         for name in names:            result.append(symbols(name, **args))            result.append(symbols(name, cls=cls, **args))          return type(names)(result)


Question: idiff should use (or better) should not use full blown to implicitly solve for a derivative which will appear in a linear fashion. would be better to use or else simply use a low-level linear solver for the calculation. The following equation takes too long to solve for : The solution can be found as

from .exceptions import GeometryError from .point import Point, Point2D, Point3D from sympy.core.containers import OrderedSetfrom sympy.core.function import Functionfrom sympy.core.exprtools import factor_termsfrom sympy.core.function import Function, expand_mul from sympy.core.sorting import ordered from sympy.core.symbol import Symbolfrom sympy.core.singleton import Sfrom sympy.polys.polytools import cancel from sympy.functions.elementary.miscellaneous import sqrtfrom sympy.solvers.solvers import solve from sympy.utilities.iterables import is_sequence


Question: idiff should use (or better) should not use full blown to implicitly solve for a derivative which will appear in a linear fashion. would be better to use or else simply use a low-level linear solver for the calculation. The following equation takes too long to solve for : The solution can be found as

eq = eq.subs(f)     derivs = {}     for i in range(n):        yp = solve(eq.diff(x), dydx)[0].subs(derivs)        # equation will be linear in dydx, a*dydx + b, so dydx = -b/a        deq = eq.diff(x)        b = deq.xreplace({dydx: S.Zero})        a = (deq - b).xreplace({dydx: S.One})        yp = factor_terms(expand_mul(cancel((-b/a).subs(derivs)), deep=False))         if i == n - 1:             return yp.subs([(v, k) for k, v in f.items()])         derivs[dydx] = yp


Question: recursion overflow even for for small As title, I am trying to run for and , but it throws a : I am not sure if this classifies as a bug, but it seems unintended especially since 10^6 is such a small number and has a "easy" factorisation (10^6 = 2^6 * 5^6).

def pow_rep_recursive(n_i, k, n_remaining, terms, p):    # Invalid arguments    if n_i <= 0 or k <= 0:        return    # No solutions may exist    if n_remaining < k:        return    if k * pow(n_i, p) < n_remaining:        return      if k == 0 and n_remaining == 0:         yield tuple(terms)    elif k == 1:        # next_term^p must equal to n_remaining        next_term, exact = integer_nthroot(n_remaining, p)        if exact and next_term <= n_i:            yield tuple(terms + [next_term])        return     else:        # TODO: Fall back to diop_DN when k = 2         if n_i >= 1 and k > 0:            yield from pow_rep_recursive(n_i - 1, k, n_remaining, terms, p)            residual = n_remaining - pow(n_i, p)            if residual >= 0:                yield from pow_rep_recursive(n_i, k - 1, residual, terms + [n_i], p)            for next_term in range(1, n_i + 1):                residual = n_remaining - pow(next_term, p)                if residual < 0:                    break                yield from pow_rep_recursive(next_term, k - 1, residual, terms + [next_term], p)   def sum_of_squares(n, k, zeros=False):


Question: () incorrectly reverses order of leading uncontracted gamma matrices The kahanesimplify() function applies such as to simplify products of gamma matrices in which contracted matrices occur. Leading gamma matrices without contractions should be unaffected, but a bug causes such leading terms to be prepended in reverse order. The bug is illustrated by the following example: The result is Both and should simplify to , but the order of and is flipped in the second case due to the bug. I found the source of the bug and it is simple to fix. In the leading matrices are removed at the beginning of the function and then inserted at the start of the product at the end of the function, and the insertion loop is just backward. I'll generate a pull request for this shortly.

# If `first_dum_pos` is not zero, it means that there are trailing free gamma     # matrices in front of `expression`, so multiply by them:    for i in range(0, first_dum_pos):        [ri.insert(0, free_pos[i]) for ri in resulting_indices]    resulting_indices = list( free_pos[0:first_dum_pos] + ri for ri in resulting_indices )      resulting_expr = S.Zero     for i in resulting_indices:


Question: returns Contains This is wrong because Contains is not a set (it's a boolean). It results in failures in other places because it doesn't have asrelational (since it isn't a set). For instance, from

isinstance(i, (Eq, Ne))])      def as_set(self):        raise NotImplementedError()        return self.args[1]


Question: SI.collectfactoranddimension() cannot properly detect that exponent is dimensionless How to reproduce:

dim /= idim**count             return factor, dim         elif isinstance(expr, Function):            fds = [self._collect_factor_and_dimension(                arg) for arg in expr.args]            return (expr.func(*(f[0] for f in fds)),                    *(d[1] for d in fds))            fds = [self._collect_factor_and_dimension(arg) for arg in expr.args]            dims = [Dimension(1) if self.get_dimension_system().is_dimensionless(d[1]) else d[1] for d in fds]            return (expr.func(*(f[0] for f in fds)), *dims)         elif isinstance(expr, Dimension):             return S.One, expr         else:


Question: Cannot parse Greek characters (and possibly others) in parsemathematica The old Mathematica parser in the package was able to parse e.g. Greek characters. Hence the following example works fine: As of SymPy v. 1.11, the function is deprecated, and is replaced by . This function, however, seems unable to handle the simple example above: This appears to be due to a bug in , which is why I have opened this issue. Thanks in advance! Cannot parse Greek characters (and possibly others) in parsemathematica The old Mathematica parser in the package was able to parse e.g. Greek characters. Hence the following example works fine: As of SymPy v. 1.11, the function is deprecated, and is replaced by . This function, however, seems unable to handle the simple example above: This appears to be due to a bug in , which is why I have opened this issue. Thanks in advance!

code_splits[i] = code_split          # Tokenize the input strings with a regular expression:        token_lists = [tokenizer.findall(i) if isinstance(i, str) else [i] for i in code_splits]        token_lists = [tokenizer.findall(i) if isinstance(i, str) and i.isascii() else [i] for i in code_splits]         tokens = [j for i in token_lists for j in i]          # Remove newlines at the beginning


Question: Bug in expand of TensorProduct + Workaround + Fix The expansion of a TensorProduct object stops incomplete if summands in the tensor product factors have (scalar) factors, e.g. This is clearly not the expected behaviour. It also effects other functions that rely on .expand(tensorproduct=True), as e.g. qapply() . Repeat .expand(tensorproduct=True) as may times as there are tensor factors, resp. until the expanded term does no longer change. This is however only reasonable in interactive session and not in algorithms. .expand relies on the method TensorProduct.evalexpandtensorproduct(). The issue arises from an inprecise check in TensorProduct.evalexpandtensorproduct() whether a recursive call is required; it fails when the creation of a TensorProduct object returns commutative (scalar) factors up front: in that case the constructor returns a Mul(cfactors, TensorProduct(..)). I thus propose the following code fix in TensorProduct.evalexpandtensorproduct() in I have marked the four lines to be / modified: The fix splits of commutative (scalar) factors from the tp returned. The TensorProduct object will be the one nc factor in nc_part (see constructor), if any. Note that the constructor will return 0 if a tensor factor is 0, so there is no guarantee that tp contains a TensorProduct object (e.g. TensorProduct(U-U, U+V).

if isinstance(args[i], Add):                 for aa in args[i].args:                     tp = TensorProduct(*args[:i] + (aa,) + args[i + 1:])                    if isinstance(tp, TensorProduct):                        tp = tp._eval_expand_tensorproduct()                    add_args.append(tp)                    c_part, nc_part = tp.args_cnc()                    # Check for TensorProduct object: is the one object in nc_part, if any:                    # (Note: any other object type to be expanded must be added here)                    if len(nc_part) == 1 and isinstance(nc_part[0], TensorProduct):                        nc_part = (nc_part[0]._eval_expand_tensorproduct(), )                    add_args.append(Mul(*c_part)*Mul(*nc_part))                 break          if add_args:


Question: collectfactorand_dimension does not detect equivalent dimensions in addition Code to reproduce: Results in:

for addend in expr.args[1:]:                 addend_factor, addend_dim = \                     self._collect_factor_and_dimension(addend)                if dim != addend_dim:                if not self.get_dimension_system().equivalent_dims(dim, addend_dim):                     raise ValueError(                         'Dimension of "{}" is {}, '                         'but it should be {}'.format(


Question: Numerical error on conversion of coulomb to statcoulomb It should be fixed as : Numerical error on conversion of coulomb to statcoulomb It should be fixed as :

cgs_gauss.set_quantity_scale_factor(maxwell, sqrt(centimeter**3*gram)/second)  # SI units expressed in CGS-gaussian units:cgs_gauss.set_quantity_scale_factor(coulomb, speed_of_light*statcoulomb/10)cgs_gauss.set_quantity_scale_factor(ampere, speed_of_light*statcoulomb/second/10)cgs_gauss.set_quantity_scale_factor(volt, speed_of_light*statvolt/10**6)cgs_gauss.set_quantity_scale_factor(coulomb, 10*speed_of_light*statcoulomb)cgs_gauss.set_quantity_scale_factor(ampere, 10*speed_of_light*statcoulomb/second)cgs_gauss.set_quantity_scale_factor(volt, 10**6/speed_of_light*statvolt) cgs_gauss.set_quantity_scale_factor(weber, 10**8*maxwell) cgs_gauss.set_quantity_scale_factor(tesla, 10**4*gauss) cgs_gauss.set_quantity_scale_factor(debye, One/10**18*statcoulomb*centimeter) cgs_gauss.set_quantity_scale_factor(oersted, sqrt(gram/centimeter)/second)cgs_gauss.set_quantity_scale_factor(ohm, 10**9/speed_of_light**2*second/centimeter)cgs_gauss.set_quantity_scale_factor(farad, One/10**9*speed_of_light**2*centimeter)cgs_gauss.set_quantity_scale_factor(henry, 10**9/speed_of_light**2/centimeter*second**2)cgs_gauss.set_quantity_scale_factor(ohm, 10**5/speed_of_light**2*second/centimeter)cgs_gauss.set_quantity_scale_factor(farad, One/10**5*speed_of_light**2*centimeter)cgs_gauss.set_quantity_scale_factor(henry, 10**5/speed_of_light**2/centimeter*second**2)  # Coulomb's constant: cgs_gauss.set_quantity_dimension(coulomb_constant, 1)


Question: Floor division with sympy.Integer gives: Argument of Integer should be of numeric type, got floor(1024/s0) gives oddly enough, it works if the lhs is a plain Python int. Floor division with sympy.Integer gives: Argument of Integer should be of numeric type, got floor(1024/s0) gives oddly enough, it works if the lhs is a plain Python int.

return NotImplemented         if isinstance(other, Integer):             return Integer(self.p // other)        return Integer(divmod(self, other)[0])        return divmod(self, other)[0]      def __rfloordiv__(self, other):         return Integer(Integer(other).p // self.p)


Question: is broken on PermutationGroups The issue is in the internal function, where it handles the case of a : When is an inverted generator, the test fails. I think the whole thing can be greatly simplified.

return GroupHomomorphism(domain, codomain, images)  def _check_homomorphism(domain, codomain, images):    if hasattr(domain, 'relators'):        rels = domain.relators    else:        gens = domain.presentation().generators        rels = domain.presentation().relators    """    Check that a given mapping of generators to images defines a homomorphism.    Parameters    ==========    domain : PermutationGroup, FpGroup, FreeGroup    codomain : PermutationGroup, FpGroup, FreeGroup    images : dict        The set of keys must be equal to domain.generators.        The values must be elements of the codomain.    """    pres = domain if hasattr(domain, 'relators') else domain.presentation()    rels = pres.relators    gens = pres.generators    symbols = [g.ext_rep[0] for g in gens]    symbols_to_domain_generators = dict(zip(symbols, domain.generators))     identity = codomain.identity      def _image(r):        if r.is_identity:            return identity        else:            w = identity            r_arr = r.array_form            i = 0            j = 0            # i is the index for r and j is for            # r_arr. r_arr[j] is the tuple (sym, p)            # where sym is the generator symbol            # and p is the power to which it is            # raised while r[i] is a generator            # (not just its symbol) or the inverse of            # a generator - hence the need for            # both indices            while i < len(r):                power = r_arr[j][1]                if isinstance(domain, PermutationGroup) and r[i] in gens:                    s = domain.generators[gens.index(r[i])]                else:                    s = r[i]                if s in images:                    w = w*images[s]**power                elif s**-1 in images:                    w = w*images[s**-1]**power                i += abs(power)                j += 1            return w        w = identity        for symbol, power in r.array_form:            g = symbols_to_domain_generators[symbol]            w *= images[g]**power        return w      for r in rels:         if isinstance(codomain, FpGroup):


Question: incorrect on "unnamed" S3 If we construct a group that's isomorphic to S3, but don't use the function to form it, then is coming up . I think the property method is fine up until the end. It ends like this: Let's talk about what's happening here. First, let be the group, given by generators . For any prime dividing the order of the group, let be the subgroup generated by the th powers of the given generators. The for-loop is saying, "If is cyclic, then for all dividing the order of the group, ," which I think is true. Fine. But the last three lines, after the for-loop, want to say the converse is also true, which it must not be, since appears to be a counterexample. The question is whether there's a good way to save this. In other words, there is always the last ditch, brute force method, where we just look through all the elements of the group for a generator: but it seems like we almost had a better method here, and it would be nice if we could patch it. I'm wondering if anyone whose group theory is not as rusty as mine might know a way. If is the subgroup of consisting of all products of th powers of elements of , it seems like the theorem we wanted might have been true with in place of ? I don't know. But it does seem like the discrepancy between and might be the issue here. In the case of presented as , is just which does have index (hence the failure), whereas and has index , and the test would not have failed.

self._is_abelian = True                 return True         for p in factors:            pgens = []            for g in self.generators:                pgens.append(g**p)            if self.index(self.subgroup(pgens)) != p:                self._is_cyclic = False                return False        if not self.is_abelian:            self._is_cyclic = False            return False         self._is_cyclic = True        self._is_abelian = True        return True        self._is_cyclic = all(            any(g**(order//p) != self.identity for g in self.generators)            for p, e in factors.items() if e > 1        )        return self._is_cyclic      @property     def is_dihedral(self):


Question: not accepting symbols The method is supposed to let you set the symbols you want to use, but, as it stands, either you pass the wrong number of symbols, and get an error message, or you pass the right number of symbols, and it ignores them, using instead:

return new_ring.from_dict(self, self.ring.domain)      def as_expr(self, *symbols):        if symbols and len(symbols) != self.ring.ngens:            raise ValueError("not enough symbols, expected %s got %s" % (self.ring.ngens, len(symbols)))        else:        if not symbols:             symbols = self.ring.symbols        elif len(symbols) != self.ring.ngens:            raise ValueError(                "Wrong number of symbols, expected %s got %s" %                (self.ring.ngens, len(symbols))            )          return expr_from_dict(self.as_expr_dict(), *symbols)


Question: Rational calc value error python 3.11, sympy 1.11.1 when calc Rational('0.5', '100'), the value is 1/; but Rational(0.5, 100) the value is 1/200, this value is the true value, and the version of sympy 1.8 is normal

q = 1             gcd = 1        Q = 1          if not isinstance(p, SYMPY_INTS):             p = Rational(p)            q *= p.q            Q *= p.q             p = p.p         else:             p = int(p)


Question: Rational calc value error python 3.11, sympy 1.11.1 when calc Rational('0.5', '100'), the value is 1/; but Rational(0.5, 100) the value is 1/200, this value is the true value, and the version of sympy 1.8 is normal

if not isinstance(q, SYMPY_INTS):             q = Rational(q)             p *= q.q            q = q.p            Q *= q.p         else:            q = int(q)            Q *= int(q)        q = Q          # p and q are now ints         if q == 0:


Question: MatMul(x.T, OneMatrix(k, 1)).diff(x) causes RecursionError The following code creates a RecursionError due to a missing array_derive registration for OneMatrix:

from sympy.matrices.expressions.hadamard import HadamardProduct from sympy.matrices.expressions.inverse import Inverse from sympy.matrices.expressions.matexpr import (MatrixExpr, MatrixSymbol)from sympy.matrices.expressions.special import Identityfrom sympy.matrices.expressions.special import Identity, OneMatrix from sympy.matrices.expressions.transpose import Transpose from sympy.combinatorics.permutations import _af_invert from sympy.matrices.expressions.applyfunc import ElementwiseApplyFunction


Question: MatMul(x.T, OneMatrix(k, 1)).diff(x) causes RecursionError The following code creates a RecursionError due to a missing array_derive registration for OneMatrix:

return ZeroArray(*(x.shape + expr.shape))  <ins>@array_derive.register(OneMatrix)def _(expr: OneMatrix, x: _ArrayExpr):    return ZeroArray(*(x.shape + expr.shape))</ins> @array_derive.register(Transpose) def _(expr: Transpose, x: Expr):     # D(A.T, A) ==> (m,n,i,j) ==> D(A_ji, A_mn) = d_mj d_ni


Question: The evaluate=False parameter to is ignored for relationals See also and This inequality evaluates even though is given: The result that should be returned is:

'exp', 'ln', 'log', 'sqrt', 'cbrt',     ) <ins>    relational_operators = {        ast.NotEq: 'Ne',        ast.Lt: 'Lt',        ast.LtE: 'Le',        ast.Gt: 'Gt',        ast.GtE: 'Ge',        ast.Eq: 'Eq'    }    def visit_Compare(self, node):        if node.ops[0].__class__ in self.relational_operators:            sympy_class = self.relational_operators[node.ops[0].__class__]            right = self.visit(node.comparators[0])            left = self.visit(node.left)            new_node = ast.Call(                func=ast.Name(id=sympy_class, ctx=ast.Load()),                args=[left, right],                keywords=[ast.keyword(arg='evaluate', value=ast.NameConstant(value=False, ctx=ast.Load()))],                starargs=None,                kwargs=None            )            return new_node        return node</ins>     def flatten(self, args, func):         result = []         for arg in args:


Question: Stats: Matrix Normal Distribution returns wrong probability density function As explained on the , the PDF of Matrix Normal Distribution is as follows: ! When initializing a matrix Normal Distribution in Sympy with simple parameters (as mentioned in the docs), the PDF you get is: Whereas the actual PDF should be: References: The difference is in the constant of the PDF and should be a simple issue to solve.

"or MatrixSymbol" % str(x))         term1 = Inverse(V)*Transpose(x - M)*Inverse(U)*(x - M)         num = exp(-Trace(term1)/S(2))        den = (2*pi)**(S(n*p)/2) * Determinant(U)**S(p)/2 * Determinant(V)**S(n)/2        den = (2*pi)**(S(n*p)/2) * Determinant(U)**(S(p)/2) * Determinant(V)**(S(n)/2)         return num/den  def MatrixNormal(symbol, location_matrix, scale_matrix_1, scale_matrix_2):


Question: Stats: Matrix Normal Distribution returns wrong probability density function As explained on the , the PDF of Matrix Normal Distribution is as follows: ! When initializing a matrix Normal Distribution in Sympy with simple parameters (as mentioned in the docs), the PDF you get is: Whereas the actual PDF should be: References: The difference is in the constant of the PDF and should be a simple issue to solve.

>>> M = MatrixNormal('M', [[1, 2]], [1], [[1, 0], [0, 1]])     >>> X = MatrixSymbol('X', 1, 2)     >>> density(M)(X).doit()    2*exp(-Trace((Matrix([    exp(-Trace((Matrix([     [-1],    [-2]]) + X.T)*(Matrix([[-1, -2]]) + X))/2)/pi    [-2]]) + X.T)*(Matrix([[-1, -2]]) + X))/2)/(2*pi)     >>> density(M)([[3, 4]]).doit()    2*exp(-4)/pi    exp(-4)/(2*pi)      References     ==========


Question: Bug with milli prefix What happened: What I expected to happen: milliW should evaluate to milli watts / mW or more generally times some unit evaluates to the number 1. I have tried this with Watts and Volts, I'm not sure what other cases this happens. I'm using sympy version 1.11.1-1 on Arch Linux with Python 3.10.9. If you cannot reproduce I would be happy to be of any assitance.

""" from sympy.core.expr import Expr from sympy.core.sympify import sympifyfrom sympy.core.singleton import S  class Prefix(Expr):     """


Question: Bug with milli prefix What happened: What I expected to happen: milliW should evaluate to milli watts / mW or more generally times some unit evaluates to the number 1. I have tried this with Watts and Volts, I'm not sure what other cases this happens. I'm using sympy version 1.11.1-1 on Arch Linux with Python 3.10.9. If you cannot reproduce I would be happy to be of any assitance.

fact = self.scale_factor * other.scale_factor         if fact == 1:            return 1        elif isinstance(other, Prefix):        if isinstance(other, Prefix):            if fact == 1:                return S.One             # simplify prefix             for p in PREFIXES:                 if PREFIXES[p].scale_factor == fact:


Question: Bug with milli prefix What happened: What I expected to happen: milliW should evaluate to milli watts / mW or more generally times some unit evaluates to the number 1. I have tried this with Watts and Volts, I'm not sure what other cases this happens. I'm using sympy version 1.11.1-1 on Arch Linux with Python 3.10.9. If you cannot reproduce I would be happy to be of any assitance.

fact = self.scale_factor / other.scale_factor          if fact == 1:            return 1            return S.One         elif isinstance(other, Prefix):             for p in PREFIXES:                 if PREFIXES[p].scale_factor == fact: