We implement the mathematical expression (as appears in the reference article) using Chebyshev polynomials via a recurrence relation.The recursive form maps neatly onto quantum add/mul blocks that Classiq can optimize.
The KL expansion expresses B(t) as an orthogonal sine series with i.i.d.Gaussian coefficients ak. In truncated form:BL(t)=pL(a,cos(t))=a0t+π2sin(πt)k=0∑L−1kakUk(cost(πt))where Uk are Chebyshev polynomials of the second kind.
The Chebyshev polynomials are a sequence of orthogonal polynomials that are related to de Moivre’s formula and the trigonometric functions.They are defined by the recurrence relation:U0(x)=1,U1(x)=2xUk+1(x)=2xUk(x)−Uk−1(x)
@qpermdef uk(two_x: Const[QNum], uk_1: Const[QNum], uk_2: Const[QNum], uk: Output[QNum]): uk |= two_x * uk_1 - uk_2@qfuncdef main(x: Output[QNum[2, UNSIGNED, 2]]): allocate(x) hadamard_transform(x) U = [QNum(f"U{k}") for k in range(L)] U[0] |= 1 U[1] |= 2 * x for k in range(2, L): uk(x, uk_1=U[k - 1], uk_2=U[k - 2], uk=U[k])qprog_uk = synthesize(main)
Circuit scaling intuition:
Loop depth grows as O(L).
Doubling truncation order increases gate count only linearly (hardware-friendly).
show(qprog_uk)
Output:
Quantum program link: https://platform.classiq.io/circuit/36pwmrzrsiD5dUq0bmDzlSnNiS6
The Brownian motion is a stochastic process that models the random movement of particles in a fluid.The approximate solution in this context is the truncated Wiener series.BL(t)=pL(a,cos(t))=a0t+π2sin(πt)k=0∑L−1kakUk(cost(πt))Key ingredients in the quantum model:
Prepare registers for coefficients (a_0,\dots,a_{L-1}) from the discretized Gaussian distribution (amplitude loading).
Prepare a time register (t) in superposition (e.g., Hadamards over a time index).
Compute:
2cos(πt) (or a stand-in approximation)
sin(πt) (or a stand-in approximation)
Uk(cos(πt)) via recurrence
Accumulate the weighted sum to form BL(t).
@qfuncdef truncated_wiener_series(t: QNum, out: Output[QNum]): As = [QNum(f"a{i}") for i in range(L)] for a in As: prepare_state(probabilities, 0, a) two_cos_pi_t = QNum("two_cos_pi_t") sin_pi_t = QNum("sin_pi_t") U = [QNum(f"U{k}") for k in range(L)] two_cos_pi_x(x=t, out=two_cos_pi_t) U[0] |= 1 U[1] |= two_cos_pi_t for k in range(2, L): uk(two_cos_pi_t, uk_1=U[k - 1], uk_2=U[k - 2], uk=U[k]) sin_pi_x(x=t, out=sin_pi_t) out |= As[0] * t + (2**0.5 / PI) * sin_pi_t * sum( [As[i] * U[i] for i in range(1, L)] ) for a in As: drop(a) for u in U: drop(u)
@qfuncdef main(t: Output[QNum], G: Output[QNum]): # Allocate qubits and prepare distributions B = QNum("B") allocate(TIME_STEPS, t) hadamard_transform(t) # Create the truncated wiener series truncated_wiener_series(t, B) # Return to price space return_to_price_space(returns=B, t=t, price=G) drop(B)
This notebook illustrates that a mathematically heavy model (KL-truncated GBM + Chebyshev recursion)
becomes circuit-light once randomness is moved into amplitudes.Next steps toward pricing (expected payoff):
Amplitude loading: put Gaussian coefficients into superposition with
O(npolylog(1/ϵ)) gates (matching the power-of-two grid).
Nested QAE (conceptually):
First QAE estimates time-averaged price along the path.
Second QAE wraps the payoff.
Query complexity can still beat classical Monte Carlo scaling.
Potential shortcut (as hinted in the reference):
Drop one QAE via smart time subsampling to reduce depth without extra qubits
(constants and practical tradeoffs depend on implementation details).
Takeaway:
The classical formula is algebraically dense, but the quantum program is highly structured,
enabling modeling-focused development with automated circuit synthesis.