def load_Q_operator(qu, depth, S0, sig, r, T, K, error=0.05):
    """
    Function to create quantum circuit for the unary representation to return an approximate probability distribution.
        This function is thought to be the prelude of run_payoff_quantum_sim
    :param qu: Number of qubits
    :param S0: Initial price
    :param depth: Number of implementations of Q
    :param sig: Volatility
    :param r: Interest rate
    :param T: Maturity date
    :param K: strike
    :return: quantum circuit, backend, prices
    """
    depth = int(depth)

    mu = ((r - 0.5 * sig**2) * T + np.log(S0)
          )  # parameters for the log_normal distribution
    sigma = sig * np.sqrt(T)
    mean = np.exp(mu + sigma**2 / 2)
    variance = (np.exp(sigma**2) - 1) * np.exp(2 * mu + sigma**2)
    stddev = np.sqrt(variance)

    # lowest and highest value considered for the spot price; in between, an equidistant discretization is considered.
    low = np.maximum(0, mean - 3 * stddev)
    high = mean + 3 * stddev
    #S = np.linspace(low, high, samples)

    # construct circuit factory for uncertainty model
    uncertainty_model = LogNormalDistribution(qu,
                                              mu=mu,
                                              sigma=sigma,
                                              low=low,
                                              high=high)

    qr = QuantumRegister(2 * qu + 2)
    cr = ClassicalRegister(1)
    qc = QuantumCircuit(qr, cr)

    uncertainty_model.build(qc, qr)
    (k, c) = payoff_circuit(qc, qu, K, high, low, error=error, measure=False)

    for i in range(depth):
        oracle_operator(qc, qu)
        payoff_circuit_inv(qc, qu, K, high, low, error=error, measure=False)
        uncertainty_model.build_inverse(qc, qr)
        diffusion_operator(qc, qu)
        uncertainty_model.build(qc, qr)
        payoff_circuit(qc, qu, K, high, low, error=error, measure=False)

    qc.measure([2 * qu + 1], [0])
    return qc, (k, c, high, low)
def load_payoff_quantum_sim(qu, S0, sig, r, T, K, error=0.05):
    """
    Function to create quantum circuit to return an approximate probability distribution.
        This function is thought to be the prelude of run_payoff_quantum_sim
    :param qu: Number of qubits
    :param S0: Initial price
    :param sig: Volatility
    :param r: Interest rate
    :param T: Maturity date
    :param K: strike
    :return: quantum circuit, backend, prices
    """

    mu = ((r - 0.5 * sig**2) * T + np.log(S0)
          )  # parameters for the log_normal distribution
    sigma = sig * np.sqrt(T)
    mean = np.exp(mu + sigma**2 / 2)
    variance = (np.exp(sigma**2) - 1) * np.exp(2 * mu + sigma**2)
    stddev = np.sqrt(variance)

    # lowest and highest value considered for the spot price; in between, an equidistant discretization is considered.
    low = np.maximum(0, mean - 3 * stddev)
    high = mean + 3 * stddev
    # S = np.linspace(low, high, samples)

    # construct circuit factory for uncertainty model
    uncertainty_model = LogNormalDistribution(qu,
                                              mu=mu,
                                              sigma=sigma,
                                              low=low,
                                              high=high)

    # values = uncertainty_model.values
    # pdf = uncertainty_model.probabilities

    qr = QuantumRegister(2 * qu + 2)
    cr = ClassicalRegister(1)
    qc = QuantumCircuit(qr, cr)
    uncertainty_model.build(qc, qr)

    k, c = payoff_circuit(qc, qu, K, high, low, error=error)

    return c, k, high, low, qc
def load_quantum_sim(qu, S0, sig, r, T):
    """
    Function to create quantum circuit for the binary representation to return an approximate probability distribution.
        This function is thought to be the prelude of run_quantum_sim
    :param qu: Number of qubits
    :param S0: Initial price
    :param sig: Volatility
    :param r: Interest rate
    :param T: Maturity date
    :return: quantum circuit, backend, (values of prices, prob. distri. function), (mu, mean, variance)
    """
    mu = ((r - 0.5 * sig**2) * T + np.log(S0)
          )  # parameters for the log_normal distribution
    sigma = sig * np.sqrt(T)
    mean = np.exp(mu + sigma**2 / 2)
    variance = (np.exp(sigma**2) - 1) * np.exp(2 * mu + sigma**2)
    stddev = np.sqrt(variance)

    # lowest and highest value considered for the spot price; in between, an equidistant discretization is considered.
    low = np.maximum(0, mean - 3 * stddev)
    high = mean + 3 * stddev
    # S = np.linspace(low, high, samples)

    # construct circuit factory for uncertainty model
    uncertainty_model = LogNormalDistribution(qu,
                                              mu=mu,
                                              sigma=sigma,
                                              low=low,
                                              high=high)

    values = uncertainty_model.values
    pdf = uncertainty_model.probabilities

    qr = QuantumRegister(qu)
    cr = ClassicalRegister(qu)
    qc = QuantumCircuit(qr, cr)
    uncertainty_model.build(qc, qr)
    qc.measure(np.arange(0, qu), np.arange(0, qu))

    return qc, (values, pdf), (mu, mean, variance)
            sortedcounts.append(counts.get(j))

plt.suptitle('Uniform Distribution')
plt.plot(sortedcounts)
plt.show()

print("\n Log-Normal Distribution")
print("-----------------")

circuit = QuantumCircuit(q, c)
lognorm = LogNormalDistribution(num_target_qubits=5,
                                mu=0,
                                sigma=1,
                                low=0,
                                high=1)
lognorm.build(circuit, q)
circuit.measure(q, c)

circuit.draw(output='mpl', filename='log.png')

job = execute(circuit, backend, shots=8192)
job_monitor(job)
counts = job.result().get_counts()

print(counts)

sortedcounts = []
sortedkeys = sorted(counts)

for i in sortedkeys:
    for j in counts: