'Construct a Trace object.
Parameters
args = sympy expression
indices = tuple/list if indices, optional'

def __new__(cls, *args):

    if (len(args) == 2):
        if (not isinstance(args[1], (list, Tuple, tuple))):
            indices = Tuple(args[1])
        else:
            indices = Tuple(*args[1])
        expr = args[0]
    elif (len(args) == 1):
        indices = Tuple()
        expr = args[0]
    else:
        raise ValueError('Arguments    to    Tr    should    be    of    form    (expr[,    [indices]])')
    if isinstance(expr, Matrix):
        return expr.trace()
    elif (hasattr(expr, 'trace') and callable(expr.trace)):
        return expr.trace()
    elif isinstance(expr, Add):
        return Add(*[Tr(arg, indices) for arg in expr.args])
    elif isinstance(expr, Mul):
        (c_part, nc_part) = expr.args_cnc()
        if (len(nc_part) == 0):
            return Mul(*c_part)
        else:
            obj = Expr.__new__(cls, Mul(*nc_part), indices)
            return ((Mul(*c_part) * obj) if (len(c_part) > 0) else obj)
    elif isinstance(expr, Pow):
        if (_is_scalar(expr.args[0]) and _is_scalar(expr.args[1])):
            return expr
        else:
            return Expr.__new__(cls, expr, indices)
    else:
        if _is_scalar(expr):
            return expr
        return Expr.__new__(cls, expr, indices)
