<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 ★ Monte Carlo Simulation To Calculate PI ★
Step1:  Necesaary Function For Monte Carlo Simulation
Step2:  Monte Carlo Simulation (with Minimal standard random number generator)
Step3:  Monte Carlo Simulation (with LCG where multiplier = 13, offset = 0 and modulus = 31)
Step4:  Monte Carlo Simulation (with Quasi-random numbers)¶
<ASSISTANT_TASK:>
Python Code:
# Import modules
import time
import math
import numpy as np
import scipy
import matplotlib.pyplot as plt
Explanation: ★ Monte Carlo Simulation To Calculate PI ★
End of explanation
def linear_congruential_generator(x, a, b, m):
    x = (a * x + b) % m
    u = x / m
    return u, x, a, b, m
def stdrand(x):
    return linear_congruential_generator(x, pow(7, 5), 0, pow(2, 31) - 1)[:2]
def halton(p, n):
    b = np.zeros(math.ceil(math.log(n + 1) / math.log(p)))
    u = np.zeros(n)
    for j in range(n):
        i = 0
        b[0] = b[0] + 1
        while b[i] > p - 1 + np.finfo(float).eps:
            b[i] = 0
            i += 1
            b[i] += 1 
        u[j] = 0
        for k in range(1, b.size + 1):
            u[j] = u[j] + b[k-1] * pow(p, -k)
    return u
Explanation: Necesaary Function For Monte Carlo Simulation
End of explanation
def monte_carlo_process_std(toss):
    x = time.time()
    hit = 0
    for i in range(toss):
        u1, x = stdrand(x)
        u2, x = stdrand(x)
        if pow(u1, 2) + pow(u2, 2) < 1.0:
            hit += 1
    return hit * 4.0 / toss
pi = monte_carlo_process_std(2000000)
print('pi = %.10f, err = %.10f' %(pi, abs(pi - np.pi)))
Explanation: Monte Carlo Simulation (with Minimal standard random number generator)
End of explanation
def monte_carlo_process_customized(toss):
    x0 = time.time()
    args = (x0, 13, 0, 31)
    hit = 0
    for i in range(toss):
        u1, *args = linear_congruential_generator(*args)
        u2, *args = linear_congruential_generator(*args)
        if pow(u1, 2) + pow(u2, 2) < 1.0:
            hit += 1
    return hit * 4.0 / toss
pi = monte_carlo_process_customized(2000000)
print('pi = %.10f, err = %.10f' %(pi, abs(pi - np.pi)))
Explanation: Monte Carlo Simulation (with LCG where multiplier = 13, offset = 0 and modulus = 31)
End of explanation
def monte_carlo_process_quasi(toss):
    hit = 0
    px = halton(2, toss)
    py = halton(3, toss)
    for i in range(toss):
        u1 = px[i]
        u2 = py[i]
        if pow(u1, 2) + pow(u2, 2) < 1.0:
            hit += 1
    return hit * 4.0 / toss
pi = monte_carlo_process_quasi(2000000)
print('pi = %.10f, err = %.10f' %(pi, abs(pi - np.pi)))
Explanation: Monte Carlo Simulation (with Quasi-random numbers)¶
End of explanation
<END_TASK>