Property-based testing framework for qiskit algorithms.
Project description
Qiskit-PTesting
This project aims to implement property-based testing for quantum circuits using the qiskit library for Python 3.6+.
To learn more about qiskit, follow this link.
I also recommend following their tutorials on quantum computing.
To learn more about property-based testing in general, follow these ressources: Intro to property based testing, Wikipedia page.
Installation
-
Run
pip install qiskit-ptestingin a terminal environement -
In any python file where you want to define property tests, add:
from Qiskit_PTesting.Qiskit_PTesting import QiskitPropertyTest, TestProperty, Qarg
That's it, you should be able to define tests in the same file.
Usage
- Create a superclass of "QiskitPropertyTest" using any name you want
- In that class, define 3 functions (optionally leave them out for default behaviour):
property(self)quantumFunction(self, qc)assertions(self)
- Inside of the function
property(), define a TestProperty object and return it - Inside of the function
quantumFunction(), define which steps are needed to be applied to qc (the quantum circuit). All of the generated tests will have those operations applied. - Inside of the function
assertion(), define which properties you would like to hold true using the built-in assertions. - Run the test class you created using the "runTests()" method.
How to define a TestProperty
A TestProperty object contains all of the necessary information to generate random tests.
It contains:
p_value: The p_value for all tests (float between 0 and 1)nbTests: The number of randomly generated tests (int greater than 0)nbTrials: The number of times each generated test will be run, otherwise called the amount of trials (int greater than 0)nbMeasurement: The number of times each trial will be measured (int greater than 0)nbQubits: The amount of required qubits for each test (int greater than 0, or a list of 2 integers, the 2nd one being greater of equal to the first)nbClassicalBits: The amount of classical bits required for each test(int greater or equal to 0)qargs: A dictionary of Qarg objects for each qubit that you want to initialise to a specific range/value (can be empty)backend: A string that expresses which backend should be used for the measurements. It can be any backend from Aer or"ibmq", which automatically uses the API token stored on the computer.
These are the default values:
testProperty = TestProperty(p_value=0.01,
nbTests=10,
nbTrials=100,
nbMeasurements=500,
nbQubits=5,
nbClassicalBits=0,
qargs={},
backend="aer_simulator")
NbQubits can be an integer or a list. In that case, the framework will generate each test with a random amount of qubits between the two specified values.
How to initalise a Qarg
A Qarg object holds 4 ints that define 2 ranges. A test property will apply this Qarg to initialise a qubit to a random value between those 2 ranges. Any qubit of a quantum circuit can be initilised using 2 values: a theta and a phi. The first range specifies what values theta can be used to initialise a qubit. The second range specifies what values phi can take.
Here is an example Qarg, that specifies that a qubit needs to be initialised with w theta between 0 and 90 degrees, and a phi of 40 to 60 degrees:
qarg = Qarg(0, 90, 45, 60)
The same Qarg can be specified using radians, if the last paramter, isRad, is set to True:
from math import pi
qarg = Qarg(0, pi/2, pi/4, pi/3, True)
A Qarg can also be specified with a statevector with two complex values in the following way:
from math import sqrt
qarg = Qarg([1/sqrt(2), 1/sqrt(2)], [10, 10], False)
The above code initialises a qubit to the state |+>. The second argument specifies that the theta can be up to 10 degrees higher or lower than the specified statevector, and same for the phi. The False means that degrees are used instead of radians.
Finally, some common states can be directly initialised with just one string:
- Qarg("0") initialises to state 0
- Qarg("1") to state 1
- Qarg("+") to state +
- Qarg("-") to state -
- Qarg("Any") to any state on the Bloch sphere
Assertions
6 assertions are up to your disposition:
Single-Qubit assertions
Assert the probability of a qubit to be in state |0>
assertProbability(qu0, expectedProba, qu0_pre=False, basis="z", filter_qc=None)
assertNotProbability(qu0, expectedProba, qu0_pre=False, basis="z", filter_qc=None)
This assertion requires 2 arguments: first, the index of the qubit to be tested, and secondly the expected probability of measuring the qubit in the state |0> along the Z-axis. It can also optionally take in an extra bool argument, that specifies whether the sampling will occur before the quantumFunction is applied. It defaults to False, so the sampling occurs after the function.
Assert that a qubit is in a given state
assertState(qu0, theta, phi, isRadian=False, qu0_pre=False, filter_qc=None)
assertNotState(qu0, theta, phi, isRadian=False, qu0_pre=False, filter_qc=None)
Assert that a qubit has teleported into another
assertTeleported(sent, received, basis="z", filter_qc=None)
assertNotTeleported(sent, received, basis="z", filter_qc=None)
This assertion requires 2 positional arguments: a sent and a received qubit. It evaluates whether quantum teleportation has occured between the qubits.
Multi-Qubit Assertions
Assert the equality or inequality of qubits:
assertEqual(qu0, qu1, qu0_pre=False, qu1_pre=False, basis="z", filter_qc=None)
assertNotEqual(qu0, qu1, qu0_pre=False, qu1_pre=False, basis="z", filter_qc=None)
This assertion requires 2 arguments, which are the indexes of the qubits to be tested, and 2 optional arguments that specify whether the qubits are to be tested before the quantumFunction() is applied. It defaults to False, so if no arguments are specified there, it will compare the qubits after the function is applied. This assertion tests whether the probabilities of measuring two qubits in the states |0> or |1> are the same. The tests are done on the Z-axis.
Assert that two qubits are entangled
assertEntangled(qu0, qu1, basis="z", filter_qc=None)
assertNotEntangled(qu0, qu1, basis="z", filter_qc=None)
This assertion requires 2 positional arguments which are the indexes of qubits. This assertion evaluates whether those two input qubits are entangled.
Assert The Most Common Output(s) Of The Circuit
assertMostCommon(output, filter_qc=None)
This assertion takes in one required positional argument: a string or a list of strings showing the most common states of a circuit
Features
Measure qubit values before the quantum algorithm
By specifying the boolean parameters "qu0_pre" or "qu1_pre" to be True, it is possbile to tell the framework to measure the specified qubit values before or after running the quantum function This is useful in many cases, for example ensuring that a qubit has changed values, or that a qubit is in the same state as another, etc...
An example of using this would be:
class example(QiskitPropertyTest):
def property(self):
return TestProperty(nbQubits=2,
qargs={0: Qarg("0"),
1: Qarg("+")})
def quantumFunction(self, qc):
qc.h(0)
def assertions(self):
#compares the qubits after the quantumFunction is run
self.assertEqual(0, 1)
#compares both qubits before
self.assertNotEqual(0, 1, qu0_pre=True, qu1_pre=True)
#compares qubit 0 after quantumFunction to qubit 1 before
self.assertEqual(0, 1, qu0_pre=False, qu1_pre=True)
Filter generated tests
It is possible to apply a certain assertion to only the generated tests that have a certain attribute. That attribute can be ANY function that returns a boolean and that takes a QuantumCircuit as input. This feature can give a lot of depth to the defined tests, and enables the users to give very general properties about the input program.
Here is an example of a use case of this feature: enabling properties on tests of any length:
from Qiskit_PTesting.Qiskit_PTesting import QiskitPropertyTest, TestProperty, Qarg
min, max = (2, 10)
class example(QiskitPropertyTest):
def property(self):
return TestProperty(nbQubits=[min, max])
def quantumFunction(self, qc):
for index in range(len(qc.qubits):
qc.h(index)
def assertions(self):
#specifies that all the qubits should be equal to each other
for index in range(max):
self.assertEqual(0, index, filter_qc=lamda qc: len(qc.qubits) > index)
example().run()
Change The Backend Used For The Measurements
Aer Simulators
The default simulator is aer_simulator, but all Aer simulators are available to choose.
Simply pass down backend="<any Aer backend>" replacing the string with your chosen backend.
Run Tests On Quantum Computers
In order to run the code on quantum comupters, you have to create an IBMQ account, and specify in the testProperty backend="ibmq"
- Create an account with IBMQ and login
- Copy the API key found in the settings panel of the "My Account" section of the website
- Run the following python code:
from qiskit import IBMQ
IBMQ.save_account("<replace_with_api_token>")
Examples
from Qiskit_PTesting.Qiskit_PTesting import QiskitPropertyTest, TestProperty, Qarg
class example(QiskitPropertyTest):
def property(self):
return TestProperty(nbQubits=2,
qargs={0: Qarg("0"),
1: Qarg("+")})
def quantumFunction(self, qc):
qc.h(0)
def assertions(self):
self.assertEqual(0, 1)
example().run()
Inner-workings of the framework
There are 4 main parts in this project:
- Test case generator
- Test execution engine
- Statistical analysis engine
- Programming interface
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file qiskit-ptesting-1.0.0.tar.gz.
File metadata
- Download URL: qiskit-ptesting-1.0.0.tar.gz
- Upload date:
- Size: 21.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.9 tqdm/4.62.3 importlib-metadata/4.8.1 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.10.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1e09285f0bdbd22633006ab7998fa57ecf1a905cea5cda986a2b36f2e58a4e7c
|
|
| MD5 |
18fc9cfa1fc847b72b760b776af5243d
|
|
| BLAKE2b-256 |
7a0efbd5fb5fb14658966986a99563e0c0822f072dcd6c38d3746af03e23a626
|