def _minpoly_compose(ex, x, dom):
    "\n    Computes the minimal polynomial of an algebraic element\n    using operations on minimal polynomials\n\n    Examples\n    ========\n\n    >>> minimal_polynomial(sqrt(2) + 3*Rational(1, 3), method='compose')(x)\n    x**2 - 2*x - 1\n    >>> minimal_polynomial(sqrt(y) + 1/y, method='compose')(x)\n    x**2*y**2 - 2*x*y - y**3 + 1\n\n    "
    if ex.is_Rational:
        return ((ex.denominator * x) - ex.numerator)
    if (ex is I):
        return ((x ** 2) + 1)
    if (ex is GoldenRatio):
        return (((x ** 2) - x) - 1)
    if (ex == exp_polar(0)):
        return (x - 1)
    if (hasattr(dom, 'symbols') and (ex in dom.symbols)):
        return (x - ex)
    if (dom.is_RationalField and _is_sum_surds(ex)):
        ex -= x
        while 1:
            ex1 = _separate_sq(ex)
            if (ex1 is ex):
                return ex
            else:
                ex = ex1
    if ex.is_Add:
        res = _minpoly_add(x, dom, *sorted(ex.args, key=count_ops, reverse=True))
    elif ex.is_Mul:
        f = Factors(ex).factors
        r = sift(f.items(), (lambda itx: (itx[0].is_Rational and itx[1].is_Rational)))
        if (r[True] and (dom == QQ)):
            ex1 = Mul(*[(bx ** ex) for (bx, ex) in (r[False] + r[None])])
            r1 = r[True]
            dens = [y.denominator for (_, y) in r1]
            lcmdens = functools.reduce(lcm, dens, 1)
            nums = [(base ** ((y.numerator * lcmdens) // y.denominator)) for (base, y) in r1]
            ex2 = Mul(*nums)
            mp1 = minimal_polynomial(ex1)(x)
            mp2 = ((ex2.denominator * (x ** lcmdens)) - ex2.numerator)
            ex2 = Mul(*[(bx ** ex) for (bx, ex) in r1])
            res = _minpoly_op_algebraic_element(Mul, ex1, ex2, x, dom, mp1=mp1, mp2=mp2)
        else:
            res = _minpoly_mul(x, dom, *sorted(ex.args, key=count_ops, reverse=True))
    elif ex.is_Pow:
        if (ex.base is E):
            res = _minpoly_exp(ex, x)
        else:
            res = _minpoly_pow(ex.base, ex.exp, x, dom)
    elif isinstance(ex, sin):
        res = _minpoly_sin(ex, x)
    elif isinstance(ex, cos):
        res = _minpoly_cos(ex, x)
    elif isinstance(ex, tan):
        res = _minpoly_tan(ex, x)
    elif (isinstance(ex, RootOf) and ex.poly.domain.is_Numerical):
        res = _minpoly_rootof(ex, x)
    elif isinstance(ex, conjugate):
        res = _minpoly_compose(ex.args[0], x, dom)
    elif isinstance(ex, Abs):
        res = _minpoly_compose(sqrt((ex.args[0] * ex.args[0].conjugate())), x, dom)
    elif isinstance(ex, re):
        res = _minpoly_compose(((ex.args[0] + ex.args[0].conjugate()) / 2), x, dom)
    elif isinstance(ex, im):
        res = _minpoly_compose((((ex.args[0] - ex.args[0].conjugate()) / 2) / I), x, dom)
    else:
        raise NotAlgebraic(f"{ex} doesn't seem to be an algebraic element")
    return res
Computes the minimal polynomial of an algebraic element
using operations on minimal polynomials

Examples
========

>>> minimal_polynomial(sqrt(2) + 3*Rational(1, 3), method='compose')(x)
x**2 - 2*x - 1
>>> minimal_polynomial(sqrt(y) + 1/y, method='compose')(x)
x**2*y**2 - 2*x*y - y**3 + 1
def _minpoly_compose(ex, x, dom):
    "\n    Computes the minimal polynomial of an algebraic element\n    using operations on minimal polynomials\n\n    Examples\n    ========\n\n    >>> minimal_polynomial(sqrt(2) + 3*Rational(1, 3), method='compose')(x)\n    x**2 - 2*x - 1\n    >>> minimal_polynomial(sqrt(y) + 1/y, method='compose')(x)\n    x**2*y**2 - 2*x*y - y**3 + 1\n\n    "
    if ex.is_Rational:
        return ((ex.denominator * x) - ex.numerator)
    if (ex is I):
        return ((x ** 2) + 1)
    if (ex is GoldenRatio):
        return (((x ** 2) - x) - 1)
    if (ex == exp_polar(0)):
        return (x - 1)
    if (hasattr(dom, 'symbols') and (ex in dom.symbols)):
        return (x - ex)
    if (dom.is_RationalField and _is_sum_surds(ex)):
        ex -= x
        while 1:
            ex1 = _separate_sq(ex)
            if (ex1 is ex):
                return ex
            else:
                ex = ex1
    if ex.is_Add:
        res = _minpoly_add(x, dom, *sorted(ex.args, key=count_ops, reverse=True))
    elif ex.is_Mul:
        f = Factors(ex).factors
        r = sift(f.items(), (lambda itx: (itx[0].is_Rational and itx[1].is_Rational)))
        if (r[True] and (dom == QQ)):
            ex1 = Mul(*[(bx ** ex) for (bx, ex) in (r[False] + r[None])])
            r1 = r[True]
            dens = [y.denominator for (_, y) in r1]
            lcmdens = functools.reduce(lcm, dens, 1)
            nums = [(base ** ((y.numerator * lcmdens) // y.denominator)) for (base, y) in r1]
            ex2 = Mul(*nums)
            mp1 = minimal_polynomial(ex1)(x)
            mp2 = ((ex2.denominator * (x ** lcmdens)) - ex2.numerator)
            ex2 = Mul(*[(bx ** ex) for (bx, ex) in r1])
            res = _minpoly_op_algebraic_element(Mul, ex1, ex2, x, dom, mp1=mp1, mp2=mp2)
        else:
            res = _minpoly_mul(x, dom, *sorted(ex.args, key=count_ops, reverse=True))
    elif ex.is_Pow:
        if (ex.base is E):
            res = _minpoly_exp(ex, x)
        else:
            res = _minpoly_pow(ex.base, ex.exp, x, dom)
    elif isinstance(ex, sin):
        res = _minpoly_sin(ex, x)
    elif isinstance(ex, cos):
        res = _minpoly_cos(ex, x)
    elif isinstance(ex, tan):
        res = _minpoly_tan(ex, x)
    elif (isinstance(ex, RootOf) and ex.poly.domain.is_Numerical):
        res = _minpoly_rootof(ex, x)
    elif isinstance(ex, conjugate):
        res = _minpoly_compose(ex.args[0], x, dom)
    elif isinstance(ex, Abs):
        res = _minpoly_compose(sqrt((ex.args[0] * ex.args[0].conjugate())), x, dom)
    elif isinstance(ex, re):
        res = _minpoly_compose(((ex.args[0] + ex.args[0].conjugate()) / 2), x, dom)
    elif isinstance(ex, im):
        res = _minpoly_compose((((ex.args[0] - ex.args[0].conjugate()) / 2) / I), x, dom)
    else:
        raise NotAlgebraic(f"{ex} doesn't seem to be an algebraic element")
    return res