View on GitHub
Open this notebook in GitHub to run it yourself
- Quantum Variables and Quantum Types
- Output Parameters and State-Preparation Functions
- Classical Parameters
- Classical Control Flow
- Quantum Assignment and Arithmetic
- Control Statements
# TODO, then synthesize and run it. All solutions are
collected at the end of the notebook - try each exercise before peeking.
Part II then builds on these foundations with six more concepts - the statements and operators used to express real quantum algorithms.
Note: If you are working in your own SDK environment, make sure Classiq is installed (pip install -U classiq) and that you have authenticated once by runningauthenticate()in a Python session. See the registration and installation guide.
Warmup
- Quantum Functions and
main
@qfunc decorator designates a
quantum function - a
function that applies operations to quantum objects.
The entry point of a quantum program, that is, the quantum function synthesized into an executable, must be named main.
The quantum parameters of main are designated with the Output-modifier, and they are measured when the program is executed.
Function main can call other quantum functions.
A typical SDK flow is:
- Compile the high-level model into a gate-level quantum program with
synthesize(). - Visualize the quantum program with
show(). - Execute the program and sample the state prepared in its output variables with
sample().
Expected result: roughly 50% of the samples are the bit vector00and 50% are11- the two qubits are perfectly correlated.
- Quantum Variables and Quantum Types
QBit- a single qubit.QNum- a number, supporting arithmetic and comparisons.
QNum[3, SIGNED, 0]).
QArray- an indexable array (e.g.my_qarr[i]) of elements of any quantum type;QArray[QBit]is the most common.QStruct- a struct of named fields (e.g.my_qstruct.f); we’ll return to structs later.
QNum, QArray[QBit]) and the
compiler infers them when the variable is initialized.
Function arguments are automatically cast between quantum types of the same size - e.g. between
QArray[QBit] and QNum - so the same function can operate on either.
Exercise A: Based on the Bell-state example above, complete create_ghz_state to prepare a
3-qubit GHZ state , then synthesize, show, and
sample it.
Expected result: roughly 50%Exercise B: Reuse the same000and 50%111.
create_ghz_state from Exercise A, but this time call it on a
signed quantum number x (QNum[3, SIGNED, 0]) instead of a qubit array.
Synthesize and
sample it.
What values do you expect to measure?
Tip: Thanks to automatic casting betweenQArray[QBit]andQNum, you don’t need to changecreate_ghz_stateat all. The bit string111is interpreted as for a signed integer (in two’s-complement representation, the MSB has weight , so111).
Expected result: roughly 50% for the value0and 50% for the value-1.
- Output Parameters and State-Preparation Functions
Output makes it output-only: it starts uninitialized and must be initialized inside the function.
A variable is initialized by:
- allocating fresh qubits in the state (using
allocate()) - assigning an object in a state specified as an expression (using
|=) - calling a state-preparation function (a function with an
Outputparameter)
Note: All ofClassiq provides built-in state-preparation functions. Two closely related ones:main’s parameters must beOutput- as the entry point, there is nowhere they could have been initialized beforehand.
prepare_state(probabilities, bound, out)- allocates a fresh object and prepares it in a state whose measurement distribution matchesprobabilities(out-of-place).inplace_prepare_state(probabilities, bound, target)- applies the same preparation to an already-allocated objecttarget(in-place), assumed to be in the state.
bound determines the maximum allowed error.)
Exercise A: Load the same distribution dist two ways, to contrast the two functions:
- Use
prepare_stateto loaddistinto a fresh variablea. - Use
inplace_prepare_stateto loaddistinto an already-allocated variableb.
dist has 8 entries, so each variable holds 3 qubits.
Expected result: The probability of measuringExercise B: The cell below fails - the variable000on bothaandbis the highest - , and the probability of measuring111on both should be the lowest - .
q is never initialized.
Run it to see the
error, then fix it such that prep is responsible for initializing q.
- Classical Parameters
prepare_state().
Classical parameters are declared with Qmod classical types
CInt,CReal,CArray, etc.
my_qnum.size) and the length of arrays (e.g. my_qarr.len) are also classical expressions in Qmod.
When main has a classical parameter, its value is left symbolic throughout the compilation process, and is only determined upon execution.
This is useful for hybrid quantum-classical algorithms.
Note: Qmod classical types (Exercise A: Define the functionCInt,CReal, etc.) remain symbolic through compilation. Parameters declared with plain Python types (int,float) also work, and can be used in arbitrary Python expressions. But they can’t serve as execution parameters, and they might hurt compilation performance. See also generative descriptions.
rotate to rotate qubit ind of qarr about the X axis by turns, given as a fraction of the full rotation. (Here the classical parameter turns is used inside an expression, not passed directly.)
Expected result: Note how the parameterExercise B: Rewrite functionturnsunderrotateremains symbolic in the quantum program visualization.
main from Exercise A such that it takes two execution parameters, alpha and beta, for the rotation of the two qubits, instead of hard-coding them inside main.
- Classical Control Flow
repeat, foreach, and if_. To specify the body of the loop, or the branches of the conditional, you typically use lambda expressions. In repeat and foreach, the iteration variable is the lambda parameter. power is a unique form of a loop statement with no iteration variable, and stronger optimizations for some special cases.
For example, the following uses repeat to apply a Hadamard gate to each qubit in a qubit array (the Hadamard transform):
hadamard_transform, which we’ll use in later sections.
Note: PythonExercise: Rewriteforandifstatements can be used inside Qmod functions. But these Python statements cannot use Qmod (symbolic) variables. They generate a flat unrolled description, which can impact compilation performance.
rotate from Section 3 so that it takes an array of turn-fractions and rotates the ith qubit of qarr by the ith value (you can assume that the arrays are of the same length).
- Quantum Assignment and Arithmetic
QNum variables; the compiler
synthesizes them into reversible quantum circuits automatically.
There are three flavors of
assignment:
- out-of-place:
res |= exprallocatesresand sets it to the result ofexpr.
- in-place-add:
x += expraddsexprinto an already-initializedx. - in-place-xor:
x ^= exprXORsexpronto an already-initializedx.
x and y into uniform
superposition, then use |= to compute both their sum total = x + y and their product
prod = x * y.
Synthesize and sample.
Expected result:Exercise (in-place): Initializexandyare each uniform over 0-3; each row showstotal = x + y(0-6) andprod = x * y(0-9) for that pair of values.
acc to the fixed value 4, then add a superposed y into it
in place with +=.
Notice how acc becomes correlated with y.
Expected result:acc = 4 + y, i.e. 4, 5, 6, and 7 - each paired with theythat produced it.
- Control Statements
control operator conditionally applies a quantum operation. In its basic form the condition
is that all control qubits are , but Qmod generalizes this: the condition can be any
Boolean expression over quantum numeric variables - comparisons (==, <, >=, …) and
logical operators (&, |). It resembles a classical if statement, except the operation is
applied in superposition over the states that satisfy it.
For example, the following applies H to q only when the control qubit flag is :
Tip:Exercise: Put a 3-qubit numbercontrolalso accepts an optionalelse_block=that applies when the condition is False. And the condition can involve real-valuedQNums too (e.g.x < 0.5), not just integers.
x into uniform superposition, then flip the target qubit to
only for the basis state where x equals 5.
Expected result:xis uniform over0-7;targetis1only in the row wherex == 5, and0everywhere else.
Solutions
Try each exercise before checking the solution below.Solution 1
- Quantum Variables and Quantum Types
- GHZ on a qubit array**
- GHZ on a signed integer**
Solution 2
- Output Parameters and State-Preparation Functions
Solution 3
- Classical Parameters
Solution 4
- Classical Control Flow
Solution 5
- Quantum Assignment and Arithmetic
Solution 6
- Control Statements