Skip to content

Commit

Permalink
completed simulation of simple two-qutrit circuit with one hadamard
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinMTO committed Oct 23, 2023
1 parent 5703cbb commit b0e96c9
Show file tree
Hide file tree
Showing 64 changed files with 1,077 additions and 608 deletions.
31 changes: 20 additions & 11 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from mqt.circuit.circuit import QuantumCircuit
from mqt.circuit.quantum_register import QuantumRegister
from mqt.interface.qasm import QASM
from mqt.circuit.components.registers.quantum_register import QuantumRegister
from mqt.simulation.provider.mqtvider import MQTProvider

qasm = """
DITQASM 2.0;
Expand All @@ -16,14 +16,23 @@
measure q[1] -> meas[1];
measure q[2] -> meas[2];
"""
c = QuantumCircuit()
c.from_qasm(qasm)
print(QASM().parse_ditqasm2_str(qasm))
s = QuantumRegister("x", 2)
print(s.__qasm__)
circ = QuantumCircuit(s)
circ.append(QuantumRegister("c", 2, [3, 3]))
x = 0
# c = QuantumCircuit()
# c.from_qasm(qasm)
# print(QASM().parse_ditqasm2_str(qasm))
qreg_example = QuantumRegister("x", 2, [3, 3])
circ = QuantumCircuit(qreg_example)
# circ.from_qasm(qasm)
h3 = circ.h(0)
print(h3.to_matrix())

provider = MQTProvider()
print(provider.backends("sim"))

# See PyCharm help at https://www.jetbrains.com/help/pycharm/
backend = provider.get_backend("tnsim")
result = backend.run(circ)

state_size = 1
for s in circ.dimensions:
state_size *= s

print(result.tensor.reshape(1, state_size))
68 changes: 46 additions & 22 deletions src/mqt/circuit/circuit.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
from __future__ import annotations

from typing import ClassVar
from typing import TYPE_CHECKING, ClassVar

from mqt.circuit.quantum_register import QuantumRegister
from mqt.interface.qasm import QASM
from mqt.circuit.components.instructions.gate_set.h import H
from mqt.circuit.components.registers.quantum_register import QuantumRegister
from mqt.circuit.qasm_interface.qasm import QASM

if TYPE_CHECKING:
from mqt.circuit.components.instructions.gate_extensions.controls import ControlData


def add_gate_decorator(func):
def gate_constructor(circ, *args):
gate = func(circ, *args)
circ.number_gates += 1
circ.instructions.append(gate)
return gate

return gate_constructor


class QuantumCircuit:
Expand Down Expand Up @@ -51,6 +65,23 @@ def __init__(self, *args):
def get_qasm_set(cls):
return cls.__qasm_to_gate_set_dict

@property
def num_qudits(self):
return self._num_qudits

@property
def dimensions(self):
return self._dimensions

def reset(self):
self.number_gates = 0
self.instructions = []
self.quantum_registers = []
self._sitemap = {}
self._num_cl = 0
self._num_qudits = 0
self._dimensions = []

def append(self, qreg: QuantumRegister):
self.quantum_registers.append(qreg)
self._num_qudits += qreg.size
Expand All @@ -61,37 +92,39 @@ def append(self, qreg: QuantumRegister):
qreg.local_sitemap[i] = num_lines_stored + i
self._sitemap[(str(qreg.label), i)] = (num_lines_stored + i, qreg.dimensions[i])

@add_gate_decorator
def csum(self, qudits: list[int]):
pass

def custom_unitary(self, qudits: list[int] | int):
pass

def cx(self, qudits: list[int]):
def cx(self, qudits: list[int], controls: ControlData | None = None):
pass

def h(self, qudit: int):
pass
@add_gate_decorator
def h(self, qudit: int, controls: ControlData | None = None):
return H(self, "H" + str(self.dimensions[qudit]), qudit, self.dimensions[qudit], controls)

def ls(self, qudits: list[int]):
def ls(self, qudits: list[int], controls: ControlData | None = None):
pass

def ms(self, qudits: list[int]):
def ms(self, qudits: list[int], controls: ControlData | None = None):
pass

def pm(self, params, qudits: list[int] | int):
def pm(self, params, qudits: list[int] | int, controls: ControlData | None = None):
pass

def r(self, params, qudit: int):
def r(self, params, qudit: int, controls: ControlData | None = None):
pass

def rz(self, params, qudit: int):
def rz(self, params, qudit: int, controls: ControlData | None = None):
pass

def s(self, qudit: int):
def s(self, qudit: int, controls: ControlData | None = None):
pass

def z(self, qudit: int):
def z(self, qudit: int, controls: ControlData | None = None):
pass

def from_qasm(self, qasm_prog):
Expand Down Expand Up @@ -138,12 +171,3 @@ def to_qasm(self):
def draw(self):
# TODO
pass

def reset(self):
self.number_gates = 0
self.instructions = []
self.quantum_registers = []
self._sitemap = {}
self._num_cl = 0
self._num_qudits = 0
self._dimensions = []
File renamed without changes.
131 changes: 131 additions & 0 deletions src/mqt/circuit/components/instructions/gate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
from __future__ import annotations

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Callable

from mqt.circuit.components.instructions.gate_extensions.controls import ControlData
from mqt.circuit.components.instructions.gate_extensions.gatetypes import GateTypes
from mqt.circuit.components.instructions.instruction import Instruction
from mqt.exceptions.circuiterror import CircuitError

if TYPE_CHECKING:
import enum

import numpy as np
from numpy import ndarray

from mqt.circuit.circuit import QuantumCircuit


class Gate(Instruction, ABC):
"""Unitary gate."""

def __init__(
self,
circuit: QuantumCircuit,
name: str,
gate_type: enum,
target_qudits: list[int] | int,
dimensions: list[int] | int,
params: list | None = None,
control_set=None,
label: str | None = None,
duration=None,
unit="dt",
) -> None:
self.parent_circuit = circuit
# self.definition = None #todo unsure whether necesssary
self._name = name
self._target_qudits = target_qudits
self._dimensions = dimensions
self._params = params
self._label = label
self._duration = duration
self._unit = unit
self._controls_data = None
if control_set:
self.control(**vars(control_set))
# TODO do it with inheritance one day
self.gate_type = gate_type

# Set higher priority than Numpy array and matrix classes
__array_priority__ = 20

@property
def ref_lines(self):
if isinstance(self._target_qudits, int):
lines = self.get_control_lines
lines.append(self._target_qudits)
elif isinstance(self._target_qudits, list):
lines = self._target_qudits + self.get_control_lines
if len(lines) == 0:
msg = "Gate has no target or control lines"
raise CircuitError(msg)
return lines

@abstractmethod
def __array__(self, dtype: str = "complex") -> np.ndarray:
pass

def to_matrix(self) -> Callable[[str], ndarray]:
"""Return a np.ndarray for the gate unitary matrix.
Returns:
np.ndarray: if the Gate subclass has a matrix definition.
Raises:
CircuitError: If a Gate subclass does not implement this method an
exception will be raised when this base class method is called.
"""
if hasattr(self, "__array__"):
return self.__array__()
msg = "to_matrix not defined for this "
raise CircuitError(msg, {type(self)})

def control(self, indices: list[int] | int, ctrl_states: list[int] | int):
if len(indices) > self.parent_circuit.num_qudits or any(
idx >= self.parent_circuit.num_qudits for idx in indices
):
msg = "Indices or Number of Controls is beyond the Quantum Circuit Size"
raise IndexError(msg)
if any(idx in self._target_qudits for idx in indices):
msg = "Controls overlap with targets"
raise IndexError(msg)
if any(ctrl >= self._dimensions[i] for i, ctrl in enumerate(ctrl_states)):
msg = "Controls States beyond qudit size "
raise IndexError(msg)
if self.ref_lines < 2:
self.set_gate_type_single()
elif self.ref_lines == 2:
self.set_gate_type_two()
elif self.ref_lines > 2:
self.set_gate_type_multi()
self._controls_data = ControlData(indices, ctrl_states)

@abstractmethod
def validate_parameter(self, parameter):
pass

@abstractmethod
def __qasm__(self) -> str:
pass

@abstractmethod
def __str__(self):
# String representation for drawing?
pass

def set_gate_type_single(self):
self.gate_type = GateTypes.SINGLE

def set_gate_type_two(self):
self.gate_type = GateTypes.TWO

def set_gate_type_multi(self):
self.gate_type = GateTypes.MULTI

@property
def get_control_lines(self):
if self._controls_data:
return self._controls_data.indices
return []
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from __future__ import annotations

from dataclasses import dataclass


@dataclass
class ControlData:
indices: list[int] | int
ctrl_states: list[int] | int
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import enum


class GateTypes(enum.Enum):
"""Enumeration for job status."""

SINGLE = "Single Qudit Gate"
TWO = "Two Qudit Gate"
MULTI = "Multi Qudit Gate"


CORE_GATE_TYPES = (GateTypes.SINGLE, GateTypes.TWO, GateTypes.MULTI)
File renamed without changes.
27 changes: 27 additions & 0 deletions src/mqt/circuit/components/instructions/gate_set/csum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from mqt.circuit.components.instructions.gate import Gate

if TYPE_CHECKING:
import numpy as np

from mqt.circuit.components.instructions.gate_extensions.controls import ControlData


class CSum(Gate):
def __qasm__(self) -> str:
pass

def __array__(self, dtype: str = "complex") -> np.ndarray:
pass

def validate_parameter(self, parameter):
pass

def __init__(self, name: str, num_qudits: int, params: list, controls: ControlData | None = None):
super().__init__(name, num_qudits, params)

def __str__(self):
pass
27 changes: 27 additions & 0 deletions src/mqt/circuit/components/instructions/gate_set/customunitary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from mqt.circuit.components.instructions.gate import Gate

if TYPE_CHECKING:
import numpy as np

from mqt.circuit.components.instructions.gate_extensions.controls import ControlData


class CustomUnitary(Gate):
def __qasm__(self) -> str:
pass

def __array__(self, dtype: str = "complex") -> np.ndarray:
pass

def validate_parameter(self, parameter):
pass

def __init__(self, name: str, num_qudits: int, params: list, controls: ControlData | None = None):
super().__init__(name, num_qudits, params)

def __str__(self):
pass
27 changes: 27 additions & 0 deletions src/mqt/circuit/components/instructions/gate_set/cx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from mqt.circuit.components.instructions.gate import Gate

if TYPE_CHECKING:
import numpy as np

from mqt.circuit.components.instructions.gate_extensions.controls import ControlData


class CEx(Gate):
def __qasm__(self) -> str:
pass

def __array__(self, dtype: str = "complex") -> np.ndarray:
pass

def validate_parameter(self, parameter):
pass

def __init__(self, name: str, num_qudits: int, params: list, controls: ControlData | None = None):
super().__init__(name, num_qudits, params)

def __str__(self):
pass
Loading

0 comments on commit b0e96c9

Please sign in to comment.