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

Code before:
"""
Primality testing

"""

from itertools import count
from typing import SupportsIndex, Iterable
from sympy.core.expr import Expr
from sympy.core.sympify import sympify
from sympy.external.gmpy import (gmpy as _gmpy, gcd, jacobi,
                                 is_square as gmpy_is_square,
                                 bit_scan1, is_fermat_prp, is_euler_prp,
                                 is_selfridge_prp, is_strong_selfridge_prp,
                                 is_strong_bpsw_prp)
from sympy.external.ntheory import _lucas_sequence
from sympy.utilities.misc import as_int, filldedent

# Note: This list should be updated whenever new Mersenne primes are found.
# Refer: https://www.mersenne.org/
MERSENNE_PRIME_EXPONENTS = (2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203,
 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, 110503, 132049,
 216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, 6972593, 13466917, 20996011, 24036583,
 25964951, 30402457, 32582657, 37156667, 42643801, 43112609, 57885161, 74207281, 77232917, 82589933,
 136279841)

def is_fermat_pseudoprime(n: SupportsIndex, a: SupportsIndex) -> bool:
    r"""Returns True if ``n`` is prime or is an odd composite integer that
    is coprime to ``a`` and satisfy the modular arithmetic congruence relation:

    .. math ::
        a^{n-1} \equiv 1 \pmod{n}

    (where mod refers to the modulo operation).

    Parameters
    ==========

Review comment (suggestion):
This file should have `from __future__ import annotations` at the top.

Code after:
"""
Primality testing

"""

from __future__ import annotations

from typing import TYPE_CHECKING

from itertools import count
from typing import SupportsIndex, Iterable
from sympy.core.sympify import sympify
from sympy.external.gmpy import (gmpy as _gmpy, gcd, jacobi,
                                 is_square as gmpy_is_square,
                                 bit_scan1, is_fermat_prp, is_euler_prp,
                                 is_selfridge_prp, is_strong_selfridge_prp,
                                 is_strong_bpsw_prp)
from sympy.external.ntheory import _lucas_sequence
from sympy.utilities.misc import as_int, filldedent

if TYPE_CHECKING:
    from sympy.core.expr import Expr

# Note: This list should be updated whenever new Mersenne primes are found.
# Refer: https://www.mersenne.org/
MERSENNE_PRIME_EXPONENTS = (2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203,
 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, 110503, 132049,
 216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, 6972593, 13466917, 20996011, 24036583,
 25964951, 30402457, 32582657, 37156667, 42643801, 43112609, 57885161, 74207281, 77232917, 82589933,
 136279841)

def is_fermat_pseudoprime(n: SupportsIndex, a: SupportsIndex) -> bool:
    r"""Returns True if ``n`` is prime or is an odd composite integer that
    is coprime to ``a`` and satisfy the modular arithmetic congruence relation:

    .. math ::
Repository: sympy/sympy
File: sympy/ntheory/primetest.py (Python)

Code before:
"""
Primality testing

"""

from itertools import count
from typing import SupportsIndex, Iterable
from sympy.core.expr import Expr
from sympy.core.sympify import sympify
from sympy.external.gmpy import (gmpy as _gmpy, gcd, jacobi,
                                 is_square as gmpy_is_square,
                                 bit_scan1, is_fermat_prp, is_euler_prp,
                                 is_selfridge_prp, is_strong_selfridge_prp,
                                 is_strong_bpsw_prp)
from sympy.external.ntheory import _lucas_sequence
from sympy.utilities.misc import as_int, filldedent

# Note: This list should be updated whenever new Mersenne primes are found.
# Refer: https://www.mersenne.org/
MERSENNE_PRIME_EXPONENTS = (2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203,
 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, 110503, 132049,
 216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, 6972593, 13466917, 20996011, 24036583,
 25964951, 30402457, 32582657, 37156667, 42643801, 43112609, 57885161, 74207281, 77232917, 82589933,
 136279841)

def is_fermat_pseudoprime(n: SupportsIndex, a: SupportsIndex) -> bool:
    r"""Returns True if ``n`` is prime or is an odd composite integer that
    is coprime to ``a`` and satisfy the modular arithmetic congruence relation:

    .. math ::
        a^{n-1} \equiv 1 \pmod{n}

    (where mod refers to the modulo operation).

Review comment (suggestion):
It should be like
```
if TYPE_CHECKING:
    from sympy.core.expr import Expr
```
to avoid problems with circular typing only imports.

Code after:
"""
Primality testing

"""

from __future__ import annotations

from typing import TYPE_CHECKING

from itertools import count
from typing import SupportsIndex, Iterable
from sympy.core.sympify import sympify
from sympy.external.gmpy import (gmpy as _gmpy, gcd, jacobi,
                                 is_square as gmpy_is_square,
                                 bit_scan1, is_fermat_prp, is_euler_prp,
                                 is_selfridge_prp, is_strong_selfridge_prp,
                                 is_strong_bpsw_prp)
from sympy.external.ntheory import _lucas_sequence
from sympy.utilities.misc import as_int, filldedent

if TYPE_CHECKING:
    from sympy.core.expr import Expr

# Note: This list should be updated whenever new Mersenne primes are found.
# Refer: https://www.mersenne.org/
MERSENNE_PRIME_EXPONENTS = (2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203,
 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, 110503, 132049,
 216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, 6972593, 13466917, 20996011, 24036583,
 25964951, 30402457, 32582657, 37156667, 42643801, 43112609, 57885161, 74207281, 77232917, 82589933,
 136279841)

def is_fermat_pseudoprime(n: SupportsIndex, a: SupportsIndex) -> bool:
    r"""Returns True if ``n`` is prime or is an odd composite integer that
Repository: sympy/sympy
File: sympy/ntheory/primetest.py (Python)

Code before:

    Examples
    ========

    >>> from sympy.ntheory.primetest import is_square
    >>> is_square(25)
    True
    >>> is_square(2)
    False

    References
    ==========

    .. [1]  https://mersenneforum.org/showpost.php?p=110896

    See Also
    ========
    sympy.core.intfunc.isqrt
    """
    if prep:
        n = as_int(n)
        if n < 0:
            return False
        if n in (0, 1):
            return True
    return gmpy_is_square(as_int(n))


def _test(n: int, base: int, s: int, t: int) -> bool:
    """Miller-Rabin strong pseudoprime test for one base.
    Return False if n is definitely composite, True if n is
    probably prime, with a probability greater than 3/4.

    """
    # do the Fermat test
    b = pow(base, t, n)
    if b == 1 or b == n - 1:
        return True
    for _ in range(s - 1):
        b = pow(b, 2, n)
        if b == n - 1:
            return True
        # see I. Niven et al. "An Introduction to Theory of Numbers", page 78
        if b == 1:
            return False
    return False


def mr(n: SupportsIndex, bases: Iterable[SupportsIndex]) -> bool:
    """Perform a Miller-Rabin strong pseudoprime test on n using a
    given list of bases/witnesses.

Review comment (suggestion):
Since this function calls `as_int(n)` unconditionally it should just do it once at the start `n = as_int(n)`.

Code after:
    quick method of confirming that it is not.

    Examples
    ========

    >>> from sympy.ntheory.primetest import is_square
    >>> is_square(25)
    True
    >>> is_square(2)
    False

    References
    ==========

    .. [1]  https://mersenneforum.org/showpost.php?p=110896

    See Also
    ========
    sympy.core.intfunc.isqrt
    """
    n = as_int(n)
    if prep:
        if n < 0:
            return False
        if n in (0, 1):
            return True
    return gmpy_is_square(n)


def _test(n: int, base: int, s: int, t: int) -> bool:
    """Miller-Rabin strong pseudoprime test for one base.
    Return False if n is definitely composite, True if n is
    probably prime, with a probability greater than 3/4.

    """
    # do the Fermat test
    b = pow(base, t, n)
    if b == 1 or b == n - 1:
        return True
    for _ in range(s - 1):
        b = pow(b, 2, n)
        if b == n - 1:
            return True
        # see I. Niven et al. "An Introduction to Theory of Numbers", page 78
        if b == 1:
            return False
    return False


def mr(n: SupportsIndex, bases: Iterable[SupportsIndex]) -> bool:
    """Perform a Miller-Rabin strong pseudoprime test on n using a
Repository: sympy/sympy
File: sympy/utilities/misc.py (Python)

Code before:
    ========

    >>> from sympy.utilities.misc import func_name
    >>> from sympy import Matrix
    >>> from sympy.abc import x
    >>> func_name(Matrix.eye(3))
    'MutableDenseMatrix'
    >>> func_name(x < 1)
    'StrictLessThan'
    >>> func_name(x < 1, short=True)
    'Lt'
    """
    alias = {
    'GreaterThan': 'Ge',
    'StrictGreaterThan': 'Gt',
    'LessThan': 'Le',
    'StrictLessThan': 'Lt',
    'Equality': 'Eq',
    'Unequality': 'Ne',
    }
    typ: type | str = type(x)
    if str(typ).startswith("<type '"):
        typ = str(typ).split("'")[1].split("'")[0]
    elif str(typ).startswith("<class '"):
        typ = str(typ).split("'")[1].split("'")[0]
    rv: str = getattr(getattr(x, 'func', x), '__name__', str(typ))
    if '.' in rv:
        rv = rv.split('.')[-1]
    if short:
        rv = alias.get(rv, rv)
    return rv


def _replace(reps):
    """Return a function that can make the replacements, given in
    ``reps``, on a string. The replacements should be given as mapping.

    Examples
    ========

    >>> from sympy.utilities.misc import _replace
    >>> f = _replace(dict(foo='bar', d='t'))
    >>> f('food')
    'bart'
    >>> f = _replace({})
    >>> f('food')
    'food'
    """
    if not reps:
        return lambda x: x
    D = lambda match: reps[match.group(0)]

Review comment (suggestion):
A better way to do this is just to have
```
typ = str(type(x))
```
at the beginning and the `str(typ)` can be `typ` everywhere else.

Code after:
    ========

    >>> from sympy.utilities.misc import func_name
    >>> from sympy import Matrix
    >>> from sympy.abc import x
    >>> func_name(Matrix.eye(3))
    'MutableDenseMatrix'
    >>> func_name(x < 1)
    'StrictLessThan'
    >>> func_name(x < 1, short=True)
    'Lt'
    """
    alias = {
    'GreaterThan': 'Ge',
    'StrictGreaterThan': 'Gt',
    'LessThan': 'Le',
    'StrictLessThan': 'Lt',
    'Equality': 'Eq',
    'Unequality': 'Ne',
    }
    typ = str(type(x))
    if typ.startswith("<type '"):
        typ = typ.split("'")[1].split("'")[0]
    elif typ.startswith("<class '"):
        typ = typ.split("'")[1].split("'")[0]
    rv = getattr(getattr(x, 'func', x), '__name__', typ)
    if '.' in rv:
        rv = rv.split('.')[-1]
    if short:
        rv = alias.get(rv, rv)
    return rv


def _replace(reps):
    """Return a function that can make the replacements, given in
    ``reps``, on a string. The replacements should be given as mapping.

    Examples
    ========

    >>> from sympy.utilities.misc import _replace
    >>> f = _replace(dict(foo='bar', d='t'))
    >>> f('food')
    'bart'
    >>> f = _replace({})
    >>> f('food')
    'food'
    """
    if not reps:
        return lambda x: x
    D = lambda match: reps[match.group(0)]
Repository: sympy/sympy
File: sympy/assumptions/refine.py (Python)

Code before:


def refine_matrixelement(expr, assumptions):
    """
    Handler for symmetric part.

    Examples
    ========

    >>> from sympy.assumptions.refine import refine_matrixelement
    >>> from sympy import MatrixSymbol, Q
    >>> X = MatrixSymbol('X', 3, 3)
    >>> refine_matrixelement(X[0, 1], Q.symmetric(X))
    X[0, 1]
    >>> refine_matrixelement(X[1, 0], Q.symmetric(X))
    X[0, 1]
    """
    from sympy.matrices.expressions.matexpr import MatrixElement
    matrix, i, j = expr.args
    if ask(Q.symmetric(matrix), assumptions):
        if (i - j).could_extract_minus_sign():
            return expr
        return MatrixElement(matrix, j, i)


def refine_trig(expr, assumptions):
    from sympy.functions.elementary.trigonometric import sin, cos
    arg = expr.args[0]
    k = S.Zero
    rem = S.Zero
    terms = arg.args if arg.is_Add else (arg,)
    for term in terms:
        coeff = term / (S.Pi / 2)
        if ask(Q.integer(coeff), assumptions):
            k += coeff
        else:
            rem += term
    if isinstance(expr, sin):
        k -= S.One
    if ask(Q.odd(k), assumptions):
        return (S.NegativeOne**(((k - 1) / 2) + 1)) * sin(rem)
    elif ask(Q.even(k), assumptions):
        return (S.NegativeOne**(k / 2)) * cos(rem)
    return expr

handlers_dict: dict[str, Callable[[Basic, Boolean | bool], Expr]] = {
    'Abs': refine_abs,
    'Pow': refine_Pow,
    'atan2': refine_atan2,
    're': refine_re,
    'im': refine_im,

Review comment (suggestion):
It would probably be better to name this something that doesn't imply it's able to handle trig functions other than sin and cos.

Code after:


def refine_matrixelement(expr, assumptions):
    """
    Handler for symmetric part.

    Examples
    ========

    >>> from sympy.assumptions.refine import refine_matrixelement
    >>> from sympy import MatrixSymbol, Q
    >>> X = MatrixSymbol('X', 3, 3)
    >>> refine_matrixelement(X[0, 1], Q.symmetric(X))
    X[0, 1]
    >>> refine_matrixelement(X[1, 0], Q.symmetric(X))
    X[0, 1]
    """
    from sympy.matrices.expressions.matexpr import MatrixElement
    matrix, i, j = expr.args
    if ask(Q.symmetric(matrix), assumptions):
        if (i - j).could_extract_minus_sign():
            return expr
        return MatrixElement(matrix, j, i)


def refine_sin_cos(expr, assumptions):
    """
    Handler for sin and cos functions.

    Examples
    ========

    >>> from sympy.assumptions.refine import refine_sin_cos
    >>> from sympy import Symbol, Q, sin, cos, pi
    >>> from sympy.abc import x, y
    >>> n = Symbol('n')
    >>> refine_sin_cos(cos(n*pi), Q.even(n))
    (-1)**n
    >>> refine_sin_cos(sin(n*pi/2), Q.odd(n) & Q.odd((n-1)/2))
    (-1)**(n/2 - 1/2)
    >>> refine_sin_cos(sin(x + n*pi/2), Q.odd(n))
    (-1)**(n/2 - 1/2)*cos(x)
    >>> refine_sin_cos(cos(x + n*pi/2), Q.even(n))
    (-1)**(n/2)*cos(x)
    >>> refine_sin_cos(cos(x + y + 2*n*pi), Q.integer(n))
    (-1)**(2*n)*cos(x + y)
    """
    from sympy.functions.elementary.trigonometric import sin, cos
    arg = expr.args[0]

    integer_coeffs_of_pi_half = []
Repository: sympy/sympy
File: sympy/assumptions/refine.py (Python)

Code before:
            return expr
        return MatrixElement(matrix, j, i)


def refine_sin_cos(expr, assumptions):
    from sympy.functions.elementary.trigonometric import sin, cos
    arg = expr.args[0]
    k_terms = []
    rem_terms = []
    terms = arg.args if arg.is_Add else (arg,)
    for term in terms:
        pi_coeff = term.coeff(S.Pi)
        if pi_coeff:
            coeff = 2 * pi_coeff
            if ask(Q.integer(coeff), assumptions):
                k_terms.append(coeff)
            else:
                rem_terms.append(term)
        else:
            rem_terms.append(term)
    k = Add(*k_terms, evaluate=False)
    rem = Add(*rem_terms, evaluate=False)
    if isinstance(expr, sin):
        k = Add(k, -1, evaluate=False)
    if ask(Q.odd(k), assumptions):
        return ((-1)**((k + 1) / 2)) * sin(rem)
    elif ask(Q.even(k), assumptions):
        return ((-1)**(k / 2)) * cos(rem)
    return expr

handlers_dict: dict[str, Callable[[Basic, Boolean | bool], Expr]] = {
    'Abs': refine_abs,
    'Pow': refine_Pow,
    'atan2': refine_atan2,
    're': refine_re,
    'im': refine_im,
    'arg': refine_arg,
    'sign': refine_sign,
    'MatrixElement': refine_matrixelement,
    'cos': refine_sin_cos,
    'sin': refine_sin_cos,
}


Review comment (suggestion):
If we're going to return something, I think it's fine if the object we're returning has automatic simplification applied to. Also, you should avoid creating objects that may not be used. 

Code after:
            return expr
        return MatrixElement(matrix, j, i)


def refine_sin_cos(expr, assumptions):
    """
    Handler for sin and cos functions.

    Examples
    ========

    >>> from sympy.assumptions.refine import refine_sin_cos
    >>> from sympy import Symbol, Q, sin, cos, pi
    >>> from sympy.abc import x, y
    >>> n = Symbol('n')
    >>> refine_sin_cos(cos(n*pi), Q.even(n))
    (-1)**n
    >>> refine_sin_cos(sin(n*pi/2), Q.odd(n) & Q.odd((n-1)/2))
    (-1)**(n/2 - 1/2)
    >>> refine_sin_cos(sin(x + n*pi/2), Q.odd(n))
    (-1)**(n/2 - 1/2)*cos(x)
    >>> refine_sin_cos(cos(x + n*pi/2), Q.even(n))
    (-1)**(n/2)*cos(x)
    >>> refine_sin_cos(cos(x + y + 2*n*pi), Q.integer(n))
    (-1)**(2*n)*cos(x + y)
    """
    from sympy.functions.elementary.trigonometric import sin, cos
    arg = expr.args[0]

    integer_coeffs_of_pi_half = []
    remaining_terms = []

    terms = arg.args if arg.is_Add else (arg,)
    for term in terms:
        coeff_of_pi = term.coeff(S.Pi)
        if coeff_of_pi and ask(Q.integer(2 * coeff_of_pi), assumptions):
            coeff_of_pi_half = 2 * coeff_of_pi
            integer_coeffs_of_pi_half.append(coeff_of_pi_half)
        else:
            remaining_terms.append(term)

    if not integer_coeffs_of_pi_half:
        return expr

    sum_of_parity_known_coeffs = 0
    sum_of_parity_unknown_coeffs = 0
    sum_of_parity_known_coeffs_is_even = True
    for coeff in integer_coeffs_of_pi_half:
        coeff_is_even = ask(Q.even(coeff), assumptions)
        if coeff_is_even is None:
            sum_of_parity_unknown_coeffs += coeff
Repository: sympy/sympy
File: sympy/utilities/iterables.py (Python)

Code before:
    ========

    >>> from sympy import group

    >>> group([1, 1, 1, 2, 2, 3])
    [[1, 1, 1], [2, 2], [3]]
    >>> group([1, 1, 1, 2, 2, 3], multiple=False)
    [(1, 3), (2, 2), (3, 1)]
    >>> group([1, 1, 3, 2, 2, 1], multiple=False)
    [(1, 2), (3, 1), (2, 2), (1, 1)]

    See Also
    ========

    multiset

    """
    if multiple:
        return [(list(g)) for _, g in groupby(seq)]
    return [(k, len(list(g))) for k, g in groupby(seq)]


def _iproduct2(
        iterable1: Iterable[T1],
        iterable2: Iterable[T2],
) -> Iterator[Tuple[T1,T2]]:
    '''Cartesian product of two possibly infinite iterables'''

    it1 = iter(iterable1)
    it2 = iter(iterable2)

    elems1: list[T1] = []
    elems2: list[T2] = []

    sentinel = object()
    def append(it, elems):
        e = next(it, sentinel)
        if e is not sentinel:
            elems.append(e)

    n = 0
    append(it1, elems1)
    append(it2, elems2)

    while n <= len(elems1) + len(elems2):
        for m in range(n-len(elems1)+1, len(elems2)):
            yield (elems1[n-m], elems2[m])
        n += 1
        append(it1, elems1)
        append(it2, elems2)


Review comment (suggestion):
This should be `tuple[T1, T2]` with lower case t and a space.

Code after:
    ========

    >>> from sympy import group

    >>> group([1, 1, 1, 2, 2, 3])
    [[1, 1, 1], [2, 2], [3]]
    >>> group([1, 1, 1, 2, 2, 3], multiple=False)
    [(1, 3), (2, 2), (3, 1)]
    >>> group([1, 1, 3, 2, 2, 1], multiple=False)
    [(1, 2), (3, 1), (2, 2), (1, 1)]

    See Also
    ========

    multiset

    """
    if multiple:
        return [(list(g)) for _, g in groupby(seq)]
    return [(k, len(list(g))) for k, g in groupby(seq)]


def _iproduct2(
    iterable1: Iterable[T1],
    iterable2: Iterable[T2],
) -> Iterator[tuple[T1, T2]]:
    '''Cartesian product of two possibly infinite iterables'''

    it1 = iter(iterable1)
    it2 = iter(iterable2)

    elems1: list[T1] = []
    elems2: list[T2] = []

    sentinel = object()
    def append(it: Iterator[T], elems: list[T]) -> None:
        e = next(it, sentinel)
        if e is not sentinel:
            elems.append(cast("T", e))

    n = 0
    append(it1, elems1)
    append(it2, elems2)

    while n <= len(elems1) + len(elems2):
        for m in range(n-len(elems1)+1, len(elems2)):
            yield (elems1[n-m], elems2[m])
        n += 1
        append(it1, elems1)
        append(it2, elems2)
Repository: sympy/sympy
File: sympy/utilities/iterables.py (Python)

Code before:

    multiset

    """
    if multiple:
        return [(list(g)) for _, g in groupby(seq)]
    return [(k, len(list(g))) for k, g in groupby(seq)]


def _iproduct2(
    iterable1: Iterable[T1],
    iterable2: Iterable[T2],
) -> Iterator[tuple[T1, T2]]:
    '''Cartesian product of two possibly infinite iterables'''

    it1 = iter(iterable1)
    it2 = iter(iterable2)

    elems1: list[T1] = []
    elems2: list[T2] = []

    sentinel = object()
    def append(it: Iterator[_T], elems: list[_T]) -> None:
        e = next(it, sentinel)
        if e is not sentinel:
            elems.append(cast(_T, e))

    n = 0
    append(it1, elems1)
    append(it2, elems2)

    while n <= len(elems1) + len(elems2):
        for m in range(n-len(elems1)+1, len(elems2)):
            yield (elems1[n-m], elems2[m])
        n += 1
        append(it1, elems1)
        append(it2, elems2)


def iproduct(*iterables):
    '''
    Cartesian product of iterables.

    Generator of the Cartesian product of iterables. This is analogous to
    itertools.product except that it works with infinite iterables and will
    yield any item from the infinite product eventually.

    Examples
    ========

    >>> from sympy.utilities.iterables import iproduct

Review comment (suggestion):
With `cast` the first type should generally be a string type like `"T"`. Then it is fine if T is defined in a TYPE_CHECKING block.

Code after:
    """
    if multiple:
        return [(list(g)) for _, g in groupby(seq)]
    return [(k, len(list(g))) for k, g in groupby(seq)]


def _iproduct2(
    iterable1: Iterable[T1],
    iterable2: Iterable[T2],
) -> Iterator[tuple[T1, T2]]:
    '''Cartesian product of two possibly infinite iterables'''

    it1 = iter(iterable1)
    it2 = iter(iterable2)

    elems1: list[T1] = []
    elems2: list[T2] = []

    sentinel = object()
    def append(it: Iterator[T], elems: list[T]) -> None:
        e = next(it, sentinel)
        if e is not sentinel:
            elems.append(cast("T", e))

    n = 0
    append(it1, elems1)
    append(it2, elems2)

    while n <= len(elems1) + len(elems2):
        for m in range(n-len(elems1)+1, len(elems2)):
            yield (elems1[n-m], elems2[m])
        n += 1
        append(it1, elems1)
        append(it2, elems2)


def iproduct(*iterables):
    '''
    Cartesian product of iterables.

    Generator of the Cartesian product of iterables. This is analogous to
    itertools.product except that it works with infinite iterables and will
    yield any item from the infinite product eventually.

    Examples
    ========

    >>> from sympy.utilities.iterables import iproduct
    >>> sorted(iproduct([1,2], [3,4]))
    [(1, 3), (1, 4), (2, 3), (2, 4)]