Encodings¶
In the ParityOS framework logical qubits are mapped to physical qubits via parity constraints, meaning there is no direct one-to-one correspondence between the logical and physical (device) qubits. Quantum information from a logical qubit is distributed over multiple physical qubits, effectively creating a virtual connectivity graph that is independent of the device’s native coupling map.
This allows e.g. a layout compiler to optimize the placement of operations by satisfying parity conditions locally, thereby reducing the need for costly routing operations and making the algorithm more robust against the specific topological constraints of the quantum hardware.
In terms of error correction codes this corresponds to a low density parity check code, but restricted to the Pauli Z Basis. This module provides classes for representing this mapping and methods for encoding objects into parity space or decoding them back to the logical space.
Parity mappings¶
The ParityMapping class describes the mapping between logical and physical qubits in a ParityOS layout.
Key Attributes¶
encoding_map: specifies the product of logical operators encoded by each physical qubit.decoding_map: specifies the product of physical operators used to decode each logical qubit.constraints: a specific set of constraints to implement the specified encoding and decoding maps on the device.partial_encoding_terms: an optional attribute that contains higher-order mapping terms for partial parity mappings.
When a ParityMapping is obtained from the Layout Service, all these attributes will be set automatically.
It also offers the following methods to transform objects from logical space to parity space:
encode_polynomial: Transform anOperatorPolynomialfrom logical to parity space.encode_problem: Transform aProblemRepresentationfrom logical to parity space.
Decoding parities¶
The ParityOS framework gets its power by representing parities of spins of logical qubits as single-qubit operators on physical qubits. The ParityStateDecoder class from the encodings.parity_decoder module connects data measured on the physical qubits with the state of the logical qubits on which a quantum algorithm was formulated. It implements the StateDecoder interface and uses the mappings defined in encodings.parity_mapping to keep track of the relationship between logical and physical qubits.
Initialize the decoder¶
The decoder needs to know about the relation between physical and logical qubit. Therefore, ParityStateDecoder has to be instantiated with a ParityMapping instance as argument. Typically, such a parity mapping is obtained as the result of a Parity layout compilation.
Decode a measured state¶
When a ParityOS quantum circuit is ran and measured (or simulated on a classical emulator), one obtains a state that describes the physical qubits. To make the connection with the logical states, we have to apply the ParityStateDecoder.decode method. This method will make the conversion based on the parity mapping that was used to instantiate the decoder. Mappings based on a two-dimensional parity layout might include a set of constraints in order to reduce to physical Hilbert space to the dimension of the logical Hilbert space. This allows for two scenarios:
Measure only a minimal subset of qubits, and infer the remaining values from the constraints. Such subsets can be obtained using the
ParityStateDecoder.select_reduced_readout_qubitsmethod.Measure all qubits. If all constraints are satisfied by the measured physical qubit values, then the decoding is straightforward. In practice however, some of the constraints might not be satisfied (i.e. the state is outside the code space). In such cases, the
ParityStateDecoder.closest_valid_physical_statescan figure out the closest valid physical states, that can then be decoded directly.
In both scenarios, the decode method computes the set of most probable logical states.
Example¶
from parityos.bits import Qubit
from parityos.encodings.parity_decoder import ParityStateDecoder
from parityos.encodings.parity_mapping import OperatorToProduct, ParityMapping
from parityos.operators.elementary_operator import Z
from parityos.operators.operator_product import OperatorProduct
from parityos.optimization.constraint import ProductConstraint
from parityos.states.pauli_state import PauliBasisState
from parityos.utils.misc_utils import Parity
# Declare the logical qubits.
qa, qb, qc = [Qubit(letter) for letter in "abc"]
# Declare the physical qubits.
q00, q01, q10 = [Qubit(pair) for pair in [(0, 0), (0, 1), (1, 0)]]
# Create ParityMapping instance. (Normally this is obtained as
# the result of a Parity layout compilation.)
encoding_map = {
OperatorToProduct(Z(q00), Z(qa) * Z(qb)),
OperatorToProduct(Z(q01), Z(qa) * Z(qc)),
OperatorToProduct(Z(q10), Z(qb) * Z(qc)),
}
decoding_map = {
OperatorToProduct(Z(qa), OperatorProduct(Z(q01))),
OperatorToProduct(Z(qb), OperatorProduct(Z(q10))),
}
constraints = {ProductConstraint(Z(q00) * Z(q01) * Z(q10), Parity.even)}
parity_mapping = ParityMapping(encoding_map, decoding_map, constraints)
# Initialize the decoder with the ParityMapping instance.
decoder = ParityStateDecoder(parity_mapping)
# Get a physical state (normally this is the result of a measurement).
# The measurement does not necessarily have to include all physical qubits. The decoder
# can infer the missing values form the contraints included in the parity mapping.
physical_measurement = PauliBasisState("01", ordered_qubits=(q00, q01))
# Decode the measurement to find the most likely logical states
logical_states = decoder.decode(physical_measurement)
assert logical_states == {PauliBasisState("11", (qa, qb))}