In [ ]:

```
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
```

The goal of this exercise is to define a class `Polynomial`

, which behaves like a polynomial. For instance

`p = Polynomial([1.,2.])`

should represent the polynomial $1 + 2X$.

The object `p`

should be callable

`p(.2) # value of the polynomial at 0.2`

One should be able to add, multiply two polynomials.

You will be guided through by the following detailed tasks.

In [ ]:

```
class Polynomial:
pass # implement here
```

Implement the `__init__`

method, which stores a list of coefficients. Use the `array`

function to copy the list, or array, of coefficiente which is passed. Store the coefficients in a property `coeffs`

.

In [ ]:

```
a = np.array([1.,2.])
p = Polynomial(a)
assert not p.coeffs is a
```

Implement the method `__getitem__`

, which allows to give acess to the coefficients. An out of bound index should return zero, like in mathematics.

In [ ]:

```
assert np.allclose(p[0], 1.)
assert np.allclose(p[3], 0.)
```

Implement the method `__add__`

, which adds two polynomials.

In [ ]:

```
q = Polynomial([1.,2.,3])
z = p+q
assert np.allclose((p+q)[0], 2.)
assert np.allclose((p+q)[2], 3.)
```

Implement the method `__repr__`

, which returns a string such as `Polynomial(array([1.,2.]))`

.

**Hint**: use the function `repr`

on the coefficient array of the polynomial.

In [ ]:

```
assert repr(p) == "Polynomial(array([ 1., 2.]))"
```

Implement `differentiate`

which returns the derivative of the polynomial.

In [ ]:

```
assert np.allclose(p.differentiate().coeffs, array([2.]))
```

Implement the method `__call__`

, which evaluates the polynomial at a given point.

**Bonus** if the method works with array inputs, like `p(array([1.,2.,3.])`

.

**Hint**: Use the functions `reduce`

and, possibly, the function `reversed`

.

In [ ]:

```
reduce?
```

In [ ]:

```
assert allclose(p(0.), 1.)
```