QuantumComputinglib learn · inspect · formalize
Checked on this commit 4,524 public declarations commit ab8f277c5704 Build record

State preparation · Exact Hermite target; polynomial-gate Bernstein–MPS construction; finite export evidence remains separate

Hermite-smoothed initial states

Prepare the sampled smooth auxiliary initial state used in Schrödingerisation, for any Hermite order k. Load function values as amplitudes and account for the preparation circuit itself.

Lean certifiedPrepare the same state with internal width \(D=2k+6\): for fixed \(k\), the certified exact-real quantum bound grows linearly with \(n_p\) rather than with the \(2^{n_p}\) amplitudes.

Source paper · general Hermite initial-state family with an ASPBE preparation circuit

Where this example comes from

Schrödingerisation based computationally stable algorithms for ill-posed problems in partial differential equations
Shi Jin, Nana Liu, Chuwen Ma · 2024

Source anchor. Jin–Liu–Ma Sec. 4.3, Eqs. (4.31)–(4.32); cubic example Eq. (6.1)

Sec. 4.3 Eq. (4.31) Eq. (4.32) Eq. (6.1)

What the paper says. The negative half-axis is extended by a degree at most \(2k+1\) Hermite polynomial on [-1,0], matching derivatives through order \(k\) at both endpoints; the positive half-axis remains exp(-p).

What ASPBE does here. ASPBE proves the explicit coefficients, global C^k smoothness and a deterministic primitive rotation circuit for the normalized sampled state. The paper's PDE recovery, Sobolev and convergence results are not claimed as Lean theorems by this case. The C2 sentence after Eq. (6.1) is not adopted: its displayed cubic is C1 at the splice points.

Open source paper ↗

Core insight · start from the mathematical object

Why an exponentially long state can still have a short preparation rule

The state has one amplitude for every grid point, but those amplitudes are not independent data. They all come from the same three-piece Hermite profile. The construction keeps that functional structure while reading the binary address, so the circuit carries only a small working state whose dimension depends on the smoothing order k.

\[N=2^{n_p},\qquad |g_k\rangle_p=\frac{1}{\sqrt{Z_k}}\sum_{j=0}^{N-1}g_k(p_j)|j\rangle,\qquad Z_k=\sum_{j=0}^{N-1}g_k(p_j)^2.\]

What the reference method actually stores

“Amplitude list” and “mass tree” are concrete objects, not jargon

The reference construction is easiest to understand if we name the two objects that make it generic.

Define this first

Explicit amplitude list

\(\bigl(g_k(p_0),g_k(p_1),\ldots,g_k(p_{N-1})\bigr)\)

This is what we mean by a sample table: write down all N function values as if they were unrelated input data. It is correct, but it immediately forgets that every entry came from one simple function.

Define this first

Binary mass tree

\(m_{d,s}=\sum_{j\bmod 2^d=s}g_k(p_j)^2\)

This is the reference preparation tree: each prefix stores the probability mass under that prefix, and its two child masses determine the next controlled rotation. The tree is transparent, but the number of prefixes grows with the number of samples.

The structural question. Can we prepare exactly the same amplitudes without first materializing the full amplitude list or its full binary mass tree?

What is special about this family?

The samples come from one short piecewise function

Before discussing MPS, bond dimension or compilation, keep the source formula visible:

\[g_k(p)=\begin{cases}e^p,&p<-1,\\ P_{2k+1}(p),&-1\le p\le0,\\ e^{-p},&p>0.\end{cases}\]

1 · keep the source function

Do not turn the Hermite profile into unrelated samples

The left tail, polynomial bridge and right tail each have a finite description. The proof keeps those descriptions alive instead of expanding them into N separate numbers.

\(e^p\;|\;P_{2k+1}(p)\;|\;e^{-p}\)

2 · read one address bit

A binary digit only chooses the next dyadic half-interval

Reading the address most-significant-bit first is an interval walk. We only need to update enough information to evaluate the same source function on the chosen child interval.

\(j=(b_1b_2\cdots b_{n_p})_2,\qquad I_{s+1}=\operatorname{child}_{b_{s+1}}(I_s)\)

3 · update small analytic memory

Tails need scalars; the polynomial needs Bernstein coefficients

The exponential pieces factor over address bits. On the polynomial piece, exact de Casteljau subdivision maps one short Bernstein coefficient vector to the left or right child vector. Boundary bookkeeping plus the two tails gives total width D=2k+6.

\(e^{\pm p_j}:\text{ scalar update},\qquad c\mapsto M_{b_s}c,\quad c\in\mathbb R^{2k+2}\)

4 · recognize a tensor train

The bit-by-bit finite-state rule is exactly an MPS/TT factorization

The long amplitude vector is represented by n_p local tensors coupled through a D-dimensional bond. The bond is working memory, not another copy of the amplitude table.

\(g_k(p_j)=\ell^{\mathsf T}A_1(b_1)\cdots A_{n_p}(b_{n_p})r,\qquad D=2k+6\)

5 · compile the bond

Canonicalize locally, complete isometries, then emit elementary gates

Small Gram contractions give the norm; thin LQ makes the chain locally norm preserving; only reachable columns are completed to real unitaries and decomposed into rotations. The bond qubits return to zero.

\(\text{TT/MPS}\to\text{local isometries}\to\text{real unitaries}\to R_y/\mathrm{CNOT}\)
The compression theorem in one line
\[g_k(p_j)=\ell^{\mathsf T}A_1(b_1)A_2(b_2)\cdots A_{n_p}(b_{n_p})r,\qquad D=2k+6.\]

The matrices are local updates selected by the address bits. The important number is the internal width \(D=2k+6\), not the number \(2^{n_p}\) of output amplitudes.

Mathematical cross-pollination

Each field supplies one indispensable interface

The proof is not “use MPS” as a black box. It changes representation four times, and each change preserves a precise invariant.

Hermite interpolation

Hermite interpolation

Supplies the smooth three-piece profile and the low-degree polynomial bridge.

Approximation theory / CAGD

Approximation theory / CAGD

Bernstein coordinates and exact de Casteljau subdivision turn a polynomial into a stable left/right interval update rule.

Tensor networks

Tensor networks

The finite update state is reinterpreted as the bond of a matrix-product state / tensor train.

Quantum compilation

Quantum compilation

Local isometries are completed and decomposed into an explicit clean Ry/CNOT circuit.

Certified quantum consequence
\[G,\operatorname{depth}\le 48\,n_pD^3=48\,n_p(2k+6)^3,\qquad q_{\mathrm{bond}}=\lceil\log_2D\rceil.\]

Read this before the proof dashboard

A smooth classical curve becomes the amplitudes of a quantum register.

A generic loader visits exponentially many amplitudes. This particular smooth family has structure: its polynomial piece can be carried by a short vector of Bernstein coefficients, while each exponential tail needs only a scalar update. The new circuit reuses that small memory as it emits the data bits. The original loader remains a transparent reference, not the complexity result.

In Schrödingerisation, this register is prepared independently of the physical-system initial state. Their joint input is \(\lvert g_k\rangle_p\otimes\lvert u_0\rangle\). Subsequent Fourier transforms and evolution are separate algorithm stages.

Read the new circuit first

Follow the data register and the reusable bond register

\[|0^{n_p}\rangle|0^q\rangle\xrightarrow{\;V_1V_2\cdots V_{n_p}\;}|g_k\rangle|0^q\rangle\]
1
Two registers have different jobs

The data register has \(n_p\) output qubits. The bond register has \(q=\lceil\log_2(2k+6)\rceil\) temporary qubits and must return to \(|0^q\rangle\).

2
One local stage emits one address bit

The symbolic tensor train is read most-significant-bit first. Stage \(V_s\) updates the small bond state and emits the next data bit; it does not look up an entry in a length-\(2^{n_p}\) table.

3
The bond stores function state, not sample values

For the tails the update is scalar. For the polynomial branch it carries Bernstein coefficients plus boundary bookkeeping. Before binary padding the total internal dimension is \(D=2k+6\).

4
Local algebra becomes elementary gates

Thin LQ/canonicalization makes each stage an isometry; reachable columns are completed to a real unitary and compiled to \(R_y\) and CNOT gates. The final bond sector is clean.

The historical mass-tree/UCRY circuit is retained below as the reference construction. The certified evolution panel shows both routes side by side.

Statement → proof → optional Lean

The mathematical claims, in the order a human would prove them

1 · Source construction

One polynomial satisfies all endpoint derivative conditions

\[t=p+1,\quad a_{k,r}=\sum_{m=0}^{r}\frac{\binom{k+r-m}{k}}{m!},\quad A_k(t)=\sum_{r=0}^{k}a_{k,r}t^r,\qquad P_k(p)=e^{-1}(1-t)^{k+1}A_k(t)+t^{k+1}A_k(1-t).\]

The coefficients are explicit. At the left endpoint all derivatives through order \(k\) equal exp(−1); at the right they alternate between 1 and −1. The polynomial degree is at most 2k+1. The literal piecewise function is globally Cᵏ; a separate gluing theorem closes this analytic claim.

Proof story

  1. Truncate a formal series\(A_k\) keeps the first \(k+1\) coefficients of \(\exp(t)/(1-t)^{k+1}\). Multiplication restores the exponential coefficients through order \(k\).
  2. Match each endpointA factor \(t^{k+1}\) kills the first \(k\) derivatives at \(t=0\). Reflect \(t\) to \(1-t\) to obtain the right endpoint.
  3. Check uniquenessA difference with both zero jets is divisible by \(t^{k+1}(1-t)^{k+1}\), whose degree is too large unless the difference is zero.
  4. Glue the smooth piecesMatching values and successive derivatives at −1 and 0 gives a globally Cᵏ real function; Lean proves the gluing for arbitrary k.
Show the Lean proof checkpoints

The mathematical explanation above is the reading layer. These compiled declarations are the proof authority.

2 · Preparation invariant

The rotations distribute exactly the requested amplitude mass

\[m_{d,s}=\sum_{j\bmod2^d=s}g_k(p_j)^2,\quad \theta_{d,s}=2\operatorname{atan2}\!\left(\sqrt{m_{d+1,s+2^d}},\sqrt{m_{d+1,s}}\right),\quad |\Psi_d\rangle=\sum_{s<2^d}\sqrt{\frac{m_{d,s}}{Z_k}}|0^{n-d}\rangle|s\rangle.\]

Every layer resolves one bit of the target state. The squared norm is preserved, and after n layers each leaf amplitude equals its sample divided by the total norm.

Proof story

  1. Partition by the next bitThe two child index sets are disjoint and together exhaust the parent.
  2. Apply a two-dimensional rotationCosine and sine give the ratios of child square-root masses to the parent square-root mass.
  3. Close the rootAt full depth each mass is a single squared sample; normalization and state action follow. Zero-mass subtrees carry zero incoming amplitude.
Show the Lean proof checkpoints

The mathematical explanation above is the reading layer. These compiled declarations are the proof authority.

3 · Polynomial quantum construction

Reuse a small memory instead of listing every amplitude

\[D=2k+6,\quad q=\lceil\log_2D\rceil,\quad U|0^{n_p+q}\rangle=|g_k\rangle|0^q\rangle,\qquad G,\mathrm{depth}\le48n_pD^3.\]

For every natural \(k\), \(n_p\ge1\) and \(L>0\), an actual Ry/CNOT circuit prepares exactly the same normalized samples. Its small bond memory has \(D\) states before binary padding. Fixed \(k\) therefore gives a linear quantum gate bound in \(n_p\), rather than exponential scaling. No amplitude oracle, success probability or uncharged initial state is assumed. The bound does not yet include the entire classical compiler or finite-bit angle synthesis.

Proof story

  1. Carry local coefficientsA degree-\(2k+1\) Bernstein vector represents the polynomial piece exactly. A boundary state decides when a dyadic interval enters that piece, and two small tail components handle the exponentials. This gives one consistent chain of width \(2k+6\) for every bit string.
  2. Normalize without a sample tableSmall local Gram matrices give exactly the full sample norm. Deterministic thin LQ turns the chain into norm-preserving local maps, retaining deficient and zero-rank cases and absorbing the signed first boundary.
  3. Compile and clean the memoryComplete only the reachable columns to a real unitary, turn each local unitary into selected rotations, and place their Ry/CNOT instructions on the physical wires. The proof covers all output amplitudes, including zero amplitude in every non-clean bond sector.
  4. Keep the remaining obligations visibleThe raw source now has an actual cached producer with a proved polynomial operation ledger. Stored normalization, LQ, completion and emission still need whole-compiler cost composition. Finite-bit input handling and uniform rounding remain open; finite QASM checks do not fill those gaps.
Show the Lean proof checkpoints

The mathematical explanation above is the reading layer. These compiled declarations are the proof authority.

4 · Classical source construction

Build a short chain, not an exponentially long sample list

\[D=2k+6,\qquad W_{\rm raw}=O(n_p(k+1)^3+n_p^2+(k+1)^2),\quad \#\exp\le3n_p+1.\]

The new raw-source producer computes and stores the coefficients, interval boundaries, tail factors and small core matrices. Lean proves that contracting its returned chain gives every original unnormalized sample. The cost bound belongs to this actual producer, not just to the size of a possible representation.

Proof story

  1. Cache shared workGenerate each reusable coefficient table and tail cache once; carry binary coordinates through the dyadic intervals.
  2. Keep the original branch testsOnly intervals wholly inside a source piece receive its injection. Both end contractions are retained, including the one-qubit case.
  3. Read the cost model carefullyThe bound counts declared exact-real operations plus separate exponential and selected integer calls. It does not prove finite-bit runtime or the total cost of compiling the final quantum circuit.
Show the Lean proof checkpoints

The mathematical explanation above is the reading layer. These compiled declarations are the proof authority.

5 · Conditional angle accuracy

A small error per rotation gives a controlled circuit error

\[\delta=\frac{\varepsilon}{24n_p(2k+6)^3},\qquad \|\widehat U-U\|_{2\to2}\le\varepsilon.\]

Keep every gate in the same position and on the same physical wires. If each changed Ry angle differs by at most delta, the entire constructed circuit differs by at most epsilon in Euclidean operator norm. The bound has no factor proportional to the number of amplitudes.

Proof story

  1. Control one actual gateThe Ry operator difference is exactly twice the absolute sine of one quarter of the angle difference, hence at most half the angle error.
  2. Add errors in circuit orderUnitary gates preserve the norm, so the ordered composition accumulates at most half the sum of the per-position angle errors.
  3. Do not confuse a budget with an implementationA supplied approximate circuit must satisfy that angle accuracy. This theorem does not calculate finite-precision angles, prove a floating-point exporter, or promise exact ancilla cleanup after rounding.
Show the Lean proof checkpoints

The mathematical explanation above is the reading layer. These compiled declarations are the proof authority.

6 · Read the evidence at the correct level

Exact real-angle gates and finite exported circuits answer different questions

\[U_k|0^n\rangle=|g_k\rangle_p,\qquad \|\widehat U_k|0^n\rangle-\widehat g_k\|_\infty\le\varepsilon_{\rm observed}.\]

The first identity is the symbolic acceptance target. The second is a measured error for a specified exported instance; the acceptance report supplies the parameters, backend versions and tolerances. The measured tolerance here is the maximum componentwise amplitude error, not a whole-vector Euclidean error.

Proof story

  1. Keep the real-angle semanticsThe generic controlled-rotation compiler preserves the mathematical gate matrix.
  2. Replay the emitted instructionsNumPy, Qiskit and QASM import all consume the actual elementary-gate list rather than a dense preparation black box.
  3. Respect the boundaryA small measured error supports that finite export. It neither proves a uniform floating-point bound nor a PDE convergence theorem.
Show the Lean proof checkpoints

The mathematical explanation above is the reading layer. These compiled declarations are the proof authority.

Diagrams and complete source packet

Complete construction and mathematical proof (LaTeX)

Complete construction and mathematical proof (LaTeX)
\documentclass[11pt]{article}
\usepackage{amsmath,amssymb,amsthm,geometry,hyperref}
\geometry{margin=1in}
\newtheorem{theorem}{Theorem}
\newtheorem{lemma}{Lemma}
\newcommand{\ket}[1]{\lvert #1\rangle}
\DeclareMathOperator{\atanTwo}{atan2}
\title{Preparing a Hermite-smoothed quantum initial state}
\author{ASPBE / QuantumComputinglib}
\date{}
\begin{document}
\maketitle

\section{The state, before the circuit}
Fix a nonnegative integer $k$, a register width $n\geq1$, and a truncation
parameter $L>0$. Put $N=2^n$ and $p_j=-\pi L+2\pi Lj/N$ for $0\leq j<N$.
The integer label uses little-endian weights:
$j=\sum_{r=0}^{n-1}2^rq_r$. Thus $q_0$ is the least significant bit,
while the printed ket is $\ket{q_{n-1}\cdots q_0}$.
The required function and quantum state are
\begin{align*}
g_k(p)&=\begin{cases}
 e^p,&p<-1,\\
 P_k(p),&-1\leq p\leq0,\\
 e^{-p},&p>0,
\end{cases}\\
Z_k&=\sum_{j=0}^{N-1}g_k(p_j)^2,
&\ket{g_k}_p&=Z_k^{-1/2}\sum_{j=0}^{N-1}g_k(p_j)\ket j.
\end{align*}
Here $P_k$ has degree at most $2k+1$ and satisfies
\[
P_k^{(a)}(-1)=e^{-1},\qquad P_k^{(a)}(0)=(-1)^a
\quad(0\leq a\leq k).
\]
These are the Hermite conditions in Jin--Liu--Ma,
\emph{Schr\"odingerisation based computationally stable algorithms for
ill-posed problems in partial differential equations},
\href{https://arxiv.org/html/2403.19123v3#S4.SS3}{arXiv:2403.19123v3,
Section 4.3, equations (4.31)--(4.32)}.
The amplitudes are $g_k(p_j)$, not their square roots. The probability of
observing label $j$ is $g_k(p_j)^2/Z_k$.

\section{An explicit polynomial, with no interpolation oracle}
For $0\leq r\leq k$, define
\[
a_{k,r}=\sum_{m=0}^{r}\frac{\binom{k+r-m}{k}}{m!},
\qquad A_k(t)=\sum_{r=0}^{k}a_{k,r}t^r.
\]
With $t=p+1$, set
\[
P_k(p)=e^{-1}(1-t)^{k+1}A_k(t)+t^{k+1}A_k(1-t).
\]
This explicit coefficient formula is the construction used by ASPBE; the
source paper specifies the endpoint conditions.

\begin{lemma}[Endpoint jets and uniqueness]
The displayed polynomial has degree at most $2k+1$ and satisfies all the
Hermite conditions above. No other polynomial of that degree does so.
\end{lemma}
\begin{proof}
The binomial series gives
$(1-t)^{-(k+1)}=\sum_{s\geq0}\binom{k+s}{k}t^s$.
The coefficient of $t^r$ in $e^t(1-t)^{-(k+1)}$ is therefore $a_{k,r}$.
Consequently $(1-t)^{k+1}A_k(t)$ and $e^t$ have identical coefficients
through degree $k$. The other summand contains the factor $t^{k+1}$,
so its first $k$ derivatives vanish at $t=0$. Multiplication by $e^{-1}$
gives the left endpoint values. At $t=1$, exchange $t$ and $1-t$;
each derivative contributes the appropriate factor $(-1)^a$.
Each product has degree at most $2k+1$.
If two interpolants exist, their difference has a zero of multiplicity
at least $k+1$ at both endpoints. It is divisible by
$p^{k+1}(p+1)^{k+1}$, of degree $2k+2$, so the difference is zero.
\end{proof}

\begin{lemma}[Positivity]
The function $g_k$ is positive on the real line; in particular $Z_k>0$.
\end{lemma}
\begin{proof}
All $a_{k,r}$ are positive. For $0<t<1$, both summands in $P_k$ are
positive. At the endpoints their values are $e^{-1}$ and $1$.
The two exterior exponentials are positive as well.
\end{proof}

For $k=1$ the formula reduces to
\[
P_1(p)=(-3+3e^{-1})p^3+(-5+4e^{-1})p^2-p+1.
\]
Its second derivative at zero is $-10+8e^{-1}\ne1$.
Thus the piecewise cubic is $C^1$, not $C^2$. The $C^2$ statement printed
after source equation (6.1) is not adopted here. This case certifies state
preparation; it does not certify the source paper's PDE error estimates.

\section{Construct the rotations from subtree masses}
Write $f_j=g_k(p_j)$. For a depth $d$ and low-bit label $s$, define
\[
m_{d,s}=\sum_{j\bmod 2^d=s}f_j^2,
\quad 0\leq d\leq n,\quad 0\leq s<2^d.
\]
The root mass is $m_{0,0}=Z_k$ and the leaves have $m_{n,j}=f_j^2$.
Partitioning each subtree by its next bit proves
\[
m_{d,s}=m_{d+1,s}+m_{d+1,s+2^d}.
\]
At layer $d$, controlled on $(q_0,\ldots,q_{d-1})$ representing $s$,
apply to $q_d$ the gate
\[
R_y(\theta_{d,s}),\qquad
\theta_{d,s}=2\atanTwo\bigl(\sqrt{m_{d+1,s+2^d}},
                                  \sqrt{m_{d+1,s}}\bigr).
\]
The convention is $R_y(\theta)=
\begin{pmatrix}\cos(\theta/2)&-\sin(\theta/2)\\
\sin(\theta/2)&\cos(\theta/2)\end{pmatrix}$.
For a zero-mass subtree the angle is zero. Its incoming amplitude is already
zero, so this choice does not alter the target.

\begin{theorem}[Deterministic preparation]
The product of these uniformly controlled rotations is unitary and maps
$\ket{0^n}$ to $\ket{g_k}_p$.
\end{theorem}
\begin{proof}
Each fixed control word selects a two-dimensional real rotation. Such a
rotation is orthogonal, hence unitary over the complex numbers. The selected
blocks act on orthogonal control subspaces, and their product is unitary.
After depth $d$ the state is
\[
\sum_{s=0}^{2^d-1}\sqrt{m_{d,s}/Z_k}\,
   \ket{0^{n-d}}\ket{s}.
\]
This holds initially. A rotation splits the amplitude of a parent according
to the square roots of its two child masses, proving the next depth.
At depth $n$, positivity gives $\sqrt{f_j^2}=f_j$, which is the claimed
normalized amplitude. There is no measurement or postselection.
\end{proof}

\section{Global smoothness and exact formal scope}
The endpoint jets also certify that the piecewise function belongs to
$C^k(\mathbb R)$. A generic gluing argument proceeds by induction on the
derivative order: equality of endpoint values gives continuity; equality
of the one-sided derivatives gives differentiability at the junction by
the slope-limit characterization. Applying the induction to the derivative
pieces gives the claim at both junctions.
This is the Lean theorem
\texttt{HermiteSmoothness.smoothInitial\_contDiff}.
The state-preparation root
\texttt{HermiteStatePreparation.hermiteStatePreparation\_complete}
separately certifies normalization, primitive-circuit action, unitarity and
gate counts. Neither root asserts a PDE discretization error, a Sobolev
estimate, or an error bound for machine-rounded angles.

\section{Elementary gates and resource accounting}
A uniformly controlled rotation is compiled recursively using half-sums
and half-differences of its angle table, separated by a CNOT and followed
by a second CNOT. For a control bit $b$, the identity
$X R_y(\beta)X=R_y(-\beta)$ makes the selected angle either
the sum or the difference of the two half-angles.
Induction on the number of controls proves equality of the full matrices.
The reference compiler has $2^d$ rotations and $2(2^d-1)$ CNOTs for $d$
controls. Summing over $d=0,\ldots,n-1$ gives
\[
\#R_y=N-1,\qquad \#\mathrm{CNOT}=2(N-1-n),
\qquad G=3(N-1)-2n.
\]
No auxiliary qubits or state-preparation oracle calls are used. These
counts concern this reference compiler, not an optimality theorem.
Classical coefficient evaluation, sample evaluation, mass reduction and
angle calculation are part of the construction cost. Floating-point
evaluation and angle synthesis are separate from ideal real-angle gates.

\section{Reproduce and inspect the evidence}
The case page links complete Lean modules, the executable generator,
OpenQASM output, a gate diagram, and the numerical acceptance report.
The numerical report records independent NumPy, Qiskit and OpenQASM replay
for finite parameter choices. Those tolerances are not substitutes for
the symbolic Lean state-action theorem. Likewise, the general exact gate
theorem does not assert that machine-rounded rotation angles have zero error.
Every public compilation claim is checked against the repository's current
Lean build before deployment.
\end{document}

Hermite polynomial: complete Lean source

Hermite polynomial: complete Lean source
import Mathlib.Analysis.SpecialFunctions.ExpDeriv
import Mathlib.Analysis.Calculus.Deriv.Polynomial
import Mathlib.Analysis.Calculus.IteratedDeriv.Lemmas
import Mathlib.Algebra.Polynomial.Taylor
import Mathlib.Algebra.Polynomial.FieldDivision
import Mathlib.RingTheory.PowerSeries.Exp
import Mathlib.RingTheory.PowerSeries.WellKnown
import Mathlib.RingTheory.PowerSeries.Trunc
import Mathlib.Tactic

/-!
# Two-point Hermite interpolation for smooth initial data

The source polynomial `sourceInterpolant` is the positive closed form obtained
by truncating `exp(X)/(1-X)^(k+1)`. All endpoint jets and positivity are proved
from its coefficients. An independent extended-Euclid construction is retained
as a reusable two-point interpolation interface. The source contract is the
smooth initial datum in arXiv:2403.19123v3, Section 4.3, equations (4.31)-(4.32).
-/

noncomputable section

open Polynomial

namespace QuantumBlockEncoding.HermitePolynomial

/-- The truncated Taylor polynomial with the prescribed ordinary derivatives. -/
def jetPolynomial (a : ℝ) (k : ℕ) (v : ℕ → ℝ) : ℝ[X] :=
  taylor (-a) (∑ j ∈ Finset.range (k + 1), monomial j (v j / (j.factorial : ℝ)))

/-- Convert Taylor coefficients to ordinary iterated derivatives. -/
theorem eval_iterate_derivative (p : ℝ[X]) (a : ℝ) (j : ℕ) :
    (derivative^[j] p).eval a = (j.factorial : ℝ) * (taylor a p).coeff j := by
  rw [taylor_coeff, ← factorial_smul_hasseDeriv]
  simp [nsmul_eq_mul]

/-- Every requested jet is realized by its local Taylor polynomial. -/
theorem jetPolynomial_jet (a : ℝ) (k j : ℕ) (v : ℕ → ℝ) (hj : j ≤ k) :
    (derivative^[j] (jetPolynomial a k v)).eval a = v j := by
  rw [eval_iterate_derivative]
  simp only [jetPolynomial, taylor_taylor, add_neg_cancel, taylor_zero]
  rw [finset_sum_coeff]
  simp only [coeff_monomial]
  rw [Finset.sum_eq_single j]
  · simp only [ite_true]
    field_simp
  · intro b hb hbj
    simp [hbj]
  · simp [Finset.mem_range, Nat.lt_succ_of_le hj]

/-- A high-multiplicity zero preserves all derivatives below the multiplicity. -/
theorem jet_eq_of_pow_dvd_sub (p q : ℝ[X]) (a : ℝ) (k j : ℕ)
    (hj : j ≤ k) (h : (X - C a) ^ (k + 1) ∣ p - q) :
    (derivative^[j] p).eval a = (derivative^[j] q).eval a := by
  have hd := pow_sub_dvd_iterate_derivative_of_pow_dvd j h
  have hj' : 1 ≤ k + 1 - j := by omega
  have hx' : X - C a ∣ (X - C a) ^ (k + 1 - j) := by
    simpa only [pow_one] using (pow_dvd_pow (X - C a) hj')
  have hx : X - C a ∣ derivative^[j] (p - q) := hx'.trans hd
  obtain ⟨r, hr⟩ := hx
  have he := congrArg (fun f : ℝ[X] => f.eval a) hr
  simpa [iterate_derivative_sub, sub_eq_zero] using he

/-- The inverse constant that normalizes the extended-gcd identity. -/
def bezoutNormalizer (A B : ℝ[X]) : ℝ[X] :=
  C ((EuclideanDomain.gcd A B).coeff 0)⁻¹

theorem bezoutNormalizer_gcd (A B : ℝ[X]) (h : IsCoprime A B) :
    bezoutNormalizer A B * EuclideanDomain.gcd A B = 1 := by
  have hg : IsUnit (EuclideanDomain.gcd A B) :=
    EuclideanDomain.gcd_isUnit_iff.mpr h
  obtain ⟨r, hr, hgr⟩ := Polynomial.isUnit_iff.mp hg
  unfold bezoutNormalizer
  rw [← hgr]
  simp only [coeff_C_zero, ← C_mul, inv_mul_cancel₀ hr.ne_zero, C_1]

/-- An explicit Chinese-remainder interpolant, using extended Euclid. -/
def twoPointInterpolant (A B u v : ℝ[X]) : ℝ[X] :=
  (bezoutNormalizer A B *
    (B * EuclideanDomain.gcdB A B * u + A * EuclideanDomain.gcdA A B * v)) %
    (A * B)

theorem twoPointInterpolant_left (A B u v : ℝ[X]) (h : IsCoprime A B) :
    A ∣ twoPointInterpolant A B u v - u := by
  have he : bezoutNormalizer A B *
      (A * EuclideanDomain.gcdA A B + B * EuclideanDomain.gcdB A B) = 1 := by
    rw [← EuclideanDomain.gcd_eq_gcd_ab]
    exact bezoutNormalizer_gcd A B h
  unfold twoPointInterpolant
  rw [EuclideanDomain.mod_eq_sub_mul_div]
  refine ⟨bezoutNormalizer A B * EuclideanDomain.gcdA A B * (v - u) -
    B * ((bezoutNormalizer A B *
      (B * EuclideanDomain.gcdB A B * u + A * EuclideanDomain.gcdA A B * v)) /
      (A * B)), ?_⟩
  calc
    _ = _ - u * (bezoutNormalizer A B *
        (A * EuclideanDomain.gcdA A B + B * EuclideanDomain.gcdB A B)) := by
      rw [he, mul_one]
    _ = _ := by ring

theorem twoPointInterpolant_right (A B u v : ℝ[X]) (h : IsCoprime A B) :
    B ∣ twoPointInterpolant A B u v - v := by
  have he : bezoutNormalizer A B *
      (A * EuclideanDomain.gcdA A B + B * EuclideanDomain.gcdB A B) = 1 := by
    rw [← EuclideanDomain.gcd_eq_gcd_ab]
    exact bezoutNormalizer_gcd A B h
  unfold twoPointInterpolant
  rw [EuclideanDomain.mod_eq_sub_mul_div]
  refine ⟨bezoutNormalizer A B * EuclideanDomain.gcdB A B * (u - v) -
    A * ((bezoutNormalizer A B *
      (B * EuclideanDomain.gcdB A B * u + A * EuclideanDomain.gcdA A B * v)) /
      (A * B)), ?_⟩
  calc
    _ = _ - v * (bezoutNormalizer A B *
        (A * EuclideanDomain.gcdA A B + B * EuclideanDomain.gcdB A B)) := by
      rw [he, mul_one]
    _ = _ := by ring

/-- The multiplicity polynomial for the endpoint `-1`. -/
def leftModulus (k : ℕ) : ℝ[X] := (X - C (-1)) ^ (k + 1)

/-- The multiplicity polynomial for the endpoint `0`. -/
def rightModulus (k : ℕ) : ℝ[X] := (X - C 0) ^ (k + 1)

theorem endpointModuli_coprime (k : ℕ) : IsCoprime (leftModulus k) (rightModulus k) := by
  apply IsCoprime.pow
  exact isCoprime_X_sub_C_of_isUnit_sub (by norm_num)

/-- The degree-bounded polynomial joining the jets of `exp p` and `exp (-p)`. -/
def interpolant (k : ℕ) : ℝ[X] :=
  twoPointInterpolant (leftModulus k) (rightModulus k)
    (jetPolynomial (-1) k (fun _ => Real.exp (-1)))
    (jetPolynomial 0 k (fun j => (-1 : ℝ) ^ j))

/-- All derivatives through order `k` at `-1` equal `exp (-1)`. -/
theorem interpolant_left_jet (k j : ℕ) (hj : j ≤ k) :
    (derivative^[j] (interpolant k)).eval (-1) = Real.exp (-1) := by
  rw [jet_eq_of_pow_dvd_sub _ (jetPolynomial (-1) k (fun _ => Real.exp (-1)))
    (-1) k j hj]
  · exact jetPolynomial_jet (-1) k j _ hj
  · exact twoPointInterpolant_left _ _ _ _ (endpointModuli_coprime k)

/-- All derivatives through order `k` at `0` equal `(-1)^j`. -/
theorem interpolant_right_jet (k j : ℕ) (hj : j ≤ k) :
    (derivative^[j] (interpolant k)).eval 0 = (-1 : ℝ) ^ j := by
  rw [jet_eq_of_pow_dvd_sub _ (jetPolynomial 0 k (fun j => (-1 : ℝ) ^ j)) 0 k j hj]
  · exact jetPolynomial_jet 0 k j _ hj
  · exact twoPointInterpolant_right _ _ _ _ (endpointModuli_coprime k)

/-- The construction has the minimal Hermite degree bound. -/
theorem interpolant_degree (k : ℕ) : (interpolant k).natDegree ≤ 2 * k + 1 := by
  have hdeg : (leftModulus k * rightModulus k).natDegree = 2 * k + 2 := by
    unfold leftModulus rightModulus
    rw [natDegree_mul (pow_ne_zero _ (X_sub_C_ne_zero _))
      (pow_ne_zero _ (X_sub_C_ne_zero _))]
    simp only [natDegree_pow, natDegree_X_sub_C, mul_one]
    omega
  have h := natDegree_mod_lt
    (bezoutNormalizer (leftModulus k) (rightModulus k) *
      (rightModulus k * EuclideanDomain.gcdB (leftModulus k) (rightModulus k) *
        jetPolynomial (-1) k (fun _ => Real.exp (-1)) +
      leftModulus k * EuclideanDomain.gcdA (leftModulus k) (rightModulus k) *
        jetPolynomial 0 k (fun j => (-1 : ℝ) ^ j)))
    (q := leftModulus k * rightModulus k) (by omega)
  rw [hdeg] at h
  exact Nat.le_of_lt_succ (by simpa [interpolant, twoPointInterpolant, Nat.add_assoc] using h)

/-- The generating series whose first `k+1` coefficients are the source's `a_{k,r}`. -/
def coefficientSeries (k : ℕ) : PowerSeries ℝ :=
  PowerSeries.exp ℝ * (PowerSeries.invOneSubPow ℝ (k + 1)).val

/-- The exact polynomial `A_k`, implemented as a finite Taylor truncation. -/
def coefficientPolynomial (k : ℕ) : ℝ[X] :=
  PowerSeries.trunc (k + 1) (coefficientSeries k)

/-- One endpoint cardinal factor in the symmetric closed-form Hermite formula. -/
def endpointFactor (k : ℕ) : ℝ[X] := (1 - X) ^ (k + 1) * coefficientPolynomial k

/-- The source closed form, in the coordinate `t = p + 1`. -/
def sourceInterpolant (k : ℕ) : ℝ[X] :=
  taylor 1 (C (Real.exp (-1)) * endpointFactor k +
    (endpointFactor k).comp (1 - X))

theorem coefficientSeries_coeff (k r : ℕ) :
    PowerSeries.coeff r (coefficientSeries k) =
      ∑ m ∈ Finset.range (r + 1), (Nat.choose (k + r - m) k : ℝ) /
        (m.factorial : ℝ) := by
  simp only [coefficientSeries, PowerSeries.coeff_mul,
    PowerSeries.invOneSubPow_val_succ_eq_mk_add_choose, PowerSeries.coeff_mk,
    PowerSeries.coeff_exp]
  rw [Finset.Nat.sum_antidiagonal_eq_sum_range_succ_mk]
  apply Finset.sum_congr rfl
  intro m hm
  have hm' : m ≤ r := by simpa using hm
  simp [Nat.add_sub_assoc hm', div_eq_mul_inv, mul_comm]

theorem coefficientSeries_coeff_nonneg (k r : ℕ) :
    0 ≤ PowerSeries.coeff r (coefficientSeries k) := by
  rw [coefficientSeries_coeff]
  exact Finset.sum_nonneg fun _ _ => div_nonneg (Nat.cast_nonneg _) (Nat.cast_nonneg _)

@[simp] theorem coefficientSeries_coeff_zero (k : ℕ) :
    PowerSeries.coeff 0 (coefficientSeries k) = 1 := by
  simp [coefficientSeries_coeff]

theorem endpointFactor_series_trunc (k : ℕ) :
    PowerSeries.trunc (k + 1) (endpointFactor k : PowerSeries ℝ) =
      PowerSeries.trunc (k + 1) (PowerSeries.exp ℝ) := by
  have hi : ((1 - PowerSeries.X : PowerSeries ℝ) ^ (k + 1)) *
      (PowerSeries.invOneSubPow ℝ (k + 1)).val = 1 :=
    (PowerSeries.invOneSubPow ℝ (k + 1)).inv_val
  simp only [endpointFactor, coefficientPolynomial, Polynomial.coe_mul,
    Polynomial.coe_pow, Polynomial.coe_sub, Polynomial.coe_one, Polynomial.coe_X,
    PowerSeries.trunc_mul_trunc, coefficientSeries]
  rw [mul_left_comm, hi, mul_one]

theorem endpointFactor_coeff (k j : ℕ) (hj : j ≤ k) :
    (endpointFactor k).coeff j = 1 / (j.factorial : ℝ) := by
  have he := congrArg (fun p : ℝ[X] => p.coeff j) (endpointFactor_series_trunc k)
  simpa [PowerSeries.coeff_trunc, Nat.lt_succ_of_le hj] using he

theorem endpointFactor_zero_jet (k j : ℕ) (hj : j ≤ k) :
    (derivative^[j] (endpointFactor k)).eval 0 = 1 := by
  rw [eval_iterate_derivative, taylor_zero, endpointFactor_coeff k j hj]
  simp [Nat.factorial_ne_zero]

theorem endpointFactor_one_jet (k j : ℕ) (hj : j ≤ k) :
    (derivative^[j] (endpointFactor k)).eval 1 = 0 := by
  have hf : (X - C (1 : ℝ)) ^ (k + 1) ∣ endpointFactor k - 0 := by
    refine ⟨(-1) ^ (k + 1) * coefficientPolynomial k, ?_⟩
    simp only [endpointFactor, sub_zero, C_1]
    rw [← mul_assoc, ← mul_pow]
    congr 2
    ring
  simpa using jet_eq_of_pow_dvd_sub (endpointFactor k) 0 1 k j hj hf

theorem sourceInterpolant_left_jet (k j : ℕ) (hj : j ≤ k) :
    (derivative^[j] (sourceInterpolant k)).eval (-1) = Real.exp (-1) := by
  rw [eval_iterate_derivative]
  simp only [sourceInterpolant, taylor_taylor, neg_add_cancel, taylor_zero]
  rw [← taylor_zero (C (Real.exp (-1)) * endpointFactor k +
    (endpointFactor k).comp (1 - X)), ← eval_iterate_derivative]
  rw [iterate_map_add, iterate_derivative_C_mul, iterate_derivative_comp_one_sub_X]
  simp [endpointFactor_zero_jet k j hj, endpointFactor_one_jet k j hj]

theorem sourceInterpolant_right_jet (k j : ℕ) (hj : j ≤ k) :
    (derivative^[j] (sourceInterpolant k)).eval 0 = (-1 : ℝ) ^ j := by
  rw [eval_iterate_derivative]
  simp only [sourceInterpolant, taylor_taylor, zero_add]
  rw [← eval_iterate_derivative]
  rw [iterate_map_add, iterate_derivative_C_mul, iterate_derivative_comp_one_sub_X]
  simp [endpointFactor_zero_jet k j hj, endpointFactor_one_jet k j hj]

theorem coefficientPolynomial_pos (k : ℕ) (t : ℝ) (ht : 0 ≤ t) :
    0 < (coefficientPolynomial k).eval t := by
  have hsum : (coefficientPolynomial k).eval t =
      ∑ r ∈ Finset.range (k + 1), PowerSeries.coeff r (coefficientSeries k) * t ^ r :=
    PowerSeries.eval₂_trunc_eq_sum_range t (RingHom.id ℝ) (k + 1) (coefficientSeries k)
  rw [hsum]
  have h := Finset.single_le_sum
    (f := fun r => PowerSeries.coeff r (coefficientSeries k) * t ^ r)
    (fun r _ => mul_nonneg (coefficientSeries_coeff_nonneg k r) (pow_nonneg ht r))
    (show 0 ∈ Finset.range (k + 1) by simp)
  simp only [coefficientSeries_coeff_zero, pow_zero, mul_one] at h
  linarith

theorem sourceInterpolant_pos (k : ℕ) (p : ℝ) (hp : p ∈ Set.Icc (-1) 0) :
    0 < (sourceInterpolant k).eval p := by
  have h0 : 0 ≤ p + 1 := by linarith [hp.1]
  have h1 : 0 ≤ 1 - (p + 1) := by linarith [hp.2]
  have ha := coefficientPolynomial_pos k (p + 1) h0
  have hb := coefficientPolynomial_pos k (1 - (p + 1)) h1
  simp only [sourceInterpolant, taylor_eval, eval_add, eval_mul, eval_C, eval_comp,
    eval_sub, eval_one, eval_X, endpointFactor, eval_pow]
  have he := Real.exp_pos (-1)
  by_cases hz : p + 1 = 0
  · simp only [hz, sub_zero, one_pow, one_mul, zero_pow (Nat.succ_ne_zero k),
      sub_self, zero_mul, add_zero]
    exact mul_pos he (coefficientPolynomial_pos k 0 le_rfl)
  · have ht : 0 < p + 1 := lt_of_le_of_ne h0 (Ne.symm hz)
    have hright : 0 < (1 - (1 - (p + 1))) ^ (k + 1) *
        (coefficientPolynomial k).eval (1 - (p + 1)) := by
      apply mul_pos _ hb
      simpa [add_comm] using pow_pos ht (k + 1)
    exact add_pos_of_nonneg_of_pos
      (mul_nonneg he.le (mul_nonneg (pow_nonneg h1 _) ha.le)) hright

/-- The coefficient polynomial is exactly the finite sum in the closed form. -/
theorem coefficientPolynomial_eval (k : ℕ) (t : ℝ) :
    (coefficientPolynomial k).eval t =
      ∑ r ∈ Finset.range (k + 1),
        (∑ m ∈ Finset.range (r + 1), (Nat.choose (k + r - m) k : ℝ) /
          (m.factorial : ℝ)) * t ^ r := by
  rw [coefficientPolynomial, Polynomial.eval, PowerSeries.eval₂_trunc_eq_sum_range]
  simp only [RingHom.id_apply, coefficientSeries_coeff]

/-- Source formula with the coordinate convention `t = p + 1` made explicit. -/
theorem sourceInterpolant_eval (k : ℕ) (p : ℝ) :
    (sourceInterpolant k).eval p =
      Real.exp (-1) * (1 - (p + 1)) ^ (k + 1) *
        (coefficientPolynomial k).eval (p + 1) +
      (p + 1) ^ (k + 1) * (coefficientPolynomial k).eval (1 - (p + 1)) := by
  simp only [sourceInterpolant, endpointFactor, taylor_eval, eval_add, eval_mul,
    eval_C, eval_pow, eval_sub, eval_one, eval_X, eval_comp]
  congr 1
  · ring
  · congr 2
    ring

theorem coefficientPolynomial_degree (k : ℕ) : (coefficientPolynomial k).natDegree ≤ k :=
  Nat.le_of_lt_succ (PowerSeries.natDegree_trunc_lt (coefficientSeries k) k)

theorem endpointFactor_degree (k : ℕ) : (endpointFactor k).natDegree ≤ 2 * k + 1 := by
  have hs : (1 - X : ℝ[X]).natDegree = 1 := by
    rw [← natDegree_neg]
    simpa using (natDegree_X_sub_C (1 : ℝ))
  have h := natDegree_mul_le (p := (1 - X : ℝ[X]) ^ (k + 1))
    (q := coefficientPolynomial k)
  rw [natDegree_pow, hs, mul_one] at h
  have ha := coefficientPolynomial_degree k
  exact (show (endpointFactor k).natDegree ≤ (k + 1) + (coefficientPolynomial k).natDegree
    from h).trans (by omega)

/-- The source closed form has degree at most `2k+1`. -/
theorem sourceInterpolant_degree (k : ℕ) : (sourceInterpolant k).natDegree ≤ 2 * k + 1 := by
  rw [sourceInterpolant, natDegree_taylor]
  apply natDegree_add_le_of_degree_le
  · exact (natDegree_C_mul_le _ _).trans (endpointFactor_degree k)
  · have hs : (1 - X : ℝ[X]).natDegree = 1 := by
      rw [← natDegree_neg]
      simpa using (natDegree_X_sub_C (1 : ℝ))
    simpa [natDegree_comp, hs] using endpointFactor_degree k

/-- Algebraic and analytic repeated differentiation agree for real polynomials. -/
theorem iteratedDeriv_polynomial (p : ℝ[X]) (j : ℕ) (x : ℝ) :
    iteratedDeriv j (fun y => p.eval y) x = (derivative^[j] p).eval x := by
  induction j generalizing p with
  | zero => rfl
  | succ j ih =>
    rw [iteratedDeriv_succ']
    have he : deriv (fun y => p.eval y) = fun y => p.derivative.eval y := by
      funext y
      exact p.deriv
    rw [he, ih, Function.iterate_succ_apply]

theorem sourceInterpolant_left_iteratedDeriv (k j : ℕ) (hj : j ≤ k) :
    iteratedDeriv j (fun p => (sourceInterpolant k).eval p) (-1) = Real.exp (-1) := by
  rw [iteratedDeriv_polynomial]
  exact sourceInterpolant_left_jet k j hj

theorem sourceInterpolant_right_iteratedDeriv (k j : ℕ) (hj : j ≤ k) :
    iteratedDeriv j (fun p => (sourceInterpolant k).eval p) 0 = (-1 : ℝ) ^ j := by
  rw [iteratedDeriv_polynomial]
  exact sourceInterpolant_right_jet k j hj

/-- The literal piecewise initial datum: left exponential, Hermite bridge, right exponential. -/
def smoothInitial (k : ℕ) (p : ℝ) : ℝ :=
  if p < -1 then Real.exp p else
    if p ≤ 0 then (sourceInterpolant k).eval p else Real.exp (-p)

theorem smoothInitial_left (k : ℕ) (p : ℝ) (hp : p < -1) :
    smoothInitial k p = Real.exp p := by simp [smoothInitial, hp]

theorem smoothInitial_middle (k : ℕ) (p : ℝ) (hp : p ∈ Set.Icc (-1) 0) :
    smoothInitial k p = (sourceInterpolant k).eval p := by
  simp [smoothInitial, not_lt.mpr hp.1, hp.2]

theorem smoothInitial_right (k : ℕ) (p : ℝ) (hp : 0 < p) :
    smoothInitial k p = Real.exp (-p) := by
  simp [smoothInitial, not_lt.mpr (show -1 ≤ p by linarith), not_le.mpr hp]

/-- Strict positivity holds globally and makes every finite sampled norm nonzero. -/
theorem smoothInitial_pos (k : ℕ) (p : ℝ) : 0 < smoothInitial k p := by
  unfold smoothInitial
  split_ifs with hl hr
  · exact Real.exp_pos p
  · exact sourceInterpolant_pos k p ⟨not_lt.mp hl, hr⟩
  · exact Real.exp_pos (-p)

/-- Agreement of a finite jet is equivalent to divisibility by the endpoint multiplicity. -/
theorem pow_dvd_sub_of_jet_eq (p q : ℝ[X]) (a : ℝ) (k : ℕ)
    (h : ∀ j ≤ k, (derivative^[j] p).eval a = (derivative^[j] q).eval a) :
    (X - C a) ^ (k + 1) ∣ p - q := by
  have ht : X ^ (k + 1) ∣ taylor a (p - q) := by
    apply X_pow_dvd_iff.mpr
    intro j hj
    have he : (j.factorial : ℝ) * (taylor a (p - q)).coeff j = 0 := by
      rw [← eval_iterate_derivative]
      simp only [iterate_derivative_sub, eval_sub, h j (by omega), sub_self]
    exact (mul_eq_zero.mp he).resolve_left (by exact_mod_cast Nat.factorial_ne_zero j)
  have hm := map_dvd (taylorAlgHom (-a)) ht
  simpa [taylor_taylor, ← sub_eq_add_neg] using hm

/-- There is only one degree-bounded polynomial with the source endpoint jets. -/
theorem sourceInterpolant_unique (k : ℕ) (p : ℝ[X]) (hp : p.natDegree ≤ 2 * k + 1)
    (hl : ∀ j ≤ k, (derivative^[j] p).eval (-1) = Real.exp (-1))
    (hr : ∀ j ≤ k, (derivative^[j] p).eval 0 = (-1 : ℝ) ^ j) :
    p = sourceInterpolant k := by
  have hleft : leftModulus k ∣ p - sourceInterpolant k :=
    pow_dvd_sub_of_jet_eq p (sourceInterpolant k) (-1) k
      (fun j hj => (hl j hj).trans (sourceInterpolant_left_jet k j hj).symm)
  have hright : rightModulus k ∣ p - sourceInterpolant k :=
    pow_dvd_sub_of_jet_eq p (sourceInterpolant k) 0 k
      (fun j hj => (hr j hj).trans (sourceInterpolant_right_jet k j hj).symm)
  have hdiv := (endpointModuli_coprime k).mul_dvd hleft hright
  by_contra hne
  have hd := natDegree_le_of_dvd hdiv (sub_ne_zero.mpr hne)
  have hm : (leftModulus k * rightModulus k).natDegree = 2 * k + 2 := by
    unfold leftModulus rightModulus
    rw [natDegree_mul (pow_ne_zero _ (X_sub_C_ne_zero _))
      (pow_ne_zero _ (X_sub_C_ne_zero _))]
    simp only [natDegree_pow, natDegree_X_sub_C, mul_one]
    omega
  have hb := (natDegree_sub_le p (sourceInterpolant k)).trans
    (max_le hp (sourceInterpolant_degree k))
  rw [hm] at hd
  omega

/-- The Euclidean-algorithm construction and the positive source formula agree exactly. -/
theorem interpolant_eq_sourceInterpolant (k : ℕ) : interpolant k = sourceInterpolant k :=
  sourceInterpolant_unique k (interpolant k) (interpolant_degree k)
    (interpolant_left_jet k) (interpolant_right_jet k)

end QuantumBlockEncoding.HermitePolynomial

Generic amplitude preparation: complete Lean source

Generic amplitude preparation: complete Lean source
import QuantumBlockEncoding.UniformlyControlledRy
import QuantumBlockEncoding.PrimitiveBasisLE
import QuantumBlockEncoding.StatePreparation

/-!
# Constructive preparation of finite real amplitude tables

Wires are ordered little-endian. The recursive construction prepares the
low-wire marginal norms first, then splits each marginal with a uniformly
controlled rotation on the new highest wire. The angles are exact real
expressions; finite numerical export is a separate evaluation obligation.
-/

namespace QuantumBlockEncoding.RealAmplitudePreparation

open Robin.ComplexLCU
open scoped Kronecker

/-- Adjoin a most-significant bit; existing wire numbers do not change. -/
def lastBasisEquiv (n : Nat) : PrimitiveBasis (n + 1) ≃ PrimitiveBasis n × Fin 2 :=
  (Fin.snocEquiv (fun _ : Fin (n + 1) => Fin 2)).symm.trans (Equiv.prodComm _ _)

@[simp] theorem lastBasisEquiv_apply {n : Nat} (b : PrimitiveBasis (n + 1)) :
    lastBasisEquiv n b = (Fin.init b, b (Fin.last n)) := rfl

@[simp] theorem lastBasisEquiv_symm_apply {n : Nat} (b : PrimitiveBasis n) (v : Fin 2) :
    (lastBasisEquiv n).symm (b, v) = Fin.snoc b v := rfl

theorem basis_eq_iff {n : Nat} (a b : PrimitiveBasis (n + 1)) :
    a = b ↔ Fin.init a = Fin.init b ∧ a (Fin.last n) = b (Fin.last n) := by
  rw [← (lastBasisEquiv n).injective.eq_iff]
  simp

/-- Tensor a circuit matrix with an untouched highest wire. -/
noncomputable def liftLastMatrix {n : Nat}
    (M : _root_.Matrix (PrimitiveBasis n) (PrimitiveBasis n) ℂ) :
    _root_.Matrix (PrimitiveBasis (n + 1)) (PrimitiveBasis (n + 1)) ℂ :=
  _root_.Matrix.reindexAlgEquiv ℂ ℂ (lastBasisEquiv n).symm
    (M ⊗ₖ (1 : _root_.Matrix (Fin 2) (Fin 2) ℂ))

@[simp] theorem liftLastMatrix_apply {n : Nat}
    (M : _root_.Matrix (PrimitiveBasis n) (PrimitiveBasis n) ℂ)
    (a b : PrimitiveBasis (n + 1)) :
    liftLastMatrix M a b =
      if a (Fin.last n) = b (Fin.last n) then M (Fin.init a) (Fin.init b) else 0 := by
  simp [liftLastMatrix, _root_.Matrix.reindexAlgEquiv_apply,
    _root_.Matrix.reindex_apply, _root_.Matrix.submatrix_apply,
    _root_.Matrix.one_apply, mul_ite]

@[simp] theorem liftLastMatrix_one (n : Nat) :
    liftLastMatrix (1 : _root_.Matrix (PrimitiveBasis n) (PrimitiveBasis n) ℂ) = 1 := by
  simp [liftLastMatrix]

theorem liftLastMatrix_mul {n : Nat}
    (M N : _root_.Matrix (PrimitiveBasis n) (PrimitiveBasis n) ℂ) :
    liftLastMatrix (M * N) = liftLastMatrix M * liftLastMatrix N := by
  simp [liftLastMatrix, ← _root_.Matrix.mul_kronecker_mul]

/-- Embed every instruction without changing its original wire number. -/
def liftGate {n : Nat} : PrimitiveGate n → PrimitiveGate (n + 1)
  | .x t => .x t.castSucc
  | .ry t a => .ry t.castSucc a
  | .rz t a => .rz t.castSucc a
  | .cx c t h => .cx c.castSucc t.castSucc (fun e => h (Fin.castSucc_injective _ e))

private theorem split_castSucc_eq {n : Nat} (t : Fin n)
    (a b : PrimitiveBasis (n + 1)) :
    (splitPrimitiveWire t.castSucc a).2 = (splitPrimitiveWire t.castSucc b).2 ↔
      (splitPrimitiveWire t (Fin.init a)).2 = (splitPrimitiveWire t (Fin.init b)).2 ∧
      a (Fin.last n) = b (Fin.last n) := by
  constructor
  · intro h
    constructor
    · funext w
      exact congrFun h ⟨w.1.castSucc, by simpa using w.2⟩
    · exact congrFun h ⟨Fin.last n, Ne.symm (Fin.castSucc_ne_last t)⟩
  · rintro ⟨h, hl⟩
    funext w
    obtain ⟨w, hw⟩ := w
    change a w = b w
    revert hw
    refine Fin.lastCases ?_ (fun i => ?_) w
    · intro _; exact hl
    · intro hi
      exact congrFun h ⟨i, by simpa using hi⟩

theorem lift_oneQubit {n : Nat} (t : Fin n)
    (M : _root_.Matrix (Fin 2) (Fin 2) ℂ) :
    liftPrimitiveOneQubit t.castSucc M = liftLastMatrix (liftPrimitiveOneQubit t M) := by
  ext a b
  simp only [liftPrimitiveOneQubit_apply, liftLastMatrix_apply, split_castSucc_eq]
  by_cases hc : (splitPrimitiveWire t (Fin.init a)).2 =
      (splitPrimitiveWire t (Fin.init b)).2 <;>
    by_cases hl : a (Fin.last n) = b (Fin.last n) <;>
    simp [hc, hl, Fin.init]

private theorem xBasis_lift {n : Nat} (t : Fin n) (b : PrimitiveBasis (n + 1)) :
    Fin.init (xBasisAction t.castSucc b) = xBasisAction t (Fin.init b) := by
  funext i
  simp [xBasisAction, Fin.init, Function.update_apply]

private theorem cxBasis_lift {n : Nat} (c t : Fin n) (b : PrimitiveBasis (n + 1)) :
    Fin.init (cxBasisAction c.castSucc t.castSucc b) =
      cxBasisAction c t (Fin.init b) := by
  by_cases h : b c.castSucc = 0 <;>
    simp [cxBasisAction, h, Fin.init, xBasis_lift]

theorem eval_liftGate {n : Nat} (g : PrimitiveGate n) :
    evalPrimitiveGate (liftGate g) = liftLastMatrix (evalPrimitiveGate g) := by
  cases g with
  | ry t a => exact lift_oneQubit t _
  | rz t a => exact lift_oneQubit t _
  | x t =>
    ext a b
    simp only [liftGate, evalPrimitiveGate, equivPermutationMatrix, liftLastMatrix_apply]
    change (if a = xBasisAction t.castSucc b then 1 else 0) =
      if a (Fin.last n) = b (Fin.last n) then
        if Fin.init a = xBasisAction t (Fin.init b) then 1 else 0 else 0
    have hl : xBasisAction t.castSucc b (Fin.last n) = b (Fin.last n) := by
      simp [xBasisAction, Ne.symm (Fin.castSucc_ne_last t)]
    simp only [basis_eq_iff, xBasis_lift, hl]
    by_cases h : a (Fin.last n) = b (Fin.last n) <;> simp [h]
  | cx c t h =>
    ext a b
    simp only [liftGate, evalPrimitiveGate, equivPermutationMatrix, liftLastMatrix_apply]
    change (if a = cxBasisAction c.castSucc t.castSucc b then 1 else 0) =
      if a (Fin.last n) = b (Fin.last n) then
        if Fin.init a = cxBasisAction c t (Fin.init b) then 1 else 0 else 0
    have hl : cxBasisAction c.castSucc t.castSucc b (Fin.last n) = b (Fin.last n) := by
      by_cases hc : b c.castSucc = 0 <;>
        simp [cxBasisAction, hc, xBasisAction, Ne.symm (Fin.castSucc_ne_last t)]
    simp only [basis_eq_iff, cxBasis_lift, hl]
    by_cases h : a (Fin.last n) = b (Fin.last n) <;> simp [h]

theorem eval_liftCircuit {n : Nat} (c : PrimitiveCircuit n) :
    evalPrimitiveCircuit (c.map liftGate) = liftLastMatrix (evalPrimitiveCircuit c) := by
  induction c with
  | nil => simp [evalPrimitiveCircuit]
  | cons g c ih =>
    simp only [List.map_cons, evalPrimitiveCircuit, ih, eval_liftGate, liftLastMatrix_mul]

/-- Euclidean mass at one binary split. -/
noncomputable def pairNorm (a b : ℝ) : ℝ := Real.sqrt (a ^ 2 + b ^ 2)

theorem pairNorm_nonneg (a b : ℝ) : 0 ≤ pairNorm a b := Real.sqrt_nonneg _

theorem pairNorm_sq (a b : ℝ) : pairNorm a b ^ 2 = a ^ 2 + b ^ 2 := by
  exact Real.sq_sqrt (add_nonneg (sq_nonneg a) (sq_nonneg b))

/-- Twice the signed polar angle, with the zero subtree assigned angle zero.
The arccos formula avoids an unverified numerical `atan2` primitive. -/
noncomputable def splitAngle (a b : ℝ) : ExactAngle :=
  if pairNorm a b = 0 then .rational 0 else
    .real (2 * if b < 0 then -Real.arccos (a / pairNorm a b)
      else Real.arccos (a / pairNorm a b))

theorem splitAngle_firstColumn (a b : ℝ) (v : Fin 2) :
    standardRyMatrix (splitAngle a b).eval v 0 * (pairNorm a b : ℂ) =
      if v = 0 then (a : ℂ) else (b : ℂ) := by
  have hr := pairNorm_nonneg a b
  have hr2 := pairNorm_sq a b
  by_cases hz : pairNorm a b = 0
  · have ha : a = 0 := by nlinarith [sq_nonneg b]
    have hb : b = 0 := by nlinarith [sq_nonneg a]
    rw [hz, Complex.ofReal_zero, mul_zero]
    simp [ha, hb]
  · have hp : 0 < pairNorm a b := lt_of_le_of_ne hr (Ne.symm hz)
    have ha : -pairNorm a b ≤ a ∧ a ≤ pairNorm a b := by
      constructor <;> nlinarith [sq_nonneg b]
    have lower : -1 ≤ a / pairNorm a b := (le_div_iff₀ hp).2 (by linarith)
    have upper : a / pairNorm a b ≤ 1 := (div_le_iff₀ hp).2 (by linarith)
    have hc : Real.cos (Real.arccos (a / pairNorm a b)) * pairNorm a b = a := by
      rw [Real.cos_arccos lower upper, div_mul_cancel₀ _ hz]
    have hs : 0 ≤ Real.sin (Real.arccos (a / pairNorm a b)) * pairNorm a b :=
      mul_nonneg (Real.sin_nonneg_of_nonneg_of_le_pi
        (Real.arccos_nonneg _) (Real.arccos_le_pi _)) hr
    have hs2 : (Real.sin (Real.arccos (a / pairNorm a b)) * pairNorm a b) ^ 2 = b ^ 2 := by
      have h := congrArg (fun x : ℝ => x * pairNorm a b ^ 2)
        (Real.sin_sq_add_cos_sq (Real.arccos (a / pairNorm a b)))
      nlinarith [sq_nonneg (Real.sin (Real.arccos (a / pairNorm a b)) * pairNorm a b)]
    have hangle : (2 * (if b < 0 then -Real.arccos (a / pairNorm a b)
        else Real.arccos (a / pairNorm a b))) / 2 =
        if b < 0 then -Real.arccos (a / pairNorm a b) else Real.arccos (a / pairNorm a b) := by
      ring
    simp only [splitAngle, if_neg hz, ExactAngle.eval, standardRyMatrix]
    rw [hangle]
    fin_cases v <;> by_cases hb : b < 0
    · simpa only [if_pos hb, realRotation, realOrthogonalRotation, Fin.val_zero,
        Real.cos_neg, if_pos rfl, Complex.ofReal_mul] using congrArg Complex.ofReal hc
    · simpa only [if_neg hb, realRotation, realOrthogonalRotation, Fin.val_zero,
        if_pos rfl, Complex.ofReal_mul] using congrArg Complex.ofReal hc
    · have he : -(Real.sin (Real.arccos (a / pairNorm a b)) * pairNorm a b) = b := by
        nlinarith
      simpa only [if_pos hb, realRotation, realOrthogonalRotation, Fin.val_zero,
        Fin.val_one, Real.sin_neg, Complex.ofReal_neg, Complex.ofReal_mul,
        neg_mul, show (1 : Fin 2) ≠ 0 from by decide, if_false] using congrArg Complex.ofReal he
    · have he : Real.sin (Real.arccos (a / pairNorm a b)) * pairNorm a b = b := by
        nlinarith
      simpa only [if_neg hb, realRotation, realOrthogonalRotation, Fin.val_zero,
        Fin.val_one, Complex.ofReal_mul,
        show (1 : Fin 2) ≠ 0 from by decide, if_false] using congrArg Complex.ofReal he

/-- Marginal amplitudes on all but the highest wire. -/
noncomputable def marginal {n : Nat} (f : PrimitiveBasis (n + 1) → ℝ) :
    PrimitiveBasis n → ℝ := fun b => pairNorm (f (Fin.snoc b 0)) (f (Fin.snoc b 1))

theorem marginal_nonneg {n : Nat} (f : PrimitiveBasis (n + 1) → ℝ) (b : PrimitiveBasis n) :
    0 ≤ marginal f b := pairNorm_nonneg _ _

/-- True squared Euclidean norm of the complete amplitude table. -/
noncomputable def normSq {n : Nat} (f : PrimitiveBasis n → ℝ) : ℝ := ∑ b, f b ^ 2

theorem normSq_nonneg {n : Nat} (f : PrimitiveBasis n → ℝ) : 0 ≤ normSq f :=
  Finset.sum_nonneg (fun _ _ => sq_nonneg _)

theorem normSq_marginal {n : Nat} (f : PrimitiveBasis (n + 1) → ℝ) :
    normSq (marginal f) = normSq f := by
  unfold normSq
  simp only [marginal, pairNorm_sq]
  rw [← (lastBasisEquiv n).symm.sum_comp]
  simp [Fintype.sum_prod_type, Fin.sum_univ_two]

/-- Chronological low-bit-first binary tree, compiled entirely to RY and CX. -/
noncomputable def prepareCircuit : (n : Nat) → (PrimitiveBasis n → ℝ) → PrimitiveCircuit n
  | 0, _ => []
  | n + 1, f =>
    (prepareCircuit n (marginal f)).map liftGate ++
      compileUniformlyControlledRy n Fin.castSucc (Fin.last n) Fin.castSucc_ne_last
        (fun b => splitAngle (f (Fin.snoc b 0)) (f (Fin.snoc b 1)))

theorem prepareCircuit_unitary {n : Nat} (f : PrimitiveBasis n → ℝ) :
    evalPrimitiveCircuit (prepareCircuit n f) ∈
      _root_.Matrix.unitaryGroup (PrimitiveBasis n) ℂ :=
  evalPrimitiveCircuit_unitary _

private theorem last_context_eq {n : Nat} (a b : PrimitiveBasis (n + 1)) :
    (splitPrimitiveWire (Fin.last n) a).2 = (splitPrimitiveWire (Fin.last n) b).2 ↔
      Fin.init a = Fin.init b := by
  constructor
  · intro h
    funext i
    exact congrFun h ⟨i.castSucc, Fin.castSucc_ne_last i⟩
  · intro h
    funext w
    obtain ⟨w, hw⟩ := w
    change a w = b w
    revert hw
    refine Fin.lastCases ?_ (fun i => ?_) w
    · intro h; exact (h rfl).elim
    · intro _; exact congrFun h i

theorem controlledLast_apply {n : Nat} (angles : PrimitiveBasis n → ExactAngle)
    (a b : PrimitiveBasis (n + 1)) :
    controlledRyBlockMatrix Fin.castSucc (Fin.last n) Fin.castSucc_ne_last angles a b =
      if Fin.init a = Fin.init b then
        standardRyMatrix (angles (Fin.init a)).eval (a (Fin.last n)) (b (Fin.last n))
      else 0 := by
  simp only [controlledRyBlockMatrix_apply, last_context_eq]
  rfl

theorem controlledLast_mul_lift {n : Nat} (angles : PrimitiveBasis n → ExactAngle)
    (M : _root_.Matrix (PrimitiveBasis n) (PrimitiveBasis n) ℂ)
    (a : PrimitiveBasis (n + 1)) :
    (controlledRyBlockMatrix Fin.castSucc (Fin.last n) Fin.castSucc_ne_last angles *
        liftLastMatrix M) a (fun _ => 0) =
      standardRyMatrix (angles (Fin.init a)).eval (a (Fin.last n)) 0 *
        M (Fin.init a) (fun _ => 0) := by
  rw [_root_.Matrix.mul_apply, ← (lastBasisEquiv n).symm.sum_comp]
  simp only [controlledLast_apply, liftLastMatrix_apply]
  simp [Fintype.sum_prod_type]
  exact Or.inl rfl

/-- The compiled first column is the normalized input table. This version
also covers the zero-qubit register, whose sole amplitude must be nonnegative. -/
theorem prepareCircuit_firstColumn {n : Nat} (f : PrimitiveBasis n → ℝ)
    (nonneg : ∀ b, 0 ≤ f b) (positive : 0 < normSq f) (b : PrimitiveBasis n) :
    evalPrimitiveCircuit (prepareCircuit n f) b (fun _ => 0) =
      ((f b / Real.sqrt (normSq f) : ℝ) : ℂ) := by
  induction n with
  | zero =>
    have heq : b = (fun _ => 0) := Subsingleton.elim _ _
    have hnorm : normSq f = f b ^ 2 := by
      calc
        normSq f = ∑ _x : PrimitiveBasis 0, f b ^ 2 :=
          Finset.sum_congr rfl (fun x _ => congrArg (fun x => f x ^ 2) (Subsingleton.elim x b))
        _ = f b ^ 2 := by simp
    have hf : 0 < f b := by have := nonneg b; rw [hnorm] at positive; nlinarith
    rw [hnorm, Real.sqrt_sq (le_of_lt hf), div_self (ne_of_gt hf)]
    simp [prepareCircuit, evalPrimitiveCircuit, heq]
  | succ n ih =>
    simp only [prepareCircuit, evalPrimitiveCircuit_append, eval_liftCircuit,
      compileUniformlyControlledRy_eval_controlledRyBlockMatrix]
    rw [controlledLast_mul_lift]
    rw [ih (marginal f) (marginal_nonneg f) (by simpa [normSq_marginal] using positive)]
    rw [normSq_marginal]
    push_cast
    rw [← mul_div_assoc]
    change
      (standardRyMatrix
        (splitAngle (f (Fin.snoc (Fin.init b) 0)) (f (Fin.snoc (Fin.init b) 1))).eval
          (b (Fin.last n)) 0 *
        (pairNorm (f (Fin.snoc (Fin.init b) 0)) (f (Fin.snoc (Fin.init b) 1)) : ℂ)) /
          (Real.sqrt (normSq f) : ℂ) = _
    rw [splitAngle_firstColumn]
    congr 1
    have hs : Fin.snoc (Fin.init b) (b (Fin.last n)) = b := Fin.snoc_init_self b
    generalize hv : b (Fin.last n) = v at *
    fin_cases v <;> simp_all

/-- Normalization is the actual sum of squared amplitudes, not a certificate flag. -/
theorem normalized_sum_sq {n : Nat} (f : PrimitiveBasis n → ℝ)
    (positive : 0 < normSq f) :
    (∑ b, (f b / Real.sqrt (normSq f)) ^ 2) = 1 := by
  simp_rw [div_pow]
  rw [← Finset.sum_div]
  change normSq f / Real.sqrt (normSq f) ^ 2 = 1
  rw [Real.sq_sqrt (normSq_nonneg f), div_self (ne_of_gt positive)]

theorem normSq_pos_of_positive {n : Nat} (f : PrimitiveBasis n → ℝ)
    (positive : ∀ b, 0 < f b) : 0 < normSq f := by
  apply Finset.sum_pos
  · intro b _; exact sq_pos_of_pos (positive b)
  · exact Finset.univ_nonempty

theorem liftCircuit_ryCount {n : Nat} (c : PrimitiveCircuit n) :
    PrimitiveCircuit.ryCount (c.map liftGate) = c.ryCount := by
  induction c with
  | nil => rfl
  | cons g c ih =>
    cases g <;> simp_all [PrimitiveCircuit.ryCount, liftGate]

theorem liftCircuit_cxCount {n : Nat} (c : PrimitiveCircuit n) :
    PrimitiveCircuit.cxCount (c.map liftGate) = c.cxCount := by
  induction c with
  | nil => rfl
  | cons g c ih =>
    cases g <;> simp_all [PrimitiveCircuit.cxCount, liftGate]

/-- The unoptimized reference tree uses exactly one RY per internal tree node. -/
theorem prepareCircuit_ryCount {n : Nat} (f : PrimitiveBasis n → ℝ) :
    (prepareCircuit n f).ryCount = 2 ^ n - 1 := by
  induction n with
  | zero => rfl
  | succ n ih =>
    simp only [prepareCircuit, PrimitiveCircuit.ryCount_append, liftCircuit_ryCount,
      compileUniformlyControlledRy_ryCount, ih, pow_succ]
    have hp : 0 < 2 ^ n := pow_pos (by decide) _
    omega

/-- CX count for the recursive reference multiplexor, without Gray-code optimization. -/
theorem prepareCircuit_cxCount {n : Nat} (f : PrimitiveBasis n → ℝ) :
    (prepareCircuit n f).cxCount = 2 * (2 ^ n - 1 - n) := by
  induction n with
  | zero => rfl
  | succ n ih =>
    simp only [prepareCircuit, PrimitiveCircuit.cxCount_append, liftCircuit_cxCount,
      compileUniformlyControlledRy_cxCount, ih, pow_succ]
    have hp : n < 2 ^ n := Nat.lt_two_pow_self
    omega

theorem prepareCircuit_oracleCalls {n : Nat} (f : PrimitiveBasis n → ℝ) :
    (prepareCircuit n f).resource.oracleCalls = 0 :=
  PrimitiveCircuit.resource_oracleCalls_eq_zero _

@[simp] theorem primitiveBasisLE_zero (n : Nat) :
    primitiveBasisLEEquiv n (fun _ => 0) = zeroBasisIndex n := by
  apply Fin.ext
  induction n with
  | zero => rfl
  | succ n ih =>
    change 0 + 2 * (primitiveBasisLEEquiv n (fun _ => 0)).val = 0
    simpa using congrArg (fun x : Nat => 2 * x) ih

@[simp] theorem primitiveBasisLE_zero_symm (n : Nat) :
    (primitiveBasisLEEquiv n).symm (zeroBasisIndex n) = (fun _ => 0) := by
  apply (primitiveBasisLEEquiv n).injective
  simp

/-- The same circuit matrix on flat little-endian integer indices. -/
noncomputable def prepareMatrixLE {n : Nat} (f : Fin (gridSize n) → ℝ) :
    _root_.Matrix (Fin (gridSize n)) (Fin (gridSize n)) ℂ :=
  _root_.Matrix.reindexAlgEquiv ℂ ℂ (primitiveBasisLEEquiv n)
    (evalPrimitiveCircuit (prepareCircuit n (fun b => f (primitiveBasisLEEquiv n b))))

theorem prepareMatrixLE_unitary {n : Nat} (f : Fin (gridSize n) → ℝ) :
    prepareMatrixLE f ∈ _root_.Matrix.unitaryGroup (Fin (gridSize n)) ℂ :=
  reindex_unitary _ _ (prepareCircuit_unitary _)

theorem normSq_reindex {n : Nat} (f : Fin (gridSize n) → ℝ) :
    normSq (fun b => f (primitiveBasisLEEquiv n b)) = ∑ j, f j ^ 2 := by
  exact (primitiveBasisLEEquiv n).sum_comp (fun j => f j ^ 2)

theorem prepareMatrixLE_firstColumn {n : Nat} (f : Fin (gridSize n) → ℝ)
    (positive : ∀ j, 0 < f j) (j : Fin (gridSize n)) :
    prepareMatrixLE f j (zeroBasisIndex n) =
      ((f j / Real.sqrt (∑ i, f i ^ 2) : ℝ) : ℂ) := by
  unfold prepareMatrixLE
  simp only [_root_.Matrix.reindexAlgEquiv_apply, _root_.Matrix.reindex_apply,
    _root_.Matrix.submatrix_apply, primitiveBasisLE_zero_symm]
  rw [prepareCircuit_firstColumn _ (fun b => le_of_lt (positive _))
    (normSq_pos_of_positive _ (fun b => positive _)), normSq_reindex]
  simp

theorem normalized_sum_sq_LE {n : Nat} (f : Fin (gridSize n) → ℝ)
    (positive : ∀ j, 0 < f j) :
    (∑ j, (f j / Real.sqrt (∑ i, f i ^ 2)) ^ 2) = 1 := by
  have h := normalized_sum_sq (fun b => f (primitiveBasisLEEquiv n b))
    (normSq_pos_of_positive _ (fun b => positive _))
  rw [normSq_reindex] at h
  calc
    _ = ∑ b, (f (primitiveBasisLEEquiv n b) / Real.sqrt (∑ i, f i ^ 2)) ^ 2 :=
      ((primitiveBasisLEEquiv n).sum_comp _).symm
    _ = 1 := h

end QuantumBlockEncoding.RealAmplitudePreparation

Global Cᵏ smoothness: complete Lean source

Global Cᵏ smoothness: complete Lean source
import QuantumBlockEncoding.HermitePolynomial
import Mathlib.Analysis.Calculus.ContDiff.Polynomial
import Mathlib.Analysis.Calculus.Deriv.Slope
import Mathlib.Topology.Piecewise

/-!
# Global regularity of the Hermite initial datum

Matching derivatives are used to prove a reusable finite-order gluing theorem.
Applying that theorem at both source junctions proves global `C^k` regularity
of the actual exponential/Hermite/exponential function.
-/

noncomputable section

open Filter Set Topology Polynomial
open QuantumBlockEncoding.HermitePolynomial

namespace QuantumBlockEncoding.HermiteSmoothness

/-- Join two real functions at a threshold, taking the right value at the threshold. -/
def splice (c : ℝ) (f g : ℝ → ℝ) (x : ℝ) : ℝ := if x < c then f x else g x

/-- Any selector preserves a common derivative when both branch values agree. -/
theorem hasDerivAt_ite_of_eq (pred : ℝ → Prop) [DecidablePred pred]
    {f g : ℝ → ℝ} {d x : ℝ} (hf : HasDerivAt f d x) (hg : HasDerivAt g d x)
    (hv : f x = g x) :
    HasDerivAt (fun y => if pred y then f y else g y) d x := by
  apply hasDerivAt_iff_tendsto_slope.mpr
  have he : slope (fun y => if pred y then f y else g y) x =
      fun y => if pred y then slope f x y else slope g x y := by
    funext y
    by_cases hx : pred x <;> by_cases hy : pred y <;>
      simp [slope_def_field, hx, hy, hv]
  rw [he]
  exact hf.tendsto_slope.if' hg.tendsto_slope

theorem hasDerivAt_splice (c : ℝ) (f g : ℝ → ℝ)
    (hf : Differentiable ℝ f) (hg : Differentiable ℝ g)
    (hv : f c = g c) (hd : deriv f c = deriv g c) (x : ℝ) :
    HasDerivAt (splice c f g) (splice c (deriv f) (deriv g) x) x := by
  rcases lt_trichotomy x c with hx | hxc | hx
  · rw [splice, if_pos hx]
    apply (hf x).hasDerivAt.congr_of_eventuallyEq
    filter_upwards [eventually_lt_nhds hx] with y hy
    simp [splice, hy]
  · subst x
    simp only [splice, lt_self_iff_false, if_false]
    exact hasDerivAt_ite_of_eq (fun y => y < c)
      (hd ▸ (hf c).hasDerivAt) (hg c).hasDerivAt hv
  · rw [splice, if_neg (not_lt.mpr hx.le)]
    apply (hg x).hasDerivAt.congr_of_eventuallyEq
    filter_upwards [eventually_gt_nhds hx] with y hy
    simp [splice, not_lt.mpr hy.le]

theorem deriv_splice (c : ℝ) (f g : ℝ → ℝ)
    (hf : Differentiable ℝ f) (hg : Differentiable ℝ g)
    (hv : f c = g c) (hd : deriv f c = deriv g c) :
    deriv (splice c f g) = splice c (deriv f) (deriv g) := by
  funext x
  exact (hasDerivAt_splice c f g hf hg hv hd x).deriv

/-- Two `C^k` real functions glue to a `C^k` function if their jets agree at the cut. -/
theorem contDiff_splice (k : ℕ) (c : ℝ) (f g : ℝ → ℝ)
    (hf : ContDiff ℝ k f) (hg : ContDiff ℝ k g)
    (hjet : ∀ j ≤ k, iteratedDeriv j f c = iteratedDeriv j g c) :
    ContDiff ℝ k (splice c f g) := by
  induction k generalizing f g with
  | zero =>
    rw [Nat.cast_zero, contDiff_zero]
    apply Continuous.if ?_ hf.continuous hg.continuous
    intro x hx
    have hxc : x = c := by
      change x ∈ frontier (Iio c) at hx
      simpa only [frontier_Iio, mem_singleton_iff] using hx
    subst x
    simpa using hjet 0 le_rfl
  | succ k ih =>
    rw [Nat.cast_add, Nat.cast_one] at hf hg ⊢
    obtain ⟨hfd, _, hfder⟩ := contDiff_succ_iff_deriv.mp hf
    obtain ⟨hgd, _, hgder⟩ := contDiff_succ_iff_deriv.mp hg
    have hv : f c = g c := by simpa using hjet 0 (Nat.zero_le _)
    have hd : deriv f c = deriv g c := by simpa using hjet 1 (by omega)
    apply contDiff_succ_iff_deriv.mpr
    refine ⟨fun x => (hasDerivAt_splice c f g hfd hgd hv hd x).differentiableAt,
      by simp, ?_⟩
    rw [deriv_splice c f g hfd hgd hv hd]
    apply ih (deriv f) (deriv g) hfder hgder
    intro j hj
    simpa only [iteratedDeriv_succ'] using hjet (j + 1) (by omega)

theorem iteratedDeriv_exp (j : ℕ) (x : ℝ) : iteratedDeriv j Real.exp x = Real.exp x := by
  simpa using congrFun (iteratedDeriv_exp_const_mul j (1 : ℝ)) x

theorem iteratedDeriv_exp_neg (j : ℕ) (x : ℝ) :
    iteratedDeriv j (fun y : ℝ => Real.exp (-y)) x = (-1 : ℝ) ^ j * Real.exp (-x) := by
  simpa using congrFun (iteratedDeriv_exp_const_mul j (-1 : ℝ)) x

/-- First join: the source polynomial and right exponential meet smoothly at zero. -/
theorem contDiff_right_splice (k : ℕ) :
    ContDiff ℝ k
      (splice 0 (fun p => (sourceInterpolant k).eval p) (fun p => Real.exp (-p))) := by
  apply contDiff_splice k 0
  · simpa using (sourceInterpolant k).contDiff_aeval (k : WithTop ℕ∞)
  · exact Real.contDiff_exp.comp contDiff_id.neg
  · intro j hj
    rw [sourceInterpolant_right_iteratedDeriv k j hj, iteratedDeriv_exp_neg]
    simp

/-- The right splice coincides with the polynomial on a neighborhood of the left junction. -/
theorem right_splice_eventuallyEq (k : ℕ) :
    splice 0 (fun p => (sourceInterpolant k).eval p) (fun p => Real.exp (-p))
      =ᶠ[𝓝 (-1)] (fun p => (sourceInterpolant k).eval p) := by
  filter_upwards [eventually_lt_nhds (show (-1 : ℝ) < 0 by norm_num)] with p hp
  simp [splice, hp]

/-- Two applications of the reusable gluing theorem close both source junctions. -/
theorem contDiff_double_splice (k : ℕ) :
    ContDiff ℝ k
      (splice (-1) Real.exp
        (splice 0 (fun p => (sourceInterpolant k).eval p) (fun p => Real.exp (-p)))) := by
  apply contDiff_splice k (-1) Real.exp _ Real.contDiff_exp (contDiff_right_splice k)
  intro j hj
  rw [iteratedDeriv_exp, (right_splice_eventuallyEq k).iteratedDeriv_eq j]
  exact (sourceInterpolant_left_iteratedDeriv k j hj).symm

/-- The original `≤ 0` middle-branch convention equals the smooth double splice exactly. -/
theorem smoothInitial_eq_double_splice (k : ℕ) :
    smoothInitial k = splice (-1) Real.exp
      (splice 0 (fun p => (sourceInterpolant k).eval p) (fun p => Real.exp (-p))) := by
  funext p
  by_cases hl : p < -1
  · simp [smoothInitial, splice, hl]
  · by_cases hr : p < 0
    · simp [smoothInitial, splice, hl, hr, hr.le]
    · by_cases hz : p = 0
      · subst p
        have hp0 : (sourceInterpolant k).eval 0 = 1 := by
          simpa using sourceInterpolant_right_jet k 0 (Nat.zero_le k)
        simp [smoothInitial, splice, hp0]
      · have hp : 0 < p := lt_of_le_of_ne (not_lt.mp hr) (Ne.symm hz)
        simp [smoothInitial, splice, hl, hr, not_le.mpr hp]

/-- The literal source initial datum is globally `C^k`, for every natural order `k`. -/
theorem smoothInitial_contDiff (k : ℕ) : ContDiff ℝ k (smoothInitial k) := by
  rw [smoothInitial_eq_double_splice]
  exact contDiff_double_splice k

end QuantumBlockEncoding.HermiteSmoothness

Hermite target and root certificate: complete Lean source

Hermite target and root certificate: complete Lean source
import QuantumBlockEncoding.HermitePolynomial
import QuantumBlockEncoding.RealAmplitudePreparation

/-!
# Exact Hermite smooth-initial-data preparation

The target is the literal exponential / Hermite-polynomial / exponential
splice, sampled at `p_j = -πL + 2πLj / 2^n`. The unitary below is the denotation
of an explicit RY/CX circuit. Its first column, normalization, and reference
gate counts hold for every smoothing order and register width.

Exact real angles belong to the symbolic certificate. Numerical evaluation
and rounded QASM angles remain separate executable-export evidence.
-/

namespace QuantumBlockEncoding.HermiteStatePreparation

open HermitePolynomial RealAmplitudePreparation ConcreteSemantics

noncomputable section

/-- Left-inclusive, right-exclusive grid on `[-πL,πL)` when `L>0`. -/
def gridPoint (n : ℕ) (L : ℝ) (j : Fin (gridSize n)) : ℝ :=
  -Real.pi * L + (j.val : ℝ) * (2 * Real.pi * L / (gridSize n : ℝ))

/-- The physical sample, without changing the polynomial on the splice interval. -/
def sampledAmplitude (k n : ℕ) (L : ℝ) (j : Fin (gridSize n)) : ℝ :=
  smoothInitial k (gridPoint n L j)

theorem sampledAmplitude_pos (k n : ℕ) (L : ℝ) (j : Fin (gridSize n)) :
    0 < sampledAmplitude k n L j := smoothInitial_pos _ _

/-- The true Euclidean normalizer of the complete finite sample table. -/
def sampleNorm (k n : ℕ) (L : ℝ) : ℝ :=
  Real.sqrt (∑ j, sampledAmplitude k n L j ^ 2)

theorem sampleNorm_pos (k n : ℕ) (L : ℝ) : 0 < sampleNorm k n L := by
  apply Real.sqrt_pos.mpr
  have h := normSq_pos_of_positive
    (fun b => sampledAmplitude k n L (primitiveBasisLEEquiv n b))
    (fun b => sampledAmplitude_pos k n L _)
  simpa only [normSq_reindex] using h

def normalizedAmplitude (k n : ℕ) (L : ℝ) (j : Fin (gridSize n)) : ℂ :=
  ((sampledAmplitude k n L j / sampleNorm k n L : ℝ) : ℂ)

/-- An actual list of primitive instructions on precisely `n` wires. -/
def hermiteCircuit (k n : ℕ) (L : ℝ) : PrimitiveCircuit n :=
  prepareCircuit n (fun b => sampledAmplitude k n L (primitiveBasisLEEquiv n b))

/-- The exact primitive denotation, reindexed by little-endian integers. -/
def hermiteUnitary (k n : ℕ) (L : ℝ) :
    _root_.Matrix (Fin (gridSize n)) (Fin (gridSize n)) ℂ :=
  prepareMatrixLE (sampledAmplitude k n L)

theorem hermiteUnitary_eq_circuit (k n : ℕ) (L : ℝ) :
    hermiteUnitary k n L =
      _root_.Matrix.reindexAlgEquiv ℂ ℂ (primitiveBasisLEEquiv n)
        (evalPrimitiveCircuit (hermiteCircuit k n L)) := rfl

theorem hermiteUnitary_unitary (k n : ℕ) (L : ℝ) :
    hermiteUnitary k n L ∈ _root_.Matrix.unitaryGroup (Fin (gridSize n)) ℂ :=
  prepareMatrixLE_unitary _

theorem hermite_firstColumn (k n : ℕ) (L : ℝ) (j : Fin (gridSize n)) :
    hermiteUnitary k n L j (zeroBasisIndex n) = normalizedAmplitude k n L j :=
  prepareMatrixLE_firstColumn _ (sampledAmplitude_pos k n L) j

/-- Every squared norm is included, including both exponential tails and the splice. -/
theorem hermite_normalized (k n : ℕ) (L : ℝ) :
    (∑ j, Complex.normSq (normalizedAmplitude k n L j)) = 1 := by
  simpa only [normalizedAmplitude, sampleNorm, Complex.normSq_ofReal, ← sq]
    using normalized_sum_sq_LE (sampledAmplitude k n L) (sampledAmplitude_pos k n L)

theorem hermite_stateAction (k n : ℕ) (L : ℝ) :
    applyVec (hermiteUnitary k n L) (zeroKet n) = normalizedAmplitude k n L := by
  rw [applyVec_zeroKet]
  funext j
  exact hermite_firstColumn k n L j

theorem hermite_ryCount (k n : ℕ) (L : ℝ) :
    (hermiteCircuit k n L).ryCount = 2 ^ n - 1 := prepareCircuit_ryCount _

theorem hermite_cxCount (k n : ℕ) (L : ℝ) :
    (hermiteCircuit k n L).cxCount = 2 * (2 ^ n - 1 - n) := prepareCircuit_cxCount _

theorem hermite_oracleCalls (k n : ℕ) (L : ℝ) :
    (hermiteCircuit k n L).resource.oracleCalls = 0 := prepareCircuit_oracleCalls _

/-- The circuit has exactly the data register and no allocated ancillary wire. -/
theorem hermite_noAncilla (k n : ℕ) (L : ℝ) :
    (hermiteCircuit k n L).resource.pureAncilla = 0 := rfl

/-- The closed symbolic root: normalization, genuine unitarity, primitive
state action and exact reference compiler resources are proved together. -/
theorem hermiteStatePreparation_complete (k n : ℕ) (L : ℝ) :
    0 < sampleNorm k n L ∧
    (∑ j, Complex.normSq (normalizedAmplitude k n L j)) = 1 ∧
    hermiteUnitary k n L ∈ _root_.Matrix.unitaryGroup (Fin (gridSize n)) ℂ ∧
    applyVec (hermiteUnitary k n L) (zeroKet n) = normalizedAmplitude k n L ∧
    (hermiteCircuit k n L).ryCount = 2 ^ n - 1 ∧
    (hermiteCircuit k n L).cxCount = 2 * (2 ^ n - 1 - n) ∧
    (hermiteCircuit k n L).resource.oracleCalls = 0 :=
  ⟨sampleNorm_pos k n L, hermite_normalized k n L, hermiteUnitary_unitary k n L,
    hermite_stateAction k n L, hermite_ryCount k n L, hermite_cxCount k n L,
    hermite_oracleCalls k n L⟩

/-- Integration into the existing concrete state-preparation certificate API. -/
def hermiteCertificate (k n : ℕ) (L : ℝ) : ComplexStatePreparationCertificate n where
  target := {
    amplitudes := normalizedAmplitude k n L
    normalization := (∑ j, Complex.normSq (normalizedAmplitude k n L j)) = 1
    source := "Exact exponential–Hermite–exponential initial datum on a little-endian grid"
  }
  gate := {
    matrix := hermiteUnitary k n L
    unitary := hermiteUnitary_unitary k n L
  }
  normalizationProof := hermite_normalized k n L
  preparationProof := hermite_stateAction k n L

end

end QuantumBlockEncoding.HermiteStatePreparation

Runnable elementary-gate exporter (Python)

From the source function to the prepared register: proof and replay paths
From the source function to the prepared register: proof and replay paths
Reference rotation-tree circuit · formula-correct logical viewThis is the preserved \(n_p=3\) reference route. The boxes below are logical UCRY layers; the archived SVG contains the chronological 7 \(R_y\) + 8 CNOT primitive sequence.
Prefix mass
\[m_{d,s}=\sum_{j\bmod 2^d=s}g_k(p_j)^2\]
Split angle
\[\theta_{d,s}=2\operatorname{atan2}\!\left(\sqrt{m_{d+1,s+2^d}},\sqrt{m_{d+1,s}}\right)\]
Layer invariant
\[|\Psi_d\rangle=\sum_{s<2^d}\sqrt{m_{d,s}/Z_k}\,|0^{n_p-d}\rangle|s\rangle\]
Primitive rotation
\[R_y(\theta)|0\rangle=\cos(\theta/2)|0\rangle+\sin(\theta/2)|1\rangle\]
Open the chronological finite gate artifact

The original SVG is kept unchanged as replay evidence; its equations are baked vector text rather than MathJax. Use this page for the typeset mathematical reading.

Open the archived circuit SVG ↗

Example circuit (OpenQASM 3)

Example circuit (OpenQASM 3)
OPENQASM 3.0;
include "stdgates.inc";
qubit[3] q;
ry(1.1952476818322655) q[0];
ry(1.1411899214842629) q[1];
cx q[0],q[1];
ry(-0.56983382256701454) q[1];
cx q[0],q[1];
ry(1.9282975397199893) q[2];
cx q[1],q[2];
ry(0.96514759743197598) q[2];
cx q[1],q[2];
cx q[0],q[2];
ry(0.38470990194757371) q[2];
cx q[1],q[2];
ry(-0.22293648255930965) q[2];
cx q[1],q[2];
cx q[0],q[2];

Accepted finite packet: OpenQASM 2 replay circuit

Accepted finite packet: OpenQASM 3 replay circuit

Sample positions and target amplitudes (CSV)

Saved mass-tree evidence required by independent replay (JSON)

Saved endpoint-jet evidence required by independent replay (JSON)

Finite replay results, backend versions and artifact hashes (JSON)

Register conventions and executable manifest (JSON)

Independent interpolation and saved-QASM replay

Independent interpolation and saved-QASM replay
#!/usr/bin/env python3
"""Replay saved artifacts using an independent rational Hermite interpolator.

No exporter functions are imported. Endpoint interpolation reconstructs the
target, while Qiskit parses and simulates the saved OpenQASM circuit.
"""
from __future__ import annotations

import argparse
import csv
from decimal import Decimal, localcontext
from fractions import Fraction
import hashlib
import json
import math
from pathlib import Path
import sys

import numpy as np


def interpolate(k: int) -> tuple[list[Fraction], list[Fraction]]:
    """Solve endpoint equations for P=exp(-1)*u+v by exact elimination."""
    if not isinstance(k, int) or not 0 <= k <= 30:
        raise ValueError("independent replay supports 0 <= k <= 30")
    size = 2*k+2
    matrix = []
    for endpoint in (0, 1):
        for order in range(k+1):
            row = [Fraction(math.factorial(i), math.factorial(i-order))*endpoint**(i-order)
                   if i >= order else Fraction(0) for i in range(size)]
            row.extend([Fraction(1), Fraction(0)] if endpoint == 0
                       else [Fraction(0), Fraction((-1)**order)])
            matrix.append(row)
    for col in range(size):
        pivot = next(i for i in range(col, size) if matrix[i][col])
        matrix[col], matrix[pivot] = matrix[pivot], matrix[col]
        divisor = matrix[col][col]
        matrix[col] = [x/divisor for x in matrix[col]]
        for row in range(size):
            if row != col and matrix[row][col]:
                factor = matrix[row][col]
                matrix[row] = [a-factor*b for a, b in zip(matrix[row], matrix[col])]
    return [row[size] for row in matrix], [row[size+1] for row in matrix]


def target_samples(k: int, n: int, length: float) -> tuple[np.ndarray, np.ndarray]:
    u, v = interpolate(k)
    points = -math.pi*length + 2*math.pi*length*np.arange(2**n)/2**n
    with localcontext() as context:
        context.prec = 100
        minus_one_exp = Decimal(-1).exp()
        coefficients = [minus_one_exp*Decimal(a.numerator)/Decimal(a.denominator)
                        + Decimal(b.numerator)/Decimal(b.denominator) for a, b in zip(u, v)]
        values = []
        for p in points:
            decimal_p = Decimal(str(p))
            if p <= -1:
                value = decimal_p.exp()
            elif p >= 0:
                value = (-decimal_p).exp()
            else:
                t = decimal_p+1
                value = Decimal(0)
                for coefficient in reversed(coefficients):
                    value = value*t+coefficient
            values.append(float(value))
    return points, np.asarray(values)


def verify(directory: Path) -> dict:
    from qiskit import qasm2, qasm3
    from qiskit.quantum_info import Statevector

    required = ["acceptance.json", "manifest.json", "circuit.qasm", "circuit.qasm2",
                "circuit.qasm3", "samples.csv", "mass-tree.json", "endpoint-jets.json"]
    for name in required:
        if not (directory/name).is_file():
            raise ValueError(f"required artifact is missing: {name}")
    acceptance = json.loads((directory/"acceptance.json").read_text(encoding="utf-8"))
    manifest = json.loads((directory/"manifest.json").read_text(encoding="utf-8"))
    if acceptance.get("accepted") is not True or acceptance.get("evidence_class") != "finite-executable-acceptance":
        raise ValueError("artifact does not claim completed executable acceptance")
    if acceptance.get("parameters") != manifest.get("parameters"):
        raise ValueError("manifest and acceptance parameters disagree")
    parameters = manifest["parameters"]
    k, n, length = parameters["k"], parameters["n"], parameters["L"]
    if not isinstance(n, int) or not 1 <= n <= 10 or not math.isfinite(length) or length <= 0:
        raise ValueError("invalid finite replay parameters")
    if n <= 5:
        required.append("circuit.svg")
    digests = acceptance.get("artifact_sha256", {})
    for name in required:
        if name == "acceptance.json":
            continue
        if not (directory/name).is_file():
            raise ValueError(f"required artifact is missing: {name}")
        actual = hashlib.sha256((directory/name).read_bytes()).hexdigest()
        if digests.get(name) != actual:
            raise ValueError(f"artifact hash mismatch: {name}")
    exporter = Path(__file__).with_name("export.py")
    if not exporter.is_file() or acceptance.get("exporter_sha256") != hashlib.sha256(exporter.read_bytes()).hexdigest():
        raise ValueError("exporter source changed after artifact acceptance")
    points, samples = target_samples(k, n, length)
    target = samples/np.linalg.norm(samples)
    with (directory/"samples.csv").open(encoding="utf-8", newline="") as stream:
        rows = list(csv.DictReader(stream))
    if len(rows) != 2**n:
        raise ValueError("wrong sample count")
    for j, row in enumerate(rows):
        if int(row["index"]) != j or row["basis_q_high_to_low"] != format(j, f"0{n}b"):
            raise ValueError("sample index or bit order mismatch")
    sample_error = max(float(np.max(np.abs(np.asarray([float(r[field]) for r in rows])-expected)))
                       for field, expected in (("p", points), ("f", samples), ("target_amplitude", target)))
    if sample_error > 1e-12:
        raise ValueError(f"independent endpoint interpolation disagrees with samples: {sample_error}")
    errors = {}
    for name, loader in (("circuit.qasm", qasm3.loads), ("circuit.qasm3", qasm3.loads), ("circuit.qasm2", qasm2.loads)):
        circuit = loader((directory/name).read_text(encoding="utf-8"))
        counts = circuit.count_ops()
        if circuit.num_qubits != n or set(counts) - {"ry", "cx"}:
            raise ValueError(f"unexpected wires or gates: {name}")
        if (counts.get("ry", 0), counts.get("cx", 0)) != (2**n-1, 2*(2**n-1-n)):
            raise ValueError(f"reference resource counts changed: {name}")
        state = np.asarray(Statevector.from_instruction(circuit).data)
        errors[name] = float(np.max(np.abs(state-target)))
    if max(errors.values()) > 1e-10:
        raise ValueError(f"independent QASM replay failed: {errors}")
    return {"passed": True, "evidence_class": "independent-finite-replay", "parameters": parameters,
            "target_method": "exact rational endpoint interpolation, evaluated at 100 decimal digits",
            "sample_max_error": sample_error, "qasm_max_amplitude_errors": errors,
            "checked_artifacts": required, "lean_certificate_claimed": False}


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--directory", type=Path, default=Path(__file__).resolve().parents[1])
    args = parser.parse_args()
    try:
        result = verify(args.directory)
    except (ValueError, KeyError, OSError, ImportError) as exc:
        print(f"Hermite independent replay failed: {exc}", file=sys.stderr)
        return 1
    print(json.dumps(result, indent=2, sort_keys=True, allow_nan=False))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Independent source-to-certificate review

Mathematical target

The equation being studied

\[\lvert g_k\rangle_p=\frac{1}{\sqrt{Z_k}}\sum_{j=0}^{2^n-1}g_k(p_j)\lvert j\rangle,\quad Z_k=\sum_jg_k(p_j)^2,\quad p_j=-\pi L+\frac{2\pi Lj}{2^n}.\]
Exact source profile.
\[g_k(p)=\begin{cases}e^p,&p<-1,\\ P_{2k+1}(p),&-1\le p\le0,\\ e^{-p},&p>0.\end{cases}\]
Prepared state.
\[N=2^{n_p},\qquad |g_k\rangle_p=\frac{1}{\sqrt{Z_k}}\sum_{j=0}^{N-1}g_k(p_j)|j\rangle,\qquad Z_k=\sum_{j=0}^{N-1}g_k(p_j)^2.\]
Certified quantum resource statement.
\[G,\operatorname{depth}\le 48\,n_pD^3=48\,n_p(2k+6)^3,\qquad q_{\mathrm{bond}}=\lceil\log_2D\rceil.\]

The samples themselves are amplitudes, not probabilities. The construction uses zero oracle calls and no postselection, and the bond register is clean at output. The exact-real quantum bound is certified separately from finite-bit implementation cost.

k
Number of endpoint derivatives matched; k=1 is the cubic splice.
n, N=2^n
Qubit count and sample count. q0 has weight 1.
L
Positive truncation parameter; grid interval [−πL,πL).
g_k(p_j)
Real amplitude before normalization, not a measurement probability.
Z_k
Sum of squared samples; normalization is proved from the actual input.

Circuit anatomy

How the candidate acts

These blocks show logical stages and register responsibilities. They do not pretend an unresolved logical oracle is already a primitive hardware gate.

Register orderReference rotation-tree diagram below: q0 is the least significant bit; layers prepare q0, q1, …, q(n−1), with no ancilla. The polynomial construction instead emits MSB-first through a small bond register, then uses public LSB wire order and returns every bond qubit to zero. Neither route uses output measurement.
01

Classical sample construction

Compute the Hermite coefficients and evaluate the two tails and the polynomial splice.

\(k,n,L\)\(g_k(p_j)\)
02

Mass reduction

Sum squared amplitudes over common low-bit prefixes. Each parent mass is the sum of its children.

\(m_{d,s}\)split angles
03

Quantum preparation

Apply one uniformly controlled Ry layer per qubit, then compile every layer to Ry and CNOT.

\(\mathrm{UCRY}_0\)\(\mathrm{UCRY}_1\)\(\mathrm{UCRY}_{n-1}\)
04

Prepared register

The final amplitudes equal the normalized samples. Independent finite replay measures numerical rounding error.

\(|g_k\rangle\)NumPy / Qiskit / QASM

Auditable evolution · certified milestones

Candidate and proof progression — how the certified construction changed

The project keeps the usual score order \((\text{gates},\text{depth},\text{auxiliary qubits},\text{oracle calls})\), but it does not compare unlike scopes as if they were one finite benchmark.

What “time to solution” means here. No generation counter or model-active runtime was persisted for this historical search. To avoid inventing one, the page reports auditable Git certification milestones. The 22 h 56 min 06 s below is repository wall-clock between the first baseline certificate and the first polynomial-gate certificate, not continuous agent compute time.

Certified baseline

Reference mass-tree / UCRY route

Certified
2026-09-09 08:45:54 UTC
Repository elapsed
baseline

Scope. Displayed resource tuple is the preserved k=1, n_p=3, L=1 finite example.

\[(G,\operatorname{depth},q_{\rm aux},Q_{\rm oracle})=(15,15,0,0)\]

Compute all sample masses, recursively split them by binary prefixes, and compile the resulting uniformly controlled rotations. This route is exact and pedagogically transparent, but it does not exploit the special function family when forming the preparation data.

Logical dataflow

samples\(g_k(p_0),\ldots,g_k(p_{N-1})\)prefix masses\(m_{d,s}\)controlled rotations\(\mathrm{UCRY}_d\)state\(|g_k\rangle\)
\[|0^{n_p}\rangle\xrightarrow{\;\text{mass tree + UCRY}\;}|g_k\rangle\]
Lean rootQuantumBlockEncoding.HermiteStatePreparation.hermiteStatePreparation_complete

Structural family certificate

Bernstein–MPS / bounded-memory route

Certified
2026-09-10 07:42:00 UTC
Repository elapsed
+22 h 56 min 06 s

Scope. All-width exact-real quantum family for arbitrary natural k, n_p>=1 and positive L.

\[(G,\operatorname{depth},q_{\rm aux},Q_{\rm oracle})\preceq\bigl(48n_p(2k+6)^3,48n_p(2k+6)^3,\lceil\log_2(2k+6)\rceil,0\bigr)\]

Keep the function in Bernstein / finite-state form, reinterpret that update rule as a bounded-bond tensor train, canonicalize the local maps and compile them to Ry/CNOT while cleaning the bond register.

Logical dataflow

analytic profile\(e^p\;|\;P_{2k+1}\;|\;e^{-p}\)finite memory\(D=2k+6\)local maps\(V_1,\ldots,V_{n_p}\)primitive circuit\(R_y/\mathrm{CNOT}\)
\[|0^{n_p}\rangle|0^q\rangle\xrightarrow{\;V_1V_2\cdots V_{n_p}\;}|g_k\rangle|0^q\rangle,\qquad q=\lceil\log_2(2k+6)\rceil\]
Lean rootQuantumBlockEncoding.ConstructiveHermitePreparation.prepare_spec
Comparison boundary. These two resource displays have different scopes: the reference tuple is the saved k=1, n_p=3 example, while the new entry is an all-width symbolic family bound. Therefore ASPBE does not label this pair a strict same-instance lexicographic winner. The certified advance is structural and asymptotic: for fixed k, the new quantum bound is linear in \(n_p\) rather than expanding an arbitrary 2^{n_p}-entry table.

Reader workbench

Edit, preview, then copy

Change symbols, language, proof steps, or the grouped-register circuit locally in your browser. The preview is explanatory; the linked Lean declaration remains the certificate.

Mathematical construction

Proof steps

One step per line. Natural language and inline mathematics are both accepted.

    Quantum circuit

    Complete packet

    Copy the reviewed construction and proof

    The packet below is generated from the reviewed case record. The exact primitive authority is the linked Lean source and executable artifact.

    Construction and circuit LaTeX
    % Requires: \usepackage{quantikz}
    \paragraph{Construction.}
    \[
    \lvert g_k\rangle_p=\frac{1}{\sqrt{Z_k}}\sum_{j=0}^{2^n-1}g_k(p_j)\lvert j\rangle,\quad Z_k=\sum_jg_k(p_j)^2,\quad p_j=-\pi L+\frac{2\pi Lj}{2^n}.
    \]
    
    % Hermite rotation tree
    \begin{quantikz}[row sep=.45cm,column sep=.6cm]
    \lstick{$q_0:\ket0$} & \gate{R_y} & \ctrl{1} & \ctrl{2} & \qw \\
    \lstick{$q_1:\ket0$} & \qw & \gate{\mathrm{UCRY}_1} & \ctrl{1} & \qw \\
    \lstick{$q_2:\ket0$} & \qw & \qw & \gate{\mathrm{UCRY}_2} & \rstick{$|g_k\rangle$} \qw
    \end{quantikz}
    English proof LaTeX
    \paragraph{Proof.}
    The exact target uses exp(p) to the left of −1, a degree-at-most 2k+1 Hermite polynomial on [−1,0], and exp(−p) to the right of 0. The real-valued samples, not their square roots, are normalized. The new Bernstein–MPS circuit has at most 48 n_p (2k+6)^3 Ry/CNOT instructions and the same upper bound on scheduled depth, with ceil(log2(2k+6)) clean bond qubits, zero oracle calls and no postselection. These are exact real-angle quantum bounds. Whole classical preprocessing and uniform finite-precision error remain open. The original exponential rotation tree and its finite downloadable packet are retained below as the reference.
    \begin{enumerate}
      \item First construct the polynomial and its endpoint jets. Build the low-bit mass tree and apply its exact controlled rotations. The invariant says that a prefix carries the square root of its total remaining probability mass. The final layer resolves each requested amplitude.
    \end{enumerate}
    Each advertised certificate is the named Lean declaration linked on this page.
    Lean declaration retrieval block
    import QuantumBlockEncoding
    
    #check QuantumBlockEncoding.HermitePolynomial.sourceInterpolant_degree
    #check QuantumBlockEncoding.HermitePolynomial.sourceInterpolant_left_iteratedDeriv
    #check QuantumBlockEncoding.HermitePolynomial.sourceInterpolant_right_iteratedDeriv
    #check QuantumBlockEncoding.HermitePolynomial.coefficientPolynomial_eval
    #check QuantumBlockEncoding.HermitePolynomial.sourceInterpolant_eval
    #check QuantumBlockEncoding.HermitePolynomial.smoothInitial_pos
    #check QuantumBlockEncoding.HermiteSmoothness.smoothInitial_contDiff
    #check QuantumBlockEncoding.compileUniformlyControlledRy_eval_controlledRyBlockMatrix
    #check QuantumBlockEncoding.HermiteStatePreparation.hermiteStatePreparation_complete
    #check QuantumBlockEncoding.HermiteBoundaryInjection.hermiteKernel_eq_sample
    #check QuantumBlockEncoding.HermiteFiniteNorm.localSampleNorm_eq_sampleNorm
    #check QuantumBlockEncoding.ConstructiveHermitePreparation.prepare_spec
    #check QuantumBlockEncoding.StoredTensorTrain.canonicalize_total_cost_le
    #check QuantumBlockEncoding.StoredHermiteRawSource.raw_contract
    #check QuantumBlockEncoding.StoredHermiteRawCost.raw_certified
    #check QuantumBlockEncoding.PrimitiveRyPerturbation.eval_ry_distance
    #check QuantumBlockEncoding.PrimitiveCircuitPerturbation.prepare_conditional_clm_distance_le
    Show the complete Lean certificate list

    Open this when you want to inspect every declaration linked to the case.

    Proof authority

    Named Lean certificates

    These declarations, compiled by the current Lean gate, support the mathematical and resource claims above.

    Optional executable checks and outputs

    Executable verification and exports

    Checking and artifact selection are independent. A user may screen with Qiskit, OpenQASM round-trip, both, or neither, then request a different set of output files.

    Backend / artifactRoleStatusEvidence
    Internal canonical evaluatorReference semantics for primitive canonical IRpassedmetrics manifest
    Qiskit replayGate-by-gate numerical screeningpassedexecutable-exports/SP-HERMITE-001/qiskit/export.py
    OpenQASM 3 round-tripStrict serialization, import, and semantic replaypassedQASM and report when generated
    Lean certificateExact proof authority at the page's stated semantic tierpassed17 named root(s)

    Replays the actual Ry/CNOT gate list using independent NumPy and Qiskit evaluators and an OpenQASM round trip. Reports finite floating-point evidence, not a general exact certificate.

    Current runnable artifact
    executable-exports/SP-HERMITE-001/qiskit/export.py
    Command
    python3 executable-exports/SP-HERMITE-001/qiskit/export.py --self-test
    Trust boundary. Fast executable checks may reject, rank, or queue a route for formalization. Floating-point tolerances do not replace the exact Lean roots above; an external exact certificate contributes only after a Lean checker verifies it.
    Source
    Jin–Liu–Ma, arXiv:2403.19123v3, Section 4.3, Eqs. (4.31)–(4.32).
    Contributor
    ASPBE authors
    Current boundary
    For fixed k the new quantum gate/depth bound is linear in \(n_p\); k is not hidden as a constant when it varies. L is any positive real in Lean, but executable experiments accept positive rational L. Several stored preprocessing components have polynomial bounds in an explicit exact-real operation model; the composed full compiler and a uniform epsilon/bit-cost certificate remain open. Finite QASM replay is not a symbolic family certificate. PDE recovery, Fourier convergence, hardware synthesis and global optimality are outside this certificate. Arbitrary amplitude tables need not have a small bond dimension.