ronantakizawa/codereview-bench huggingface dataset:
Repository: sympy/sympy
File: sympy/core/sympify.py (Python)

Code before:
            break
        except TypeError:  # the kern might cause unknown errors...
            if hit:
                s = olds  # maybe it didn't like the kern; use un-kerned s
                hit = False
                continue
            expr = sympify(s)  # let original error raise

    if not hit:
        return expr

    from .symbol import Symbol
    rep = {Symbol(kern): 1}
    def _clear(expr):
        if isinstance(expr, (list, tuple, set)):
            return type(expr)([_clear(e) for e in expr])
        if hasattr(expr, 'subs'):
            return expr.subs(rep, hack2=True)
        return expr
    expr = _clear(expr)
    # hope that kern is not there anymore
    return expr


# Avoid circular import
from .basic import Basic


Review comment (suggestion):
The only noqa I had to add because it overwrites sympy.core.Basic above that is used in a TYPE_CHECKING block. We want it here for side effect importing most likely. Everything else is an automated edit and all tests pass

Code after:
            break
        except TypeError:  # the kern might cause unknown errors...
            if hit:
                s = olds  # maybe it didn't like the kern; use un-kerned s
                hit = False
                continue
            expr = sympify(s)  # let original error raise

    if not hit:
        return expr

    from .symbol import Symbol
    rep = {Symbol(kern): 1}
    def _clear(expr):
        if isinstance(expr, (list, tuple, set)):
            return type(expr)([_clear(e) for e in expr])
        if hasattr(expr, 'subs'):
            return expr.subs(rep, hack2=True)
        return expr
    expr = _clear(expr)
    # hope that kern is not there anymore
    return expr


# Avoid circular import
from .basic import Basic  # noqa: TC001
Repository: sympy/sympy
File: sympy/strategies/core.py (Python)

Code before:
""" Generic SymPy-Independent Strategies """
from __future__ import annotations
from collections.abc import Callable, Mapping
from typing import TypeVar
from sys import stdout


_S = TypeVar('_S')
_T = TypeVar('_T')


def identity(x: _T) -> _T:
    return x


def exhaust(rule: Callable[[_T], _T]) -> Callable[[_T], _T]:
    """ Apply a rule repeatedly until it has no effect """
    def exhaustive_rl(expr: _T) -> _T:
        new, old = rule(expr), expr
        while new != old:
            new, old = rule(new), new
        return new
    return exhaustive_rl


def memoize(rule: Callable[[_S], _T]) -> Callable[[_S], _T]:
    """Memoized version of a rule

    Notes
    =====

    This cache can grow infinitely, so it is not recommended to use this

Review comment (suggestion):
If you want you can relax these rules to slightly to allow unused stdlib rule to allow it live happily outside of TYPE_CHECKING blocks because the marginal diff is pretty rare since in large codebases some dependency might import them anyway.

This is the most aggressive management for all 1st party and third party imports.

Code after:
""" Generic SymPy-Independent Strategies """
from __future__ import annotations
from typing import TypeVar, TYPE_CHECKING
from sys import stdout

if TYPE_CHECKING:
    from collections.abc import Callable, Mapping


_S = TypeVar('_S')
_T = TypeVar('_T')


def identity(x: _T) -> _T:
    return x


def exhaust(rule: Callable[[_T], _T]) -> Callable[[_T], _T]:
    """ Apply a rule repeatedly until it has no effect """
    def exhaustive_rl(expr: _T) -> _T:
        new, old = rule(expr), expr
        while new != old:
            new, old = rule(new), new
        return new
    return exhaustive_rl


def memoize(rule: Callable[[_S], _T]) -> Callable[[_S], _T]:
    """Memoized version of a rule

    Notes
    =====
Repository: sympy/sympy
File: sympy/utilities/magic.py (Python)

Code before:
"""Functions that involve magic. """

def pollute(names: list[str], objects: list[object]) -> None:
    """Pollute the global namespace with symbols -> objects mapping. """
    from inspect import currentframe
    frame = currentframe().f_back.f_back    # type: ignore

    try:
        for name, obj in zip(names, objects):
            frame.f_globals[name] = obj     # type: ignore
    finally:
        del frame  # break cyclic dependencies as stated in inspect docs


Review comment (suggestion):
Rather than using `type: ignore` it would be better to check for `None` explicitly e.g.:
```python
    frame = currentframe()
    frame = (frame.f_back if frame is not None else None)
    frame = (frame.f_back if frame is not None else None)
    if frame is None:
        raise RuntimeError("This Python implementation does not support set._get_frame().")
```

Code after:
"""Functions that involve magic. """

def pollute(names: list[str], objects: list[object]) -> None:
    """Pollute the global namespace with symbols -> objects mapping. """
    from inspect import currentframe
    frame = currentframe()

    # Go back two frames to find the caller
    frame = frame.f_back if frame is not None else None
    frame = frame.f_back if frame is not None else None

    if frame is None:
        raise RuntimeError("Unable to get stack frame.")

    try:
        for name, obj in zip(names, objects):
            frame.f_globals[name] = obj
    finally:
        del frame  # break cyclic dependencies as stated in inspect docs
Repository: sympy/sympy
File: sympy/calculus/singularities.py (Python)

Code before:
"""
Singularities
=============

This module implements algorithms for finding singularities for a function
and identifying types of functions.

The differential calculus methods in this module include methods to identify
the following function types in the given ``Interval``:
- Increasing
- Strictly Increasing
- Decreasing
- Strictly Decreasing
- Monotonic

"""
from __future__ import annotations
from typing import Set,Callable
from sympy.core.expr import Expr
from sympy.sets.sets import Interval
from sympy.core.basic import Basic
from sympy.core.power import Pow
from sympy.core.singleton import S
from sympy.core.symbol import Symbol
from sympy.core.sympify import sympify
from sympy.functions.elementary.exponential import log
from sympy.functions.elementary.trigonometric import sec, csc, cot, tan, cos
from sympy.functions.elementary.hyperbolic import (
    sech, csch, coth, tanh, cosh, asech, acsch, atanh, acoth)
from sympy.utilities.misc import filldedent


def singularities(expression: Expr, symbol: Symbol|Basic, domain: Interval|None =None) -> Set[Symbol]:
    """
    Find singularities of a given function.

    Parameters
    ==========

    expression : Expr
        The target function in which singularities need to be found.
    symbol : Symbol
        The symbol over the values of which the singularity in
        expression in being searched for.

    Returns

Review comment (suggestion):
There should be a space after the comma. Please see PEP 8:
https://peps.python.org/pep-0008/

There are similar spacing issues in other places.

It is not necessary to use `typing.Set` because `set` can be used.

Typing only imports should go in an `if TYPE_CHECKING` block.

Code after:
"""
Singularities
=============

This module implements algorithms for finding singularities for a function
and identifying types of functions.

The differential calculus methods in this module include methods to identify
the following function types in the given ``Interval``:
- Increasing
- Strictly Increasing
- Decreasing
- Strictly Decreasing
- Monotonic

"""

from __future__ import annotations

from typing import TYPE_CHECKING

from sympy.core.power import Pow
from sympy.core.singleton import S
from sympy.core.symbol import Symbol
from sympy.core.sympify import sympify
from sympy.functions.elementary.exponential import log
from sympy.functions.elementary.trigonometric import sec, csc, cot, tan, cos
from sympy.functions.elementary.hyperbolic import (
    sech, csch, coth, tanh, cosh, asech, acsch, atanh, acoth)
from sympy.utilities.misc import filldedent


if TYPE_CHECKING:
    from typing import Callable
    from sympy.core.expr import Expr
    from sympy.sets.sets import Set
    from sympy.core.basic import Basic
    from sympy.logic.boolalg import Boolean


def singularities(
    expression: Expr | complex,
    symbol: Symbol | Basic,
    domain: Set | None = None,
) -> set[Symbol]:
    """
Repository: sympy/sympy
File: sympy/matrices/decompositions.py (Python)

Code before:
        S = S.diag(*Singular_vals)
        U, _ = U.QRdecomposition()
        V = AH * U * S.inv()

    return U, S, V

def _QRdecomposition_optional(M, normalize=True):
    def dot(u, v):
        return u.dot(v, hermitian=True)

    dps = _get_intermediate_simp(expand_mul, expand_mul)

    A = M.as_mutable()
    ranked = []

    Q = A
    R = A.zeros(A.cols)

    for j in range(A.cols):
        for i in range(j):
            if Q[:, i].is_zero_matrix:
                continue

            R[i, j] = dot(Q[:, i], Q[:, j]) / dot(Q[:, i], Q[:, i])
            R[i, j] = dps(R[i, j])
            Q[:, j] -= Q[:, i] * R[i, j]

        Q[:, j] = dps(Q[:, j])
        if Q[:, j].is_zero_matrix is not True:
            ranked.append(j)
            R[j, j] = M.one

    Q = Q.extract(range(Q.rows), ranked)
    R = R.extract(ranked, range(R.cols))

    if normalize:
        # Normalization
        for i in range(Q.cols):
            norm = Q[:, i].norm()
            Q[:, i] /= norm
            R[i, :] *= norm

    return M.__class__(Q), M.__class__(R)


def _QRdecomposition(M):
    r"""Returns a QR decomposition.

    Explanation
    ===========


Review comment (performance):
The `.equals` function can be very expensive. The zero equivalence problem can be difficult in general.

Code after:
        S = S.diag(*Singular_vals)
        U, _ = U.QRdecomposition()
        V = AH * U * S.inv()

    return U, S, V

def _QRdecomposition_optional(M, normalize=True):
    def dot(u, v):
        return u.dot(v, hermitian=True)

    dps = _get_intermediate_simp(expand_mul, expand_mul)

    A = M.as_mutable()
    ranked = []

    Q = A
    R = A.zeros(A.cols)

    for j in range(A.cols):
        for i in range(j):
            z = Q[:, i].is_zero_matrix
            if z is True:
                continue

            norm = dps(dot(Q[:, i], Q[:, i]))
            if z is None and norm.equals(0):
                continue

            R[i, j] = dot(Q[:, i], Q[:, j]) / norm
            R[i, j] = dps(R[i, j])
            Q[:, j] -= Q[:, i] * R[i, j]

        Q[:, j] = dps(Q[:, j])
        z = Q[:, j].is_zero_matrix
        if z is True or dps(dot(Q[:, j], Q[:, j])).equals(0):
            continue
        ranked.append(j)
        R[j, j] = M.one

    Q = Q.extract(range(Q.rows), ranked)
    R = R.extract(ranked, range(R.cols))

    if normalize:
        # Normalization
        for i in range(Q.cols):
            norm = Q[:, i].norm()
            Q[:, i] /= norm
            R[i, :] *= norm

    return M.__class__(Q), M.__class__(R)
Repository: sympy/sympy
File: sympy/polys/polytools.py (Python)

Code before:
        else:  # pragma: no cover
            raise OperationNotSupported(f, 'decompose')

        return list(map(f.per, result))

    def shift(f: Poly, a: Expr) -> Poly:
        """
        Efficiently compute Taylor shift ``f(x + a)``.

        Examples
        ========

        >>> from sympy import Poly
        >>> from sympy.abc import x

        >>> Poly(x**2 - 2*x + 1, x).shift(2)
        Poly(x**2 + 2*x + 1, x, domain='ZZ')

        See Also
        ========

        shift_list: Analogous method for multivariate polynomials.
        """
        return f.per(f.rep.shift(a))

    def shift_list(f: Poly, a) -> Poly:
        """
        Efficiently compute Taylor shift ``f(X + A)``.

        Examples
        ========

        >>> from sympy import Poly
        >>> from sympy.abc import x, y

        >>> Poly(x*y, [x,y]).shift_list([1, 2]) == Poly((x+1)*(y+2), [x,y])
        True

        See Also
        ========

        shift: Analogous method for univariate polynomials.
        """
        return f.per(f.rep.shift_list(a))

    def transform(f: Poly, p: Poly, q: Poly) -> Poly:

        """
        Efficiently evaluate the functional transformation ``q**n * f(p/q)``.



Review comment (suggestion):
We don't need annotations for `f` but `a` should have an annotation.

Code after:
        else:  # pragma: no cover
            raise OperationNotSupported(f, 'decompose')

        return list(map(f.per, result))

    def shift(f, a: Expr) -> Poly:
        """
        Efficiently compute Taylor shift ``f(x + a)``.

        Examples
        ========

        >>> from sympy import Poly
        >>> from sympy.abc import x

        >>> Poly(x**2 - 2*x + 1, x).shift(2)
        Poly(x**2 + 2*x + 1, x, domain='ZZ')

        See Also
        ========

        shift_list: Analogous method for multivariate polynomials.
        """
        return f.per(f.rep.shift(a))

    def shift_list(f, a: list[Expr]) -> Poly:
        """
        Efficiently compute Taylor shift ``f(X + A)``.

        Examples
        ========

        >>> from sympy import Poly
        >>> from sympy.abc import x, y

        >>> Poly(x*y, [x,y]).shift_list([1, 2]) == Poly((x+1)*(y+2), [x,y])
        True

        See Also
        ========

        shift: Analogous method for univariate polynomials.
        """
        return f.per(f.rep.shift_list(a))

    def transform(f, p: Poly, q: Poly) -> Poly:

        """
        Efficiently evaluate the functional transformation ``q**n * f(p/q)``.
Repository: sympy/sympy
File: sympy/polys/polytools.py (Python)

Code before:
        opt.polys = bool(_polys)

    return polys, opt


def _update_args(args, key, value):
    """Add a new ``(key, value)`` pair to arguments ``dict``. """
    args = dict(args)

    if key not in args:
        args[key] = value

    return args


@public
def degree(f, gen=0):
    """
    Return the degree of ``f`` in the given variable.
    When ``f`` is a univariate polynomial, it is not
    necessary to pass a generator, but if the generator
    is given as an int it refers to the gen-th generator
    of the expression which must be passed as a Poly
    instance.

    The degree of 0 with respect to any variable is ``-oo``.

    Examples
    ========

    >>> from sympy import degree
    >>> from sympy.abc import x, y

    >>> degree(x**2)
    2
    >>> degree(x**2 + y*x + 1, gen=x)
    2
    >>> degree(x**2 + y*x + 1, gen=y)
    1
    >>> degree(0, x)
    -oo

    See also
    ========

    sympy.polys.polytools.Poly.total_degree
    degree_list
    """

    _degree = lambda x: Integer(x) if type(x) is int else x


Review comment (suggestion):
```suggestion
    The degree of 0 with respect to any variable is ``-oo``; if ``f``
    is a numerical expression equal to 0, but not identically 0,
    zero may be returned instead (because the variable does not appear).
```

Code after:
        opt.polys = bool(_polys)

    return polys, opt


def _update_args(args, key, value):
    """Add a new ``(key, value)`` pair to arguments ``dict``. """
    args = dict(args)

    if key not in args:
        args[key] = value

    return args


@public
def degree(f, gen=0):
    """
    Return the degree of ``f`` in the given variable.
    When ``f`` is a univariate polynomial, it is not
    necessary to pass a generator, but if the generator
    is given as an int it refers to the gen-th generator
    of the expression which must be passed as a Poly
    instance.

    The degree of 0 with respect to any variable is ``-oo``; if ``f``
    is a numerical expression equal to 0, but not identically 0,
    zero may be returned instead (because the variable does not appear).

    Examples
    ========

    >>> from sympy import degree
    >>> from sympy.abc import x, y

    >>> degree(x**2)
    2
    >>> degree(x**2 + y*x + 1, gen=x)
    2
    >>> degree(x**2 + y*x + 1, gen=y)
    1
    >>> degree(0, x)
    -oo

    In contrast to the strict Poly method, if the specified generator is
    not in Poly's generators, the Poly instance is recast in terms of the
    generator instead of raising an error.

    >>> from sympy import Poly
    >>> p = Poly(x + y, x)
    >>> p.degree(y)
Repository: sympy/sympy
File: sympy/polys/polytools.py (Python)

Code before:

    Examples
    ========

    >>> from sympy import degree
    >>> from sympy.abc import x, y

    >>> degree(x**2)
    2
    >>> degree(x**2 + y*x + 1, gen=x)
    2
    >>> degree(x**2 + y*x + 1, gen=y)
    1
    >>> degree(0, x)
    -oo

    In contrast to the strict Poly method, if the specified generator is
    not in Poly's generators, the Poly instance is recast in terms of the
    generator instead of raising an error.

    >>> from sympy import Poly
    >>> p = Poly(x + y, x)
    >>> p.degree(y)
    Exception raised:
    ...
    PolynomialError: a valid generator expected, got y
    >>> degree(p, y)
    1

    See also
    ========

    sympy.polys.polytools.Poly.total_degree
    degree_list
    """

    _degree = lambda x: Integer(x) if type(x) is int else x

    f = sympify(f, strict=True)
    if type(gen) is int:
        if isinstance(f, Poly):
            return _degree(f.degree(gen))
        if f.is_Number:
            return S.NegativeInfinity if f.is_zero else S.Zero
        p = Poly(f, expand=False)
        gens = p.gens
        free = f.free_symbols
        if not (gen == 0 and len(gens) == 1 and len(free) < 2 and f.is_polynomial(
                gen := next(iter(gens))) and # <-- assigns gen
                gen.is_Atom):  # e.g. x or pi
            raise TypeError(filldedent('''

Review comment (suggestion):
```suggestion
    sympy.polys.polyerrors.PolynomialError: a valid generator expected, got y
```

Code after:

    Examples
    ========

    >>> from sympy import degree
    >>> from sympy.abc import x, y

    >>> degree(x**2)
    2
    >>> degree(x**2 + y*x + 1, gen=x)
    2
    >>> degree(x**2 + y*x + 1, gen=y)
    1
    >>> degree(0, x)
    -oo

    In contrast to the strict Poly method, if the specified generator is
    not in Poly's generators, the Poly instance is recast in terms of the
    generator instead of raising an error.

    >>> from sympy import Poly
    >>> p = Poly(x + y, x)
    >>> p.degree(y)
    Traceback (most recent call last):
    ...
    PolynomialError: a valid generator expected, got y

    >>> degree(p, y)
    1

    See also
    ========

    sympy.polys.polytools.Poly.total_degree
    degree_list
    """

    _degree = lambda x: Integer(x) if type(x) is int else x

    f = sympify(f, strict=True)
    if type(gen) is int:
        if isinstance(f, Poly):
            return _degree(f.degree(gen))
        if f.is_Number:
            return S.NegativeInfinity if f.is_zero else S.Zero
        try:
            p = Poly(f, expand=False)
        except GeneratorsNeeded:  # e.g. f = (1+I)**2/2
            gens = ()  # do not guess what the user intended
        else:
            gens = p.gens
Repository: sympy/sympy
File: sympy/polys/polytools.py (Python)

Code before:
    ========

    >>> from sympy import degree
    >>> from sympy.abc import x, y

    >>> degree(x**2)
    2
    >>> degree(x**2 + y*x + 1, gen=x)
    2
    >>> degree(x**2 + y*x + 1, gen=y)
    1
    >>> degree(0, x)
    -oo

    In contrast to the strict Poly method, if the specified generator is
    not in Poly's generators, the Poly instance is recast in terms of the
    generator instead of raising an error.

    >>> from sympy import Poly
    >>> p = Poly(x + y, x)
    >>> p.degree(y)
    Exception raised:
    ...
    sympy.polys.polyerrors.PolynomialError: a valid generator expected, got y

    >>> degree(p, y)
    1

    See also
    ========

    sympy.polys.polytools.Poly.total_degree
    degree_list
    """

    _degree = lambda x: Integer(x) if type(x) is int else x

    f = sympify(f, strict=True)
    if type(gen) is int:
        if isinstance(f, Poly):
            return _degree(f.degree(gen))
        if f.is_Number:
            return S.NegativeInfinity if f.is_zero else S.Zero
        p = Poly(f, expand=False)
        gens = p.gens
        free = f.free_symbols
        if not (gen == 0 and len(gens) == 1 and len(free) < 2 and f.is_polynomial(
                gen := next(iter(gens))) and # <-- assigns gen
                gen.is_Atom):  # e.g. x or pi
            raise TypeError(filldedent('''
                To avoid ambiguity, this expression requires either

Review comment (suggestion):
```suggestion
    >>> p.degree(y)
    Traceback (most recent call last):
    ...
    PolynomialError: a valid generator expected, got y

    >>> degree(p, y)
```

Code after:
    ========

    >>> from sympy import degree
    >>> from sympy.abc import x, y

    >>> degree(x**2)
    2
    >>> degree(x**2 + y*x + 1, gen=x)
    2
    >>> degree(x**2 + y*x + 1, gen=y)
    1
    >>> degree(0, x)
    -oo

    In contrast to the strict Poly method, if the specified generator is
    not in Poly's generators, the Poly instance is recast in terms of the
    generator instead of raising an error.

    >>> from sympy import Poly
    >>> p = Poly(x + y, x)
    >>> p.degree(y)
    Traceback (most recent call last):
    ...
    PolynomialError: a valid generator expected, got y

    >>> degree(p, y)
    1

    See also
    ========

    sympy.polys.polytools.Poly.total_degree
    degree_list
    """

    _degree = lambda x: Integer(x) if type(x) is int else x

    f = sympify(f, strict=True)
    if type(gen) is int:
        if isinstance(f, Poly):
            return _degree(f.degree(gen))
        if f.is_Number:
            return S.NegativeInfinity if f.is_zero else S.Zero
        try:
            p = Poly(f, expand=False)
        except GeneratorsNeeded:  # e.g. f = (1+I)**2/2
            gens = ()  # do not guess what the user intended
        else:
            gens = p.gens
        free = f.free_symbols
        if not (gen == 0 and len(gens) == 1 and len(free) < 2 and f.is_polynomial(