Consider a toy problem wherein we’re given a black box function called f which operates on four 1-bit inputs we’ll label b1,b2,b3 and a. f is stateful, and perhaps better interpreted as a “circuit” with the following behavior:
f=⎩⎨⎧a←¬a if b1a←¬a if b2a←¬a if b3
The catch is that any subset of those cases might be ignored, deleted, faulty, flipped by a gamma ray1, etc. E.g., we might receive an f with the second case “deleted” resembling:
f=⎩⎨⎧a←¬a if b1a←¬a if b3
For an instance of this problem with n inputs, there are 2n−1 possible subsets of “missing” statements which can be interpreted as toggles acting on our accumulator. (2n−1 since we discount the a which accumulates the effect of the other inputs).
We can consider the set of all possible configurations of this black box function f with 4 arguments (3 input bits and one accumulator bit):
Where the subscripts correspond to which cases are present in the function. The problem statement is: given some unknown function f∈Fn, we want to determine whichf we’re dealing with in as few invocations or “queries” to f as possible.
An initial naive approach might be to select an arbitrary initial binary string, say 0ˉ, flip the first bit, pass it to f and observe what happens. For f∈F3 this might look like:
f(1000)→1001
This tells us that the first case (toggling a contingent on toggling b1is present in our given f). Not that this logarithmically eliminates fully half of the 23 possible fs (the ones where b1 is absent, deleted, corrupted, etc.):
So we know that our given function must be fb1,b3, but that took n=3 total invocations for a mystery function with 3 inputs. Can we do better? We might experiment with more “sophisticated” input string combinations, but we’ll quickly find that regardless of our input to f, we can never eliminate more than half the possible remaining answers at any iteration of this sluethy procedure.
To prove this, let’s consider what information we gain by sampling f. Or, donning our Shannon deerstalker, perhaps a better question to ask is: how much information do we gain?
The answer is –perhaps obviously from the framing of the problem statement thus far– precisely 1 bit of information which gets encoded in the last bit of the output a. So, the answer is, with classical computing techniques: … no, we cannot do better than n queries to f.
Suppose that there did exist a procedure which lets us identify the f∈F3 with only two invocations. We would have at our disposal 2 bits of information:
f(∙)=…a1f(∙)=…a2
Leaving us with four possible combination of a1,a2:
a1a2={00,01,10,11}
But there are still eight possible choices for f∈F3 and 2 bits of information still only inform on four of those possibilites, so we can conclude that any such procedure which claims perfect accuracy is WRONG since there’s simply not enough information. Not with classical computing techniques, that is. With quantum computing, we can get the number of invocations of f down to one singular sample for any naturally numbered n by leveraging some sick linear algebra on the properties of qubits.
Quantum
A qubit is the fundamental data type in quantum computing. Typically denoted ∣ψ⟩, with the bracket notation indicating that the value of x can exist somewhere in between the two basic states: ∣0⟩ and ∣1⟩. The measure of a qubit’s propinquity to each basic state is denoted as an amplitude:
−1.0≤α∣0⟩≤+1.0−1.0≤α∣1⟩≤+1.0
And we can omit the amplitude’s subscript when the basic state being referenced is unambiguous.
Crucially, we don’t need a concrete implementation of a device which can replicate superposition (though this is more achievable than we might initially assume) in order to reason about quantum quantities.
Properties of Qubits
Measuring a qubit’s amplitude collapses it to one of its basic states depending on the amplitude. The exact rule governing which basic state is observed when a qubit collapses is given by the amplitude of that basic state squared:
p[∣x⟩=∣0⟩]=α2
E.g. for a qubit ∣x⟩ with amplitude α∣0⟩=0.8, and since we know that the probability of observing one of the two possible basic states must sum to one, we have:
Note that this also allows for negative amplitudes, e.g. this is an equally valid quantum state for ∣x⟩ to be in:
Since α∣0⟩2+α∣1⟩2=1.
Similarly to classical bits, for n qubits, there are 2n possible measurements which are the 2n possible basic state configuration after measuring each of the qubits’ amplitudes. However, collections of qubits form quantum systems, the constituents of which cannot be meaningfully considered in isolation.
E.g. For n=2 qubits, we have a system of 4 basic states:
With some amplitude on each of the basic states where the sum of the squares of said amplitudes is one:
While it may seem natural to assume that each qubit on its own has distinct amplitudes on each of its basic states, this is not the case. Together, the n qubits jointly have amplitudes on each of their 2n basic states. This property is called quantum entanglement and is precisely what gives rise to the clever solutions found in quantum programming which are not possible with conventional approaches.
Quantum Programming
A quantum program takes as input n qubits in some valid superposition of the 2n basic states and takes them to some other (excluding the identity QP, I guess) valid super positions. In other words, a quantum program is any set of operations which satisfies the pre- and post-condition:
i∑2nαi=1
Where i is expressed in base 10 [footnote, this is a base joke. Base two]. A quantum operation we might be interested in to solve the problem from earlier would be qubit negation on n qubits. This can be achieved by “swapping” amplitudes of corresponding basic states. The operation can be visualized on a n−dimensional cube. E.g., for n=3:
The “toggle” or negation operation swaps a corner on the face of the cube where qi=0 with The corner where qi=1, and i∈{1,2,…,n}
This operation is one of three named for Mathematician Pauli, and is denoted X or σx. We’ll cover the other two operations in a following section. Note that, without even knowing how to quantitatively represent this negation operation, we know that it is a valid one since it doesn’t violate the pre- and post-condition of squared amplitude summation to one.
To avoid have to bother validation summations for each quantum operation we might want to define, we can institute an abstraction constraint that these operations only define how each of the basic states are transformed in terms of one another rather than modifying amplitudes directly. This opens many direct analogs to linear algebra that might already be showing around the cracks of this ELI25AIDKALA2 explanation.
This abstraction constraint begs the question, though, what about non-basic states? E.g. what if we composed a 1-bit probabilistic operator with our negation “gate” which toggles the a qubit of a basic state with p=2/3 and does nothing the rest of the time:
RNG(q)=⎩⎨⎧σx(q)Id(q) if p∼U<2/3 if p∼U≥2/3
We can again visualize this behavior as a tree without having to worry our pretty little brains with any quantitative conception of what the hell we’re talking about (pictures r fun):
We can see that the probability of observing any of the basic states of this system is just the product of the probabilities of descending down any branch π of this amplitude tree that results in that basic state ∣01⟩:
p[∣AB⟩=∣01⟩]=i∈π∣01⟩∏pi=1×32×1=32
Quantum program analysis is almost identical, the only difference being that quantum instructions operate on amplitudes which can be negative whereas a classical stochastic decision tree operates on probabilities on the unit interval. Conveniently for us, this means that some of the amplitudes might cancel each other out, whereas in the classical context, probabilities are strictly additive (in the monotonically increasing sense of the word).
So far the two operations we’ve defined so far, σx and simple conditionals, don’t offer any further utility than those gates which are already available in classical circuitry as evidenced by their amplitude trees which don’t introduce any quantum branching:
It’s now time to introduce non-trivial non-basic qubit states. Let’s define a unary function: Rotate(q):∣ψ⟩→∣ψ⟩ with the following amplitude tree:
We can easily verify that it’s a valid quantum operation since it maps valid quantum states to other valid quantum states. Now suppose we have another operation f which takes some qubit in the zero state and transforms it to a qubit with some amplitudes x,y on each of its basic states s.t. x2+y2=1. We can (non-rigorously) check that Rotate is valid by passing f(q) as its input and examining the resultant amplitude tree:
Collapsing the amplitudes to measure the distribution over basic states, we get:
So, Rotate is valid ■. An example of an invalid operation might be assignment. Yes, that most basic of instructions we might expect to see in a program:
q←∣0⟩
Verboten! We can develop some intuition about this by subjecting assignment to the same procedural treatment as Rotate:
Now, for a non-trivial quantum operation, and perhaps the most important (? depends who u ask, where my Hadamard truthers at), the Hadamard [Link to other mentions throughout the blog]:
Let’s observe how it behaves with some of our other operations:
And we can go a step further by enumerating the amplitudes on each of the basis states at each of the six steps of the program:
instr
∣000⟩
∣001⟩
∣010⟩
∣011⟩
∣100⟩
∣101⟩
∣110⟩
∣111⟩
init
+1
Toggle(q1)
0
+1
Hadamard(q1)
+0.71
+0.71
Hadamard(q3)
+0.5
+0.5
+0.5
+0.5
if q1 and q2 Toggle(q3)
+0.5
+0.5
+0.5
+0.5
Hadamard(q3)
+0.71
+0.71
Note that – even though the +0.5 amplitude appears on the ∣011⟩ basic state, the final amplitude on this state is zero because both of the branches where it appears have inverse amplitudes which cancel each other out. And herein lies the crux of quantum programming: designing algorithms where the amplitude of undesirable quantum states cancel out:
This isn’t always feasible, however. Sometimes the best we can do is leaving a subset of ”undesirable” output states with a minimal amount of amplitude and then relying on probabilistic correctness over a series of trials.
Designing Quantum Programs
Since the state of n qubits can be fully described by a collection of 2n amplitudes, it’s natural to model n qubits as 2n-dimensional vectors containing amplitudes on each of the basic states:
With a vector spanning eight dimensions (1 for each basis) corresponding to each of the basic states, we can easily visualize up to three of those dimensions. And, per the sum-squared amplitudes theorem, we can geometrically represent the state of the qubits as a point on the 2n-dimensional unit sphere. This is fun to say, but for any number of qubits greater than 1, we need at least 4-dimensional space which is more than you might be able to visualize.3 Before getting bogged down with n-dimensional visualizations, let’s play with our linear algebraic interpretation of qubit state for n=1 which is nicely represented on the plane:
We can describe quantum instructions operating on qubits as matrices of transition amplitudes multiplied by the state vector.
Now, back to the harsh realities of n>3-dimensional space, suppose we have two qubits q1,q2 and we want to compute the Hadamard matrix for this system: H⊗2.
For Hq1, we can just fill in transition amplitude entries in the matrix for basis state pairs where q2 doesn't change:
Hq1=211010010110100101
And, similarly we can compute Hq2 for values where q1 doesn't change:
Hq2=211100110000110011
Furthermore, we can compose them via normal matrix multiplication to compute H⊗2=Hq1⊗Hq2 – and order actually doesn't matter for these operations since they modify different qubits by construction:
and recall that matrix multiplication with a vector with a single entry of 1 essentially acts as a select on that column s.t. our resultant product is the second row of our Hadamard matrix as a column vector:
∣ψ⟩H⊗3=+−+−+−+−
Then, we invoke f on the quantum state which –if we remember that far back– toggles the accumulator iff b2 in the input string is set. This has the effect of applying f to each entry in the vector, examining the middle bit of each basis state:
Note that, prior to this step, all states where the accumulator bit was 1 had negative amplitude, and all states where the accumulator bit was 0 had positive amplitude. When we invoke the oracle f, the basis states where the accumulator doesn't change still have positive amplitude if the accumulator bit is unset and negative if it is set, just like before – but those basis states where the accumulator did get toggled now have the inverse amplitude pattern (− if a=0, and + if a=1) which encodes a sort of truth table for f where positive amplitudes correspond to TODO: ???
In other words, taking the basis state ∣010⟩ which has negative amplitude implies that if b1=0,b2=1,a=0, then a will be 1 after f is called. Conversely, in ∣100⟩ the accumulator bit is unset since it has positive amplitude.
Now we run into another problem: if we were to try to measure the qubits now, the amplitudes would collapse to pure noise since all the magnitudes would cancel each other out and we'd effectively get a random 3-bit binary string as out output. To account for this, we just plop in another H⊗3 and, curiously, the purpose of this operation is completely different to the columnal selection from earlier since our state vector is no longer of the correct form to pick a single entry.
Again, it's useful to visualize what happens when we perform this multiplication:
As we can see, as we compute the matrix multiplication all the amplitude values gradually accumulate on the ∣011⟩ basic state such that when we measure all the qubits, we learn the configuration of the mystery f∈F3 that we were given with p=1. The proof that this program is correct for fixed n is trivial via programmatically enumerating all variations of f.
If this seems like too convenient or mystically clever of a solution it's because this sequence of operations was discovered prior to the declaration of the problem statement. The problem of "mystery f" was retconned as a problem to motivate this demonstration of a quantum system offering constant time solution to a problem with linear complexity by classic means. This problem is known as the Bernstein-Vazirani problem, and is one of many similarly contrived examples of "quantum supremacy."
Formally, the Bernstein-Vazirani4 problem is posed: given an oracle f:{0,1}n→{0,1} where all that's known of f is that it's output is the dot product between the input vector and a secret string s∈{0,1}n modulo 2, we're tasked with finding s s.t.
f(x)=x⋅s=x1s1⊕x2s2⊕⋯⊕xnsn
More Math
Now that the gloves are off in terms of the linear algebra, let's revisit some of the earlier handwavey definitions of qubits and quantum gates.
Qubits as vectors
A qubit can be expressed as a linear combination of the amplitudes and the system's basis states:
∣ψ⟩=a∣0⟩+b∣1⟩
where a,b∈C, though we can largely ignore the complex components of pretty much all the systems and gates we'll cover (for explanations of the global phase described by complex components, ur gonna need an ELI35). As a linear combination, quantum states are easily expressed as vectors:
The basis states of a quantum state vector span the 2D Hilbert Space which is just a well-defined complex vector space where the inner product exists.
Normalization Condition
The aforementioned "validity" rule for quantum states is known as the normalization condition:
∣a∣2+∣b∣2=1
For an n-dimensional system, we sum over the squares of the amplitudes of all basic states:
i∑∣αi∣2=1
Quantum Operations
Operations on single cubits can be expressed as 2x2 unitary and hermitian matrices. Unitary to ensure the conservation of amplitude, and Hermitian to ensure that the eigenvalues (measurable quantities which need to correspond to real world things) are real valued.5
A matrix U is said to be unitary if its inverse equals its transpose conjugate (also known as the hermitian adjoint) U†:
U†U=UU†=I
The hermitian adjoint operation is a linear map which transposes an m×n complex matrix and conjugates each entry (negating the complex component).
A=[00a+bi0]⟹A†=[0a−bi00]
For real matrices, the hermitian adjoint is just the transpose.
Bloch Sphere
Quantum operations on singular qubits can be visualized as maps between points on the unit sphere. As mentioned earlier, this also holds for systems of multiple qubits on hyper spheres but the utility of the Bloch sphere diminishes proportionately to one's ability to visualize higher dimensions and rotations therein.
Here, θ,ϕ are the usual polar and azimuthal angles in spherical coordinate representation. The Pauli gates, then, are just rotations about these axes by π radians. E.g.
again we drop the complex component since we're ignoring global phase of the quantum system, and just rotate dat boi about the x-axis (as observed in the planar example):
Similarly, this process yields a geometrically intuitive conception of the other two Pauli operations:
Note that each of these are involutory, meaning that their squares are equal to the identity matrix. From these Pauli matrices, we can also generalize to arbitrary rotation operations:
It should be clear(er) now that all qubit operations acting on an n-dimensional quantum system map a point on the hypersphere to another point, which can always be achieved via some rotation, e.g.
so the Hadamard is just a rotation about the diagonal on the xz-plane of the Bloch sphere. Two applications of a rotation by π will complete a full revolution about the sphere, returning to the original point.
Multi-qubit Systems
Recall that singular qubits occupy 2D Hilbert Spaces:
∣ψ⟩∈HA,∣ϕ⟩∈HB
The state vector of a composite system of two qubits is given by the tensor product of the two constituent state vectors being combined, where the tensor product ∣Ψ⟩ is defined as follows:
And since the tensor product is distributive, we can also write a combination of operations in such a way is explicates the fact that each quantum operator is acting independently on the composite state space:
(A⊗B)(∣ψ⟩⊗∣ϕ⟩)=A∣ψ⟩⊗B∣ϕ⟩
With this representation of multi-qubit systems, we can introduce some multi-qubit operations.
Multi-qubit Operations
Thus far, we've only defined single-qubit gates/operations, but we can also perform some actions on multiple qubits at a time, with a few crucial distinctions from classical logic gates. For starters, quantum gates must be reversible. Whereas it's entirely common for classical logic gates to map multiple inputs to a single binary output, since quantum systems model state changes in physical systems, the modifications made to each of the inputs must also be expressed in the output. The above description is phrased as a constraint, but it's really just a natural conclusion from the prior definitions about quantum operations being unitary & hermitian – which lets us simply apply the adjoint of an operation to "undo" it.
classiscal gate
reversible?
AND
sometimes
OR
no
NOT
yes
NAND
no
XOR
no
It should be straightforward to convince yourself that the input vector to these gates is not definitively knowable given the output bit/vector.
CNOT
The Controlled-NOT gate is analogous to the the classical XOR which can be thought of as addition mod2 given by the following truth table:
⊕
0
1
0
0
1
1
1
0
Observe that, for a 2 qubit system, q1 remains unchanged, and the state vectors of q2∈HAB are swapped:
∣00⟩↦∣00⟩∣01⟩↦∣01⟩∣10⟩↦∣11⟩∣11⟩↦∣10⟩
Algebraically, we can express this as the matrix:
UCNOT=1000010000010010
We can use CNOT to swap the states of two qubits the same way we might swap two classical variables' values without introducing a tmp value with three XORs:
b1
b2
b1⊕b2
b1⊕(b1⊕b2)
0
0
0
0
0
1
1
1
1
0
1
0
1
1
0
1
so b1⊕(b1⊕b2)≡b2.
and, in fact, we can represent any C-gate applied to an operation U with this procedure:
CU=1000010000u00u1000u01u11
Toffoli
The Toffoli gate is effectively a CNOT on a 3-qubit system:
The Toffoli truth table indicates that q1,q2 remain unchanged, and q3 only changes if both q1=q2=1:
q1
q2
q3
q1′
q2′
q3′
0
0
0
0
0
0
0
0
1
0
0
1
0
1
0
0
1
0
0
1
1
0
1
1
1
0
0
1
0
0
1
0
1
1
0
1
1
1
0
1
1
1
1
1
1
1
1
0
Entanglement
Recall from the section about multi-qubit states the expression:
(A⊗B)(∣ψ⟩⊗∣ϕ⟩)=A∣ψ⟩⊗B∣ϕ⟩
When a 2-qubit composite state function can be expressed as a tensor product of the constituent qubit states like this, then the composite state is said to be separable. E.g.
For example, we can show that the following quantum state is separable:
∣ψ⟩∣ϕ⟩=21∣0⟩+21∣1⟩∈HA=∣0⟩∈HB
The tensor product between ∣ψ⟩ and ∣ϕ⟩ yields the following composite state:
∣ψ⟩⊗∣ϕ⟩=21∣00⟩+21∣10⟩∈HAB
And we can verify this is separable by checking if the product of the differences of amplitudes along the major and minor diagonals cancel each other out:
which should be a surprise since this composite state was constructed from separated states via the tensor product :p. By means of counter example, let's take a look at a special quantum state in HAB:
Since the amplitudes don't cancel out, this state is inseparable or entangled. This quantum state ∣Φ+⟩ is one of four maximally entangled systems referred to as the Bell States.
But what does it mean to be maximally entangled? Before tackling this question, or motivating even why we care, it's time to really get our hands dirty.
Dir-Ac notation
Commonly referred to as "bra-ket" notation, but it's more fun and kind of conventional to summon up some new fangled notation to become one-up on your academic peers.
Ket's we're familiar with, but what the hell was Dirac smoking with those bras.6 First let's consider a linear function ℓx which maps a 2-dimensional vector to a scalar by just shitting out the x component of its input:
ℓxℓxvℓx[vxvy]:R2→R=vx=vx
ℓx is indeed a linear map since it satisfies the following properties:
ℓx(u+x)ℓx(cv)=ℓxu+ℓxv=cℓcv
Linear maps of this form which take an element of our vector space and shit out a scalar are called linear functionals. The algebraic representation of ℓx will be a 2x1 matrix, AKA a row vector:
ℓx=[10]
All linear functionals in R2 are two-dimensional row vectors. In other words, the set of all linear functions in R2 is the set of all row vectors of the form [ab], and thus this set forms its own vector space known as the dual space.
Formally, given a vector space V, the dual space V∗ is the vector space of all linear functionals in V. Linear functionals find natural relevance in quantum mechanics wherever we want to measure a quantum state which is the process of "collapsing" the quantum state into a single number which resembles ℓx:R2→R.
We denote linear functionals in quantum mechanics as those functions of the dual of the Hilbert space with "bras": ⟨ϕ∣∈H∗, operating on kets. Note how when we smush a bra together with a ket, we get something that looks an awful lot like an inner product:
⟨ϕ∣∣ψ⟩[10][ab]=c=1⋅a+0⋅b≡[10][ab]
any ℓ∈R2 acts on any vector and can be expressed as a dot product by translating ℓ into a column vector courtesy of the Riesz Representation Theorem.7 I guess this is like significant if you're smart enough to have mentally bifurcated row vector/matrix multiplication as different than the dot product and thus this revelation may seem inobvious or maybe even haram. But, obviously, my brain was already rotating row vectors into column vectors (or maybe the other way around, idek), without realizing the profundity of being able to do so.
For any linear functional ℓϕ, the action of ℓϕ is equivalent to taking the inner product with some unique vector ϕ:
ℓϕv=ϕ⋅v
So, it's no mistake that:
⟨ϕ∣∣ψ⟩≡⟨ϕ∣ψ⟩
This is useful for increasingly many reasons (as I'm realizing). Take, for example, the orthonormal basis of the vector space of a quantum system to be:
∣B1⟩,∣B2⟩,∣B3⟩,...
and an arbitrary qubit of the system as:
∣ψ⟩=i∑αi∣Bi⟩
Since all of the states are orthonormal, we can compute their amplitude coefficients as:
There are two measures of entanglement we'll consider. The first being the Positive Partial Transpose, and the second being a more comfy Von Neumann entropic measure.
Positive Partial Transpose
Let ∣Ψ⟩∈HAB, and the density matrix ρ=∣Ψ⟩⟨Ψ∣. The trace of ρ (the sum of the eigenvalues, including duplicates), is given by:
Tr(ρ)=j,k=0,1∑(⟨j∣⊗⟨k∣)∣Ψ⟩⟨Ψ∣(∣j⟩⊗∣k⟩)
which is the sum of the inner product with the basis vectors of the composite state. For an n=2 qubit system, we have 4 basis states, the trace of which is a scalar. The partial trace of a density matrix is the trace only on a part (or slice) of the Hilbert space, and yields what is known as the reduced density matrix:
we can see that the partial reduced density matrix collapses the outer product between the j,l kets where the indices j=l, thus the density matrix of ρA is a 2x2, whereas ρ is 4x4. We can recastρA in terms of the outer products of μ via substitution:
Which means that we have exact information about the quantum system since the reduced density matrix is a pure state given by a single outer product instead of e.g. a mixture of outer products.
An impure, or mixed state for the partial density matrix of a non-separable state would have the form:
ρA⟹Tr(ρA2)=∣0⟩⟨0∣+∣1⟩⟨1∣+⋯<1
Perfect mixed states are those where there is zero measurable information of the system, the partial density matrix of which are proportional to the identity matrix:
ρA⟹Tr(ρA2)=21I=21
implying that we have equal likelihood of measuring a qubit's state in any of the basis states. The bounds for our measure of entanglement, then, is:
21≤Tr(ρA2)≤1
An example of a maximally entangled state could be any of the Bell states:
This, if nothing else, is an illustrative example of how linear functionals behave, but is a rather painful measure of entanglement.
Von Neumann Entropy
An equally valid measure of disorder of a quantum system is Von Neumann Entropy, defined as:
E=−x∑p(x)logp(x)
For quantum systems p(x) is equivalent to measuring the state vector ∣ψi⟩∣. We can show that Von Neumann entropy is equivalent to:
E(ρ)=−Tr(ρlogρ)
Working backwards from the classical definition, and recalling that the eigenvalues of ρ correspond to the measurable quantities of our quantum system we replace p(x)=pi with the eigenvalues λi:
E=−i∑λilogλi
We can derive this result from the definition of the density matrix:
ρ=i∑pi∣ψi⟩⟨ψi∣
which is equivalent to the spectral decomposition of the matrix formed by the outer product within the sum above:
ρ=i∑λi∣i⟩⟨i∣
This will be a diagonal matrix of the form
λ10000λ20000⋱0000λn
where n specifies the dimensionality of the Hilbert space of the system, and the diagonal matrix is in the basis of ∣i⟩. Plugging this expression of ρ back into the Von Neumann definition, the sum can be written as the Trace operation:
Given a binary lattice G=(V,E), where n=∣V∣, a binary vector b∈{0,1}n, and a sparse n×n adjacency matrix for G: A – sparse in the sense that Aij=0 unless i,j correspond to neighboring vertices on the lattice: ∣i−j∣≤1:
Aij=⎩⎨⎧00 or 1if ∣i−j∣>1o.w.
e.g. for n=42 we might have a grid that resembles:
![[HLF-1.png]]
q(x)=1≤i<j∑n2Aijxixj+i=1∑nbiximod4
where x=[x1,x2,...,xn]∈F2 are binary values. A quadratic form is a polynomial where all terms are degree two, and note that since all our variables are binary-valued, xi2=xi, so that second summation, though appearing to be degree one (and thus, not quadratic, is in fact equivalent to the sum of the squares of bixi).
We further restrict q(x) onto the linear subspace Lq given by:
Lq={x∈{0,1}n:q(x⊕y)=q(x)+q(y)∀y∈{0,1}n}
where ⊕ is arithmetic on the binary ring i.e. mod 2. It's also worth noting that, by design, Lq is the null space, or kernel of A – that is:
Ax=0∀x∈Lq
Together, the definitions of q and Lq imply that there exists at least one vector z∈{0,1}n s.t.
q(x)=2i=1∑nzixi,∀x∈Lq=2z⊤x
We can find all the solutions classically by exhaustively checking all y∈{0,1}n like so:
import numpy as np
classHLF:"""
A: a symmetric adjaceny matrix of "weights" for a lattice
b: vertice "weights"
"""def__init__(self, A, b): self.n = A.shape[0]assert A.shape ==(self.n, self.n)assert b.shape ==(self.n,)# symmetricassert np.array_equal(A, A.T)# only neighboring cells can be connectedfor i inrange(self.n):for j inrange(self.n):if A[i][j]==1:# I am the smartest man alive. Google and MathStackExchange BTFO'd# I'd like to thank Daniel Shiffman and my whiteboardassert(abs(abs(i - self.n)-abs(j - self.n)))%2==1 self.A = A
self.b = b
Note that this code is adapted/corrected from an example on Google's quantumai page, but they botch a few crucial aspects of the problem constraints.
Notably, this can be accomplished with a constant-depth circuit:
![[HLF-2.png]] To build these chonker matrices, we can first define some helpers:
A = np.array([[0,1,1,0],[1,0,0,0],[1,0,0,0],[0,0,0,0]])b = np.array([0,0,1,0])n = A.shape[0]Z =[[1,0],[0,-1]]S =[[1,0],[0,-0j]]H =1/ np.sqrt(2)* np.array([[1+0j,1+0j],[1+0j,-1+0j]])qubits =[np.zeros(4)for _ inrange(4)]for i inrange(n): qubits[i]= qubits[i] @ H
for j inrange(n):if A[i][j]==1: qubits[i]= qubits[i] @ Z
if b[i]==1: qubits[i]= qubits[i] @ S
qubits[i]= qubits[i] @ H
which leaves our qubits in a state of z.
Again, this problem is psychopathic because it only exists as a variant of Bernstein-Vazirani to prove that quantum circuits can be used to solve classically exponential sized problems with a constant depth of quantum circuits.
Real Problems Have No Solutions
Microsoft just patted themselves on the back so hard they dislodged a rib,11 announcing a new "topological" chip which offers a path to million-qubit systems. This number is significant since that's the order of magnitude required for Shor's algorithm to be remotely viable.12,13 And even then, there are already provisions for "post-quantum" crypto.14
Footnotes
Footnotes
Accounting for cosmic ray bit flips on board Voyager-2↩
Explain Like I’m 25 And I Don’t Know Any Linear Algebra ↩
Ethan Bernstein and Umesh Vazirani. "Quantum Complexity Theory." SIAM Journal on Computing Vol. 26, No. 5. 1997. ↩
that's not to say that complex values have no "real world" significance. I'd be loath to perpetuate the notion of "imaginary" numbers being just that – it's just that, for our intents and purposes lol, the complex components are imaginary, negligible, and we just need some guard rails to ensure this model doesn't fly off the rails to silly town aka imaginaryville. ↩