Quantum Operations

QFrame vs Qubit

Allocate qubit operations must be called differently according to different backends. Since Cirq, Qiskit and Sdqs are circuit simulators, qubits allocated as circuit blocks. STIM supports all invocation methods.

alternate text

Allocate Qubit

As expected from a quantum network simulator, QDNS can perform allocate qubit operations with different backends. Allocate operation gets application unique qubit pointer from backend. In the example below, Alice node is doing allocate operations:

class Alice(QDNS.Node):
    def __init__(self):
        super().__init__("Alice")
        self.create_new_application(self.alice_default_app)

    @staticmethod
    def alice_default_app(default_app: QDNS.Application, *user_args):

        """
        allocate_qframe in below:
            Allocates 3 qubit circit in Cirq, Qiskit or Sdqs
            Allocates 3 qubit in Stim
        """
        qubits = default_app.allocate_qframe(3)
        print("Allocated 3x1 frame: ", qubits)

        """
        allocate_qframes in below:
            Allocates 3 qubit 3 circit in Cirq, Qiskit or Sdqs
            Allocates 9 qubit in Stim
        """
        qubit_frames = default_app.allocate_qframes(3, 3)
        print("Allocated 3x3 frame: ", qubit_frames)

        """
        allocate_qframe in below:
            Allocates 2 qutrit circuit in Cirq
            Allocates 2 qubit circit in Qiskit or Sdqs
            Allocates 2 qubit in Stim
        """
        qutrits = default_app.allocate_qframe(2, 3)
        print("Allocated qutrits: ", qutrits)

        """
        allocate_qubit in below:
            Allocates 1 qubit circit in Cirq, Qiskit or Sdqs
            Allocates 1 qubit in Stim
        """
        qubit = default_app.allocate_qubit()
        print("Allocated qubit: ", qubit)

        """
        allocate_qubits in below:
            Allocates 4 qubit circit in Cirq, Qiskit or Sdqs
            Allocates 4 qubit in Stim
        """
        qubits = default_app.allocate_qubits(4)
        print("Allocated qubit: ", qubits)

        print("Total allocated qubits in app: ", default_app.allocated_qubits)
Allocated 3x1 frame:  ['1020000000', '1020000001', '1020000002']
Allocated 3x3 frame:  [['1020000100', '1020000101', '1020000102'],
                       ['1020000200', '1020000201', '1020000202'],
                       ['1020000300', '1020000301', '1020000302']]
Allocated qutrits:  ['1030000000', '1030000001']
Allocated qubit:  '1020000400'
Allocated qubits:  ['1020000500', '1020000501', '1020000502', '1020000503', '1020000504']

Total allocated qubits in app:
[
    '1020000000', '1020000001', '1020000002', '1020000100', '1020000101',
    '1020000102', '1020000200', '1020000201', '1020000202', '1020000300',
    '1020000301', '1020000302', '1030000000', '1030000001', '1020000400',
    '1020000500', '1020000501', '1020000502', '1020000503', '1020000504'
]

allocate_qframe(s) function works as allocate_qubit(s) on STIM.

Deallocate Qubits

In order to use the hardware resources more effectively, the qubits whose work is finished should be released. The code below continues from previous sections:

class Alice(QDNS.Node):
    def __init__(self):
        super().__init__("Alice")
        self.create_new_application(self.alice_default_app)

    @staticmethod
    def alice_default_app(default_app: QDNS.Application, *user_args):
        ...
        ...
        default_app.deallocate_qubits(*qubits)

Measure Qubits

With this operation we can measure qubits. The code below continues from previous sections:

class Alice(QDNS.Node):
    def __init__(self):
        super().__init__("Alice")
        self.create_new_application(self.alice_default_app)

    @staticmethod
    def alice_default_app(default_app: QDNS.Application, *user_args):
        ...
        ...

        # Lets measure all qubits allocated by this application.
        # True Flag = Do non-destructive measures.
        print("Results: ", default_app.measure_qubits(default_app.allocated_qubits, True))
Results:  [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

Gates

QDNS contains various operators preapired for users:

from QDNS import gates
print("Gate Count: ", gates.predefined_gates.__len__())
print("Gates: ", [gate.gate_name for gate in gates.predefined_gates])
Gate Count:  37
Gates:  [
    'IDGate', 'RXGate', 'RYGate', 'RZ', 'PauliX', 'PauliY',
    'PauliZ', 'SGate', 'TGate', 'HGate', 'Psedo-HGate', 'CRXGate',
    'CXGate', 'CRYGate', 'CYGate', 'CRZGate', 'CYGate', 'CSGate',
    'CTGate', 'CHGate', 'IIGate', 'SWAPGate', 'iSWAPGate', 'XXGate',
    'YYGate', 'ZZGate', 'MSGate', 'MagicGate', 'CVGate', 'XYGate',
    'DCXGate', 'bSWAPGate', 'QFTGate', 'WGate', 'CCXGate', 'CSWAPGate', 'CCZGate'
]

Applying gates to qubits follows as:

class Alice(QDNS.Node):
    def __init__(self):
        super().__init__("Alice")
        self.create_new_application(self.alice_default_app)

    @staticmethod
    def alice_default_app(default_app: QDNS.Application, *user_args):
        ...
        ...

        qubits = default_app.allocate_qframe(2)
        default_app.apply_transformation(gates.HGate(), qubits[0])
        default_app.apply_transformation(gates.CXGate(), qubits[0], qubits[1])
        print("Results: ", default_app.measure_qubits(qubits))
Results:  [1. 1.]

Reset

QDNS allows users to reset qubits in every backend:

class Alice(QDNS.Node):
    def __init__(self):
        super().__init__("Alice")
        self.create_new_application(self.alice_default_app)

    @staticmethod
    def alice_default_app(default_app: QDNS.Application, *user_args):
        ...
        ...

        # Lets reset epr qubits from top.
        default_app.reset_qubits(qubits)
        print("After Reset Result: ", default_app.measure_qubits(qubits))
Results:  [0. 0.]

Generating Pairs

QDNS has built in epr and ghz pair generation process that faster than doing this manually:

class Alice(QDNS.Node):
    def __init__(self):
        super().__init__("Alice")
        self.create_new_application(self.alice_default_app)

    @staticmethod
    def alice_default_app(default_app: QDNS.Application, *user_args):
        ...
        ...

        epr_frames = default_app.generate_entangle_pairs(10)
        ghz_frames = default_app.generate_ghz_pair(3, 10)

        print("EPR's: ", epr_frames)
        print("GHZ's: ", ghz_frames)
EPR's:  [
    ['1020012900', '1020012901'], ['1020013000', '1020013001'],
    ['1020013100', '1020013101'], ['1020013200', '1020013201'],
    ['1020013300', '1020013301'], ['1020013400', '1020013401'],
    ['1020013500', '1020013501'], ['1020013600', '1020013601'],
    ['1020013700', '1020013701'], ['1020013800', '1020013801']
]
GHZ's:  [
['1020019600', '1020019601', '1020019602'], ['1020019700', '1020019701', '1020019702'],
['1020019800', '1020019801', '1020019802'], ['1020019900', '1020019901', '1020019902'],
['1020020000', '1020020001', '1020020002'], ['1020020100', '1020020101', '1020020102'],
['1020020200', '1020020201', '1020020202'], ['1020020300', '1020020301', '1020020302'],
['1020020400', '1020020401', '1020020402'], ['1020020500', '1020020501', '1020020502']
]

Full Test

The following codes contain all the tests:

import QDNS
from QDNS import gates
import logging

class Alice(QDNS.Node):
    def __init__(self):
        super().__init__("Alice")
        self.create_new_application(self.alice_default_app)

    @staticmethod
    def alice_default_app(default_app: QDNS.Application, *user_args):

        """
        allocate_qframe in below:
            Allocates 3 qubit circit in Cirq, Qiskit or Sdqs
            Allocates 3 qubit in Stim
        """
        qubits = default_app.allocate_qframe(3)
        print("Allocated 3x1 frame: ", qubits)

        """
        allocate_qframes in below:
            Allocates 3 qubit 3 circit in Cirq, Qiskit or Sdqs
            Allocates 9 qubit in Stim
        """
        qubit_frames = default_app.allocate_qframes(3, 3)
        print("Allocated 3x3 frames: ", qubit_frames)

        """
        allocate_qframe in below:
            Allocates 2 qutrit circuit in Cirq
            Allocates 2 qubit circit in Qiskit or Sdqs
            Allocates 2 qubit in Stim
        """
        qutrits = default_app.allocate_qframe(2, 3)
        print("Allocated qutrits: ", qutrits)

        """
        allocate_qubit in below:
            Allocates 1 qubit circit in Cirq, Qiskit or Sdqs
            Allocates 1 qubit in Stim
        """
        qubit = default_app.allocate_qubit()
        print("Allocated qubit: ", qubit)

        """
        allocate_qubits in below:
            Allocates 4 qubit circit in Cirq, Qiskit or Sdqs
            Allocates 4 qubit in Stim
        """
        qubits = default_app.allocate_qubits(4)
        print("Allocated qubits: ", qubits)

        print("Total allocated qubits in app: ", default_app.allocated_qubits)

        # Deallocate some qubits
        default_app.deallocate_qubits(*qubits)

        # Lets measure all qubits allocated by this application
        print("Results: ", default_app.measure_qubits(default_app.allocated_qubits, True))

        # Lets create manually epr
        qubits = default_app.allocate_qframe(2)
        default_app.apply_transformation(gates.HGate(), qubits[0])
        default_app.apply_transformation(gates.CXGate(), qubits[0], qubits[1])
        print("Results: ", default_app.measure_qubits(qubits))

        # Lets reset epr qubits from top
        default_app.reset_qubits(qubits)
        print("After Reset Result: ", default_app.measure_qubits(qubits))

        # Lets generate epr and ghz auto
        epr_frames = default_app.generate_entangle_pairs(10)
        ghz_frames = default_app.generate_ghz_pair(3, 10)

        print("EPR's: ", epr_frames)
        print("GHZ's: ", ghz_frames)

def main():
    logging.basicConfig(level=logging.WARNING)

    net = QDNS.Network()
    net.add_device(Alice())

    frames = {
        2: {
            1: 128,
            2: 128,
            3: 64,
            4: 32
        },

        3: {
            2: 16
        }

    }
    conf = QDNS.BackendConfiguration(QDNS.CIRQ_BACKEND, 5, frames)
    sim = QDNS.Simulator()
    sim.simulate(net, conf)

if __name__ == '__main__':
    main()
WARNING:QDNS::Kernel::Backend:CIRQ backend is prepaired for simulation. Prepairation time: ~0.1609 sec
Allocated 3x1 frame:  ['1020019200', '1020019201', '1020019202']
Allocated 3x3 frames: [['1020019300', '1020019301', '1020019302'],
                       ['3020019200', '3020019201', '3020019202'],
                       ['2020019200', '2020019201', '2020019202']]

Allocated qutrits:  ['1030000000', '1030000001']
Allocated qubit:  1020000000
Allocated qubits:  ['1020022400', '1020022401', '1020022402', '1020022403']

Total allocated qubits in app:  ['1020019200', '1020019201', '1020019202', '1020019300',
                                 '1020019301', '1020019302', '3020019200', '3020019201',
                                 '3020019202', '2020019200', '2020019201', '2020019202',
                                 '1030000000', '1030000001', '1020000000', '1020022400',
                                 '1020022401', '1020022402', '1020022403']

Results:  [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

Results:  [1. 1.]

After Reset Result:  [0. 0.]

EPR's: [
         ['1020012900', '1020012901'], ['1020013000', '1020013001'],
         ['2020012800', '2020012801'], ['2020012900', '2020012901'],
         ['3020012800', '3020012801'], ['3020012900', '3020012901'],
         ['4020012800', '4020012801'], ['4020012900', '4020012901'],
         ['5020012800', '5020012801'], ['5020012900', '5020012901']
       ]
GHZ's: [
         ['1020019400', '1020019401', '1020019402'], ['1020019500', '1020019501', '1020019502'],
         ['2020019300', '2020019301', '2020019302'], ['2020019400', '2020019401', '2020019402'],
         ['5020019200', '5020019201', '5020019202'], ['5020019300', '5020019301', '5020019302'],
         ['3020019300', '3020019301', '3020019302'], ['3020019400', '3020019401', '3020019402'],
         ['4020019200', '4020019201', '4020019202'], ['4020019300', '4020019301', '4020019302']
       ]

WARNING:QDNS::Alice:Device simulation is idled after 1.0017 seconds.
WARNING:QDNS::Kernel:Simulation is ended in 1.2541 seconds. Real raw time: 0.0485