'''Experiment 11.4: randomly chosen Riemann sums.

The program computes Riemann sums for the function f(x) = 3*x**2 on the interval [0,1]. 
We use the partition Z = {0, 1/n, 2/n, ..., 1}, where n is the input parameter of the function.
The choice of the intermediate points is done by means of n random numbers, 
which are uniformly distributed on each subinterval of the partition.
(See numpy.random.uniform)

Input:
    n... Number of summands 

Output:
    sum... Approximation of the integral of f(x) = 3*x**2 from 0 to 1.

Typical call of program:
    from python11_1 import riemann_sum
    riemann_sum(10)     # riemann_sum(n)

'''

import numpy as np
import matplotlib.pyplot as plt

def riemann_sum(n):
    x = np.arange(0, 1, 1./n)
    
    '''Here we create random intermediate points xi such that
    x[i] <= xi[i] <= x[i+1] for all i = 0...n-1. 
    '''
    xi = x + np.random.uniform(0,1./n,n)
    fx = 3*xi**2
        
    r_sum = sum(fx/n)
    
    '''We plot the function 3*x**2 and the rectangles that represent the summands of the Riemann sum'''
    plt.figure()
    plt.plot(np.arange(0,1,1e-3), 3*np.arange(0,1,1e-3)**2)
    
    for j in range(n-1):
        plt.plot([x[j],x[j],x[j+1],x[j+1]], [0,fx[j],fx[j],0], 'k')
    plt.plot([x[-1],x[-1],1,1], [0,fx[-1],fx[-1],0], 'k')
    plt.text(0,2.8,'Riemann sum estimate:\n'+str(r_sum), fontsize = 14,
         horizontalalignment='left', verticalalignment='center')
    
    plt.show()
    return r_sum