Interface

Interfaces to external packages all operate under the same overall design strategy. They each define a get_<interface>_config() function which returns a trueq.Config object that contains gates that are compatible with the interface gate definitions. Unfortunately the default trueq.Config objects which are returned typically have degeneracy in them. For example Identity is a special case of Z(phi) when phi=0, or the s gate is when Z(phi=90). When converting to these interface representations, the compiler will raise warnings that multiple possible representations are found.

Each interface fixes this degeneracy by maintaining a “priority list” containing the names of the gates found in the external package.

In order to alter this priority list, each interface exposes: tq.interface.<interface>.get_priority_list(), tq.interface.<interface>.set_priority_list(). See any interface definition of get_priority_list() for more information.

When an interface is successfully loaded, trueq.Circuit gets additional functionality in the form of a Circuit.to_<interface>(), which will convert the True-Qᵀᴹ circuit representation into the representation of the external package. By altering the priority list for the specified package, the user can select specific gates to build into by default. Additional advanced options can be accessed by passing custom config objects which are compatable with the interface gates, see trueq.interface.<interface>.conversion.from_trueq_circ() for more information.

Cirq

trueq.interface.cirq.from_trueq_circ(tq_circ, metadata=None, config='ZXZ', device=None, join_meas=True)

Converts a True-Qᵀᴹ Circuit into an Cirq Circuit object.

import cirq
import trueq as tq

mat = cirq.ops.FSimGate(theta=5, phi=1)._unitary_()

fsim_factory = tq.config.GateFactory("fsim", matrix=mat)
x90_factory = tq.config.GateFactory("x", hamiltonian=[["X", 90]])
z_factory = tq.config.GateFactory("z", hamiltonian=[["Z", "phi"]])

config = tq.Config.from_params(
    name="example",
    n_sys=2,
    mode="ZXZXZ",
    factories=[z_factory, x90_factory, fsim_factory],
)

circ = tq.Circuit([{(0, 1): tq.Gate.cx}])

tq.interface.cirq.from_trueq_circ(circ, config=config)

Note

If nothing else is provided, this automatically decomposes single qubit operations into \(R_Z(\theta)R_X(\phi)R_Z(\gamma)\) single qubit gates.

Parameters
  • circuit (Circuit) – A True-Qᵀᴹ circuit to be converted into an Cirq Circuit

  • metadata (trueq.interface.metadata.CirqMetadata) – Metadata required to accurately reproduce the original cirq circuit. If this is not provided, measurements are added at the end of the circuit.

  • config (Config or str) – If a Config which contains gates which are directly decomposable into Cirq native gates is provided, then conversion will take place into gates specified by that config. Additionally config also accepts text strings describing decomposition methods, strings must be of paulis which are defined in trueq.config.decomposition.QubitMode, then Gates are decomposed into all allowed Cirq gates, with single qubit operations being decomposed into the specified pauli string.

  • device (None or cirq.Device) – A cirq.Device, if no device is provided, an unconstrained device with cirq.GridQubit is assumed.

  • join_meas (bool) – This determines if Meas are joined into single cirq.meas() objects, or single meas object in parallel in the given moment/cycle.

Returns

A Cirq circuit representation of the Circuit

trueq.interface.cirq.to_trueq_circ(cirq_circ)

Takes a Cirq Circuit and converts it into a True-Qᵀᴹ Circuit

Note

Measurements are always placed at the end of the circuits.

Parameters

cirq_circ – a Cirq representation of a circuit

Returns

the exact input required by from_trueq_circ(), see that function for a full description of values returned.

Return type

tuple of (Circuit, trueq.interface.metadata.CircMetadata)

trueq.interface.cirq.set_priority_list(priority)

Set the priority list and reset all caching for the Cirq interface.

If None is provided, the priority list is reset to the default.

See trueq.interface.cirq.get_priority_list() for a full description.

Parameters

priority (list) – The priority list as described in get_priority_list, if None is provided, this resets the priority list to the default.

trueq.interface.cirq.get_priority_list()

Returns the current conversion priority list.

During conversion from True-Qᵀᴹ, there are times when there is degeneracy in the choice of gate to convert into. An example of this is an X rotation of 0 degrees, this gate can be represented as a 0 degree, X, Y or Z rotation, as well as an identity gate. The priority list breaks this degeneracy, True-Qᵀᴹ gates will be preferentially converted into Cirq gates which are higher on the list first.

trueq.interface.cirq.set_priority_list() can be used to set a new priority list. This priority list is also used to build the configuration object which is returned by trueq.interface.cirq.get_cirq_config().

Return type

list

trueq.interface.cirq.get_cirq_config

Get a trueq.Config which contains all compatible Cirq gates listed in the priority list for the Cirq interface, see trueq.interface.cirq.get_priority_list().

Parameters

mode – The single qubit decomposition mode as defined in tq.config.QubitMode. This defaults to ZXZXZ decomposition

Return type

trueq.Config

Qiskit

trueq.interface.qiskit.from_trueq_circ(circuit, metadata=None, config=None)

Converts a True-Qᵀᴹ circuit into an Qiskit Circuit.

Note

If nothing else is provided, this adds measurements on all qubits at the end of the circuit.

Single qubit gates are reduced to the simplest they can up to numerical rounding, IE: some U3 gates become U2 or U1.

Blocking operations are added at the end of every Cycle

Parameters
  • circuit (Circuit) – A True-Qᵀᴹ circuit to be converted into an Qiskit QuantumCircuit

  • metadata (QiskitMetadata) – Metadata required to accurately reproduce the original qiskit circuit. If this is not provided, only 1 quantum register is created, and on classical register, then measurements are added at the end of the circuit mapping each quantum bit to each classical bit.

  • config (Config) – A given config object which contains gates which can be performed by qiskit, but also has hardware restrictions. For example, a Config object can represent a CNOT gate that is restricted to specific sets of qubits, and a CNOT gate is a known native gate in Qiskit. Providing this config means that not only will the circuit be converted into Qiskit representation, but also that it will satisfy hardware restrictions. If no config is provided, all possible qiskit gates are used in the compilation.

Returns

A Qiskit circuit representation of the Circuit

Return type

qiskit.QuantumCircuit

trueq.interface.qiskit.to_trueq_circ(qk_circ)

Take a qiskit Circuit and convert it into a True-Qᵀᴹ Circuit.

Note

Barriers are not preserved, and measurements are always placed at the end of the circuits.

Parameters

dag (qiskit.QuantumCircuit) – A qiskit circuit representation of a circuit.

Returns

the exact input required by from_trueq_circ(), see that function for a full description of values returned.

Return type

tuple of (Circuit, trueq.interface.metadata.QiskitMetadata)

trueq.interface.qiskit.get_qiskit_config

Get a trueq.Config which contains all compatible Qiskit gates listed in the priority list for the Qiskit interface, see trueq.interface.qiskit.get_priority_list().

Parameters

mode – The single qubit decomposition mode as defined in tq.config.QubitMode. This defaults to ZXZXZ decomposition.

Return type

trueq.Config

trueq.interface.qiskit.set_priority_list(priority)

Set the priority list and reset all caching for the Qiskit interface.

If None is provided, the priority list is reset to the default.

See trueq.interface.qiskit.get_priority_list() for a full description.

Parameters

priority (list) – The priority list as described in get_priority_list, if None is provided, this resets the priority list to the default.

trueq.interface.qiskit.get_priority_list()

Returns the current conversion priority list.

During conversion from True-Qᵀᴹ, there are times when there is degeneracy in the choice of gate to convert into. An example of this is an X rotation of 0 degrees, this gate can be represented as a 0 degree, X, Y or Z rotation, as well as an identity gate. The priority list breaks this degeneracy, True-Qᵀᴹ gates will be preferentially converted into Qiskit gates which are higher on the list first.

trueq.interface.qiskit.set_priority_list() can be used to set a new priority list. This priority list is also used to build the configuration object which is returned by trueq.interface.qiskit.get_qiskit_config().

Return type

list

trueq.interface.qiskit.randomly_compile_qiskit(circuit, twirling_group=None, compress=True)

Randomly compiles a given Qiskit QuantumCircuit or DAGCircuit object.

Accepts the same options as trueq.randomly_compile()

Parameters
  • circuit (QuantumCircuit or DAGCircuit) – A Qiskit circuit object

  • twirling_group (dict or None) – A twirling group, see randomized compilation documentation

  • compress (bool) – Whether or not mutable gates should be compressed as much as possible.

Returns

A qiskit circuit

Return type

qiskit.QuantumCircuit

class trueq.interface.qiskit.RCPass(twirling_group=None, compress=True)

This is a Pass object as used in Qiskit’s transpiler object. This enables use of True-Qᵀᴹ’s randomized compilation tools in the framework of Qiskit.

Randomly compile a given DAG, optionally compress single qubit gates as much as possible after insertion of twirl operations.

Beginner users are recommended to use the defaults.

Parameters
  • twirling_group (dict | None) – A twirling group, see randomized compilation documentation

  • compress (bool) – Whether or not mutable gates should be compressed as much as possible.

run(dag)

Randomly Compile a DAGCircuit

Return type

DAGCircuit

trueq.interface.qiskit.config_from_backend(backend)

Takes an IBM Backend and converts it into a trueq.Config object.

This works with backends which contain the following gate names, ['u1', 'u2', 'u3', 'cx'].

In the following example, we construct a config object from the “ibmqx2” chip.

import qiskit as qk
import trueq as tq

qk.IBMQ.load_account()
provider = qk.IBMQ.get_provider()
backend = provider.get_backend("ibmqx2")
config = tq.interface.qiskit.config_from_backend(backend)

The config built will contain the chip topology constraints as well as the gates themselves. See trueq.Config for more information.

Parameters

backend (qiskit.provider.BaseBackend) – A backend from qiskit.

Returns

A config which contains gates and topology of a given backend.

Return type

trueq.Config

class trueq.interface.qiskit.Executor(circuits, backend, filename=None, n_shots=128, max_submissions=5, overwrite=False)

Asynchronous True-Qᵀᴹ circuit submission to a Qiskit backend. This enables submission of large numbers of circuits to a Qiskit backend device.

Since current hardware devices have a limit to the number of circuits that can be run at any one time, batching of circuits must be performed. An example of this is the ibmqx2 chip provided by IBM, it has a stated limit of 75 circuits which may be submitted to it at any one time. This means that if a user wishes to submit more than 75 circuits, the total collection of circuits needs to be broken up into groups (or batches) of no more than 75 circuits. The trueq.CircuitCollection has native support for the batching of circuits like this, and more details can be found under trueq.CircuitCollection.batch().

The Executor converts batched circuits into Qiskit formatted objects, and submits them to the provided backend as jobs on the physical devices. The executor then keeps track of the status of each job asynchronously, updating the status periodically as to where the jobs are in the device’s queue.

Since most devices have a limit as to the number of batches that can be submitted by one user at any given time, the executor will only submit up to a max_submissions number of batches at any one time. Once a batch has run on the device, and has been removed from the job queue, the executor will place another batch into the queue until there are a total of max_submissions submitted jobs at any one time.

Here is a worked example, where a simple circuit is submitted to the IBMQ simulator backend:

import trueq as tq
import qiskit as qk

# loading IBMQ account and selecting a backend
qk.IBMQ.load_account()
provider = qk.IBMQ.get_provider()
backend = provider.get_backend('ibmq_qasm_simulator')

# Generating a simple circuit of only the H gate
circs = tq.Circuit([{0: tq.Gate.h},
                    {0: tq.Meas()}])

# The handling of the submission of the circuits
ex = tq.interface.qiskit.Executor(circs, backend)

# This is a blocking operation, and will block until all data has been acquired
ex.results().results
# [Results({'1': 530, '0': 494})]

A more complicated example, where advanced batching options are used, as well as automatic saving of results:

import trueq as tq
import qiskit as qk

qk.IBMQ.load_account()
provider = qk.IBMQ.get_provider()
backend = provider.get_backend('ibmq_qasm_simulator')

circs = tq.make_srb((0, 1), [4, 64, 128])

# Batch the circuits into groups of 75, including readout calibration circuits
# in each batch
ro_circuits = tq.make_readout_calibration([0, 1])
batches = circs.batch(75, extra_circuits=ro_circuits)

ex = tq.interface.qiskit.Executor(batches, backend, filename='example_srb.tq')

ex.results().results
Parameters
  • circuits (trueq.CircuitCollection | trueq.Circuit | generator) –

    The circuits which are to be submitted to the Qiskit backend. Depending on what is submitted here, there are several possible outcomes:

    • trueq.Circuit

      It will be converted to a trueq.CircuitCollection. Results will be placed back inside of the original circuit object itself, and can be viewed as data is retrieved from the backout without having to wait.

    • trueq.CircuitCollection

      It will be batched using the maximum allowed batch size for the given backend. For very long circuits this may result in errors due to limited memory of the classical hardware which control the backend. If errors occur during the submission of a trueq.CircuitCollection, it is recommended to resubmit using the third submission type. Results are placed back inside of the original circuits as data is retrieved from the server.

    • trueq.CircuitCollection.batch

      The circuits will be batched exactly as given by the batch generator. This can be used to submit automatic readout correction circuits, see above example or trueq.CircuitCollection.batch() for more details about possible options. Results are placed inside original circuits as data comes in, note that some batching options may result in additional circuits being added to the collection.

  • backend (qiskit.provider.BaseBackend) – The Qiskit backend where the circuits will be submitted.

  • filename (str) – Optional filename where results will be saved. If this is provided the Executor will also be able to partially recover from a crash of the python session, loss of internet, or other interruption in data acquisition.

  • n_shots (int) – The number of shots of the circuits to be aquired.

  • max_submissions (int) – The maximum number of batches allowed in a backend queue at any one time. A typical IBMQ user has approximately 5 jobs allowed at once. This number is set by the backend provider and should be set here accordingly.

  • overwrite (bool) – Whether to overwrite the file on disk if it exists before these circuits are executed. Note that regardless of the value of this flag, after this first check, the file on disk will continually be updated as new results come in.

property n_shots

Number of shots to be aquired by the backend.

Return type

int

property backend

Qiskit backend where the circuits will be submitted.

Return type

qiskit.provider.BaseBackend

property filename

Filename where circuits with results will be saved.

Return type

str

property circuits

Batched trueq.CircuitCollection, if a single circuit was provided, it will have been converted into a trueq.CircuitCollection. See trueq.interface.qiskit.Executor documentation for more details.

Return type

list

results()

Returns the trueq.CircuitCollection complete with results.

Note

This is a blocking operation, and once called you will have to wait until all circuits have completed acquisition on the backend.

This is not required to be called in order to get results, as results are automatically placed into the provided circuits when they are retrieved from the backend. This function is simply a means to force code to wait until the backend returns all of the results.

Return type

trueq.CircuitCollection

property status

Returns a text representation for the current status of all jobs.

This is a string equivalent of the html output provided in jupyter.

Return type

str

save(overwrite=False)

Saves the current trueq.CircuitCollection regardless of status of acquisition.

This is called automatically whenever a new batch is either submitted or retrieved from the backend.

Parameters

overwrite (bool) – Whether to force an overwrite of the existing file.

cancel()

Cancels all currently submitted jobs if possible.

It is recommended that this be run any time a submission mistake is made, as circuits that have been submitted to the backend will stay in queue otherwise.

pyQuil

trueq.interface.pyquil.from_trueq_circ(circ, metadata=None, config='ZXZ')

Converts from a Circuit to a pyquil.Program.

This accepts a metadata object which contains information not present in a trueq circuit object.

Note

Measurements are always assumed to be at the end of a circuit.

If metadata is not provided, measurements are placed at the end of the circuit on all qubits, reading out to a classical register called ‘ro’

Aribtrary single qubit gates are decomposed using the ZXZ decomposition by default.

If an SU(4) gate is provided which is not performable by Pyquil, it is decomposed using the trueq.compilation.Compiler().

Parameters
  • circ (Circuit) – The True-Qᵀᴹ circuit to be converted to pyquil.

  • metadata (PyquilMetadata) – Metadata which may not be present in the True-Qᵀᴹ representation, but is present in pyquil.

  • config (Config or str) – If a Config which contains gates which are directly decomposable into Pyquil native gates is provided, then conversion will take place into gates specified by that config. Additionally config also accepts text strings describing decomposition methods, strings must be of paulis which are defined in trueq.config.decomposition.QubitMode, then Gates are decomposed into all allowed Pyquil gates, with single qubit operations being decomposed into the specified pauli string.

trueq.interface.pyquil.to_trueq_circ(program)

Converts from a pyquil.Program to a Circuit.

This returns a tuple, the first item in the tuple is the Circuit, the second is PyquilMetadata which contains information present in the pyquil program which is not representable by trueq circuits.

Parameters

program (pyquil.Program) – The pyquil program to be converted into a trueq circuit.

Return type

tuple of (Circuit, PyquilMetadata)

trueq.interface.pyquil.get_priority_list()

Returns the current conversion priority list.

During conversion from True-Qᵀᴹ, there are times when there is degeneracy in the choice of gate to convert into. An example of this is an X rotation of 0 degrees, this gate can be represented as a 0 degree, X, Y or Z rotation, as well as an identity gate. The priority list breaks this degeneracy, True-Qᵀᴹ gates will be preferentially converted into PyQuil gates which are higher on the list first.

trueq.interface.pyquil.set_priority_list() can be used to set a new priority list. This priority list is also used to build the configuration object which is returned by trueq.interface.pyquil.get_pyquil_config().

Return type

list

trueq.interface.pyquil.set_priority_list(priority)

Set the priority list and reset all caching for the PyQuil interface.

If None is provided, the priority list is reset to the default.

See trueq.interface.pyquil.get_priority_list() for a full description.

Parameters

priority (list) – The priority list as described in get_priority_list, if None is provided, this resets the priority list to the default.

trueq.interface.pyquil.get_pyquil_config

Get a trueq.Config which contains all compatible PyQuil gates listed in the priority list for the PyQuil interface, see trueq.interface.pyquil.get_priority_list().

Parameters

mode – The single qubit decomposition mode as defined in tq.config.QubitMode. This defaults to ZXZXZ decomposition.

Return type

trueq.Config