rootof: use modular exponentiation with RootOf objects

Given a root of a polynomial of degree `n` any power of that root greater than or equal to `n` can be written in terms of powers less than `n`. Performing this modular reduction with `RootOf` expressions can curb expression swell, at least with respect to handling large powers of the root. In some cases this results in a performance improvement when handling large degree expressions with `RootOf`s.

The change involves adding behavior to `RootOf._eval_power()` such that, whenever an exponent greater than the root's defining polynomial's degree is provided, a modular exponentiation algorithm is used to determine the result. Otherwise, the default `Expr._eval_power()` is called.

Example:
```
In [1]: r = RootOf(x**5 - 3*x**2 - 1,0)

In [2]: r**5
Out[2]:
                          2
        ⎛ 5      2       ⎞
3⋅RootOf⎝x  - 3⋅x  - 1, 0⎠  + 1

In [3]: r = RootOf(2*x**3 + 2*x - 1,0)

In [4]: p = random_poly(y, 20, -4, 4); q = random_poly(y, 20, -4, 4)

In [5]: %time (p.subs(y,r) * q.subs(y,r)).expand()
CPU times: user 103 ms, sys: 2.08 ms, total: 105 ms
Wall time: 109 ms
Out[5]:
                                   2
                ⎛   3             ⎞                ⎛   3             ⎞
  1023983⋅RootOf⎝2⋅x  + 2⋅x - 1, 0⎠    24609⋅RootOf⎝2⋅x  + 2⋅x - 1, 0⎠   13901
- ────────────────────────────────── + ─────────────────────────────── + ─────
                 2048                                256                  512
```
Without modular exponentiation / reduction the example expansion would take approximately 340 ms.

Closes #8543.
You may want to omit redundant parentheses.