From 9a2831259c91f6abb1ab077ebd409e3732eb44a4 Mon Sep 17 00:00:00 2001 From: chunhui2333 <1772662323@qq.com> Date: Sun, 17 Jul 2022 21:36:08 +0800 Subject: [PATCH 1/5] first --- src/quingo/if_backend/backend_hub.py | 15 +++-- .../non_arch_backend/pyqdraw_quantumsim.py | 60 +++++++++++++++++++ 2 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 src/quingo/if_backend/non_arch_backend/pyqdraw_quantumsim.py diff --git a/src/quingo/if_backend/backend_hub.py b/src/quingo/if_backend/backend_hub.py index ca9a59c..be2d377 100755 --- a/src/quingo/if_backend/backend_hub.py +++ b/src/quingo/if_backend/backend_hub.py @@ -3,8 +3,8 @@ import importlib class Backend_info(): def __init__(self, module_name, module_path, with_timing, is_simulator): - self.module_name = module_name - self.module_path = module_path + self.module_name = module_name #库名字 + self.module_path = module_path #库路径 self.with_timing = with_timing self.is_simulator = is_simulator @@ -23,7 +23,8 @@ class Backend_info(): return module def get_instance(self): - return getattr(self.get_module(), self.module_name)() + #从给定文件中拿出模块对应的名字 + return getattr(self.get_module(), self.module_name)() def singleton(cls): @@ -37,7 +38,7 @@ def singleton(cls): @singleton -class Backend_hub(): +class Backend_hub(): def __init__(self): self.backends = {} @@ -49,9 +50,13 @@ class Backend_hub(): 'PyQCISim_quantumsim', 'pyqcisim_quantumsim', with_timing=False, is_simulator=True) + self.backends['pyqdraw_quantumsim'] = Backend_info( + 'PyDRAW_quantumsim', 'pyqdraw_quantumsim', with_timing=False, + is_simulator=True) + def support(self, backend_name): return (backend_name in self.backends) def get_instance(self, backend_name): backend_info = self.backends[backend_name] - return backend_info.get_instance() + return backend_info.get_instance() diff --git a/src/quingo/if_backend/non_arch_backend/pyqdraw_quantumsim.py b/src/quingo/if_backend/non_arch_backend/pyqdraw_quantumsim.py new file mode 100644 index 0000000..547f5f9 --- /dev/null +++ b/src/quingo/if_backend/non_arch_backend/pyqdraw_quantumsim.py @@ -0,0 +1,60 @@ +from pathlib import Path +from quingo.if_backend.if_backend import If_backend +import quingo.global_config as gc +from quingo.core.utils import * +from src import do_sim; + +logger = get_logger((__name__).split('.')[-1]) + + +class PyDraw_quantumsim(If_backend): + """A functional QCIS simulation backend using PyQCISim and QuantumSim.""" + + def __init__(self, **kwargs): #关键字参数 + + super().__init__("PyDraw_QuantumSim", is_simaultor=True) + self.sim = do_sim.PyDraw() + self.pyqcisim_dir = gc.qgrtsys_root_dir / "if_backend" / "pydraw" + self.verbose = kwargs.pop('verbose', False) #没有就返回False + self.loglevel = kwargs.pop('loglevel', logging.INFO) #没有就返回logging.INFO + logger.setLevel(self.loglevel) + self.res = None + + def available(self): + return True + + def get_qisa(self): + return "qcis" + + def set_log_level(self, log_level): + self.log_level = log_level + logger.setLevel(self.log_level) + + def set_verbose(self, verbose): + pass + + def upload_program(self, prog_fn, is_binary=False): + assert not is_binary + + if not isinstance(prog_fn, Path): + prog_fn = Path(prog_fn) + + f = prog_fn.open('r').read() #前面的都是读文件的操作,读入f + try: + #此处为compile过程 + self.sim.compiler(f) + return True + except Exception as e: + quingo_err("Error in the QCIS program compiling process of PyQCISim: {}".format(e)) + return False + + def execute(self): + try: + self.res=self.sim.excute() + except Exception as e: + quingo_err("Error in PyQCISim Simulation: {}".format(e)) + return False + + def read_result(self): #这里承接manager.py + """This function tries to read the computation result of the quantum kernel.""" + return self.res -- Gitee From c5b1d94f5cfa8362193d1d1afb28ca412195f2a2 Mon Sep 17 00:00:00 2001 From: chunhui2333 <1772662323@qq.com> Date: Sun, 17 Jul 2022 21:41:06 +0800 Subject: [PATCH 2/5] all --- real_final/setup.py | 10 + real_final/src/QCIS/__init__.py | 0 real_final/src/QCIS/instr.py | 151 +++++++++++ real_final/src/QCIS/lexer.py | 125 +++++++++ real_final/src/QCIS/parser.py | 199 +++++++++++++++ real_final/src/__init__.py | 0 real_final/src/do_sim.py | 48 ++++ real_final/src/kernel/__init__.py | 0 real_final/src/kernel/circuit.py | 83 ++++++ real_final/src/kernel/gate.py | 87 +++++++ real_final/src/kernel/gates_lib.py | 293 ++++++++++++++++++++++ real_final/src/kernel/ket/__init__.py | 0 real_final/src/kernel/ket/entanglement.py | 0 real_final/src/kernel/ket/qubit.py | 65 +++++ real_final/src/kernel/ket/state.py | 120 +++++++++ real_final/src/kernel/ket/store.py | 50 ++++ real_final/src/kernel/qubit.py | 88 +++++++ real_final/src/kernel/utils.py | 78 ++++++ real_final/src/output/__init__.py | 0 real_final/src/output/store.py | 59 +++++ real_final/src/output/symbol_map.py | 25 ++ 21 files changed, 1481 insertions(+) create mode 100644 real_final/setup.py create mode 100644 real_final/src/QCIS/__init__.py create mode 100644 real_final/src/QCIS/instr.py create mode 100644 real_final/src/QCIS/lexer.py create mode 100644 real_final/src/QCIS/parser.py create mode 100644 real_final/src/__init__.py create mode 100644 real_final/src/do_sim.py create mode 100644 real_final/src/kernel/__init__.py create mode 100644 real_final/src/kernel/circuit.py create mode 100644 real_final/src/kernel/gate.py create mode 100644 real_final/src/kernel/gates_lib.py create mode 100644 real_final/src/kernel/ket/__init__.py create mode 100644 real_final/src/kernel/ket/entanglement.py create mode 100644 real_final/src/kernel/ket/qubit.py create mode 100644 real_final/src/kernel/ket/state.py create mode 100644 real_final/src/kernel/ket/store.py create mode 100644 real_final/src/kernel/qubit.py create mode 100644 real_final/src/kernel/utils.py create mode 100644 real_final/src/output/__init__.py create mode 100644 real_final/src/output/store.py create mode 100644 real_final/src/output/symbol_map.py diff --git a/real_final/setup.py b/real_final/setup.py new file mode 100644 index 0000000..82d403e --- /dev/null +++ b/real_final/setup.py @@ -0,0 +1,10 @@ +import setuptools +setuptools.setup(name='symqc', + version='0.0.1', + description='Quantum computing simulator based on symbolic operation', + url='https://gitee.com/huang-zixiao/qsim', + author='13974811840', + author_email='1245949348@qq.com', + license='MIT', + packages=setuptools.find_packages(), + zip_safe=False) \ No newline at end of file diff --git a/real_final/src/QCIS/__init__.py b/real_final/src/QCIS/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/real_final/src/QCIS/instr.py b/real_final/src/QCIS/instr.py new file mode 100644 index 0000000..d166276 --- /dev/null +++ b/real_final/src/QCIS/instr.py @@ -0,0 +1,151 @@ +from enum import Enum, auto + + +class QCISOpCode(Enum): + # The first single-qubit operation + RZ = auto() + XYARB = auto() + XY = auto() + XY2P = auto() + XY2M = auto() + X = auto() + X2P = auto() + X2M = auto() + Y = auto() + Y2P = auto() + Y2M = auto() + Z = auto() + Z2P = auto() + Z2M = auto() + Z4P = auto() + Z4M = auto() + S = auto() + SD = auto() + T = auto() + TD = auto() + H = auto() + RX = auto() + RY = auto() + RXY = auto() + # The last single-qubit operation + + # The first two-qubit operation + CZ = auto() + CNOT = auto() + SWP = auto() + SSWP = auto() + ISWP = auto() + SISWP = auto() + CP = auto() + FSIM = auto() + # The last two-qubit operation + + # The first measurement operation + MEASURE = auto() + M = auto() + # The last measurement operation + + B = auto() + + def is_single_qubit_op(self): + return self.RZ.value <= self.value <= self.RXY.value + + def is_two_qubit_op(self): + return self.CZ.value <= self.value <= self.FSIM.value + + def is_measure_op(self): + return self.MEASURE.value <= self.value <= self.M.value + + +class QCIS_instr(object): + def __init__(self, op_code, **kwargs): + """ + Data structure for representing QCIS instructions. + + Attributes: + op_code: The operation code of the QCIS instruction. + azimuth: The angle between the axis to rotate along and z-axis. + altitude: The angle of rotation along a given axis. + + Single-qubit operation only attributes: + qubit: The name string of target qubit. + + Two-qubit operation only attributes: + control_qubit: The name string of control qubit. + target_qubit: The name string of target qubit. + + Measurement operation only attributes: + qubits_list: The names of all qubits to be measured. + """ + self.op_code = op_code + + if op_code.is_two_qubit_op(): + if self.op_code == QCISOpCode.CP or self.op_code == QCISOpCode.FSIM: + self.azimuth = kwargs["azimuth"] + self.control_qubit = kwargs["control_qubit"] + self.target_qubit = kwargs["target_qubit"] + return + + if op_code.is_single_qubit_op(): + self.qubit = kwargs["qubit"] + + if self.op_code == QCISOpCode.XYARB or self.op_code == QCISOpCode.RXY: + self.azimuth = kwargs["azimuth"] + self.altitude = kwargs["altitude"] + return + + if ( + self.op_code == QCISOpCode.XY + or self.op_code == QCISOpCode.XY2P + or self.op_code == QCISOpCode.XY2M + or self.op_code == QCISOpCode.RZ + ): + self.azimuth = kwargs["azimuth"] + return + + if self.op_code == QCISOpCode.RX or self.op_code == QCISOpCode.RY: + self.altitude = kwargs["altitude"] + return + + return + + if op_code.is_measure_op(): + # Should be a list even measuring only one qubit + self.qubits_list = kwargs["qubits_list"] + self.qubits_list.sort() + return + + if op_code == QCISOpCode.B: + self.qubits_list = kwargs["qubits_list"] + self.qubits_list.sort() + return + + raise ValueError("Found unrecognized opcode: ", op_code) + + def __str__(self): + if self.op_code.is_two_qubit_op(): + return "Two-qubit op: {}, control: {}, target: {}".format( + self.op_code, self.control_qubit, self.target_qubit + ) + + if self.op_code.is_single_qubit_op(): + params_str = "" + if self.op_code == QCISOpCode.XYARB: + params_str = ", azimuth: {}, altitude: {}".format( + self.azimuth, self.altitude + ) + return "Single-qubit op: {}, qubit: {}{}".format( + self.op_code, self.qubit, params_str + ) + + if self.op_code.is_measure_op(): + qubits_list_str = " ".join([qubit for qubit in self.qubits_list]) + return "Measure op: {}, qubits list: {}".format( + self.op_code, qubits_list_str + ) + + raise ValueError("Unrecognized instruction.") + + def __eq__(self, other): + # Two QCISInst instances with same values of attributes will be identical + return self.__dict__ == other.__dict__ diff --git a/real_final/src/QCIS/lexer.py b/real_final/src/QCIS/lexer.py new file mode 100644 index 0000000..a0b0aad --- /dev/null +++ b/real_final/src/QCIS/lexer.py @@ -0,0 +1,125 @@ +import ply.lex as lex + + +class QCISLexer(object): + """QCIS lexer""" + + def __init__(self): + """Create a ply lexer.""" + self.data = None + self.lexer = lex.lex(module=self, debug=False, errorlog=lex.NullLogger()) + self.lineno = 1 + + def input(self, data): + """Set the input text data.""" + self.data = data + self.lexer.input(data) + + def token(self): + """Return the next token.""" + ret = self.lexer.token() + return ret + + reserved = { + # ---Basic Operations--- + "CZ": "CZ", + "MEASURE": "MEASURE", # Deprecated measurement, use `M` + "M": "M", # Recommended measurement + "RZ": "RZ", + "XYARB": "XYARB", # Deprecated arbitrary xy-plane axis rotation, use `RXY` + "XY": "XY", + "XY2P": "XY2P", + "XY2M": "XY2M", + "X": "X", + "X2P": "X2P", + "X2M": "X2M", + "Y": "Y", + "Y2P": "Y2P", + "Y2M": "Y2M", + "Z": "Z", + "Z2P": "Z2P", # Deprecated z-axis rotation, use `S` + "Z2M": "Z2M", # Deprecated z-axis rotation, use `SD` + "Z4P": "Z4P", # Deprecated z-axis rotation, use `T` + "Z4M": "Z4M", # Deprecated z-axis rotation , use `TD` + "S": "S", + "SD": "SD", + "T": "T", + "TD": "TD", + "B": "B", # Time barrier for two qubits (useless in simulator) + # ---Extended Operations--- + "H": "H", + "RX": "RX", + "RY": "RY", + "RXY": "RXY", + "CNOT": "CNOT", + "SWP": "SWP", + "SSWP": "SSWP", + "ISWP": "ISWP", + "SISWP": "SISWP", + "CP": "CP", + "FSIM": "FSIM", + # ---Advanced Operations--- + # ! Note: Not supported now! + # "SET": "SET", + # "CMT": "CMT", + # "I": "I", + # "X12": "X12", + # "X23": "X23", + # "AXY": "AXY", + # "DTN": "DTN", + # "PLS": "PLS", + # "PLSXY": "PLSXY", + # "SWD": "SWD", + # "SWA": "SWA", + # "MOV": "MOV", + } + + tokens = ["FLOAT", "QREG", "NEWLINE"] + list(reserved.values()) + + def t_FLOAT(self, t): + r"""[-+]?[0-9]+(\.([0-9]+)?([eE][-+]?[0-9]+)?|[eE][-+]?[0-9]+)?""" + # r"[-]?\d+(\.\d+)?" + t.value = float(t.value) + + return t + + def t_QREG(self, t): + r"""[a-zA-Z_][\.a-zA-Z_0-9]*""" + # If it is an identifier but not a reserved word, then it must be QREG + t.type = self.reserved.get(t.value, "QREG") + return t + + def t_NEWLINE(self, t): + r"""\n""" + self.lineno += len(t.value) + t.lexer.lineno = self.lineno + return t + + t_ignore = " \t" + # Note that `.` can not match \n + t_ignore_COMMENT = r"\#.*" + + def find_column(self, t): + """Compute the column of the token t.""" + if t is None: + return 0 + last_line_end = self.data.rfind("\n", 0, t.lexpos) + column = t.lexpos - last_line_end + return column + + def t_error(self, t): + # When a token has no matching rule, `t.value` will contain the rest of input. + # Thus we usually only report the string before the first space, \n or \t. + raise ValueError( + "Give string ({}) at (line {}, col {}) cannot match any QCIS token rule".format( + t.value.split(" ")[0].split("\n")[0].split("\t")[0], + t.lexer.lineno, + self.find_column(t), + ) + ) + + def get_all_token(self): + return [tok for tok in self.lexer] + + def get_all_token_info(self): + return [(tok.type, tok.value, tok.lineno, tok.lexpos) for tok in self.lexer] diff --git a/real_final/src/QCIS/parser.py b/real_final/src/QCIS/parser.py new file mode 100644 index 0000000..2d1ced1 --- /dev/null +++ b/real_final/src/QCIS/parser.py @@ -0,0 +1,199 @@ +import tempfile + +import ply.yacc as yacc + +from .instr import QCISOpCode, QCIS_instr +from .lexer import QCISLexer + +OP_CODE_CONVERTER = { + "MEASURE": QCISOpCode.MEASURE, + "M": QCISOpCode.M, + "B": QCISOpCode.B, + "XY": QCISOpCode.XY, + "XY2P": QCISOpCode.XY2P, + "XY2M": QCISOpCode.XY2M, + "X": QCISOpCode.X, + "X2P": QCISOpCode.X2P, + "X2M": QCISOpCode.X2M, + "Y": QCISOpCode.Y, + "Y2P": QCISOpCode.Y2P, + "Y2M": QCISOpCode.Y2M, + "Z": QCISOpCode.Z, + "Z2P": QCISOpCode.Z2P, + "Z2M": QCISOpCode.Z2M, + "Z4P": QCISOpCode.Z4P, + "Z4M": QCISOpCode.Z4M, + "S": QCISOpCode.S, + "SD": QCISOpCode.SD, + "T": QCISOpCode.T, + "TD": QCISOpCode.TD, + "H": QCISOpCode.H, + "RX": QCISOpCode.RX, + "RY": QCISOpCode.RY, + "RZ": QCISOpCode.RZ, + "XYARB": QCISOpCode.XYARB, + "RXY": QCISOpCode.RXY, + "CZ": QCISOpCode.CZ, + "CNOT": QCISOpCode.CNOT, + "SWP": QCISOpCode.SWP, + "SSWP": QCISOpCode.SSWP, + "ISWP": QCISOpCode.ISWP, + "SISWP": QCISOpCode.SISWP, + "CP": QCISOpCode.CP, + "FSIM": QCISOpCode.FSIM, +} + + +class QCISParser(object): + """QCIS parser""" + start = "root" + + def __init__(self): + self.error_list = None + self.lexer = QCISLexer() + self.tokens = self.lexer.tokens # Import all defined tokens in lexer + self.parse_dir = tempfile.mkdtemp(prefix="sim-test") + self.parser = yacc.yacc(module=self, debug=False, outputdir=self.parse_dir) + self.__instructions = [] # To save all instructions extracted from program + self.__qubit_names = set() # A set for all qubit names occurred in program + + # As instructions are generated when specific rules are matched, these two method do not need to do any thing! + def p_root(self, p): + """root : program""" + pass + + def p_program(self, p): + """program : instruction NEWLINE program + | instruction + | NEWLINE program + | + """ + pass + + def p_instruction_n_qubit(self, p): + """instruction : MEASURE qlist + | M qlist + | B qlist""" + self.__qubit_names.update(p[2]) + self.__instructions.append(QCIS_instr(OP_CODE_CONVERTER[p[1]], qubits_list=p[2])) + + def p_qlist(self, p): + """qlist : QREG qlist + | QREG + """ + if len(p) == 3: # Matching rule 1 + # Extending qlist.value (a list, p[2]) with QREG.value (a number, p[1]) + p[0] = [p[1]] + p[2] + else: # Matching rule 2 + # Create the starting qubits list for all qubits to be measured + p[0] = [p[1]] + + def p_instruction_1_qubit_2_param(self, p): + """instruction : XYARB QREG FLOAT FLOAT + | RXY QREG FLOAT FLOAT""" + self.__qubit_names.add(p[2]) + self.__instructions.append( + QCIS_instr(OP_CODE_CONVERTER[p[1]], qubit=p[2], azimuth=p[3], altitude=p[4]) + ) + + def p_instruction_1_qubit_1_altitude(self, p): + """instruction : RX QREG FLOAT + | RY QREG FLOAT""" + self.__qubit_names.add(p[2]) + self.__instructions.append( + QCIS_instr(OP_CODE_CONVERTER[p[1]], qubit=p[2], altitude=p[3]) + ) + + def p_instruction_1_qubit_1_azimuth(self, p): + """instruction : XY QREG FLOAT + | XY2P QREG FLOAT + | XY2M QREG FLOAT + | RZ QREG FLOAT""" + self.__qubit_names.add(p[2]) + self.__instructions.append( + QCIS_instr(OP_CODE_CONVERTER[p[1]], qubit=p[2], azimuth=p[3]) + ) + + def p_instruction_1_qubit_0_param(self, p): + """instruction : X QREG + | X2P QREG + | X2M QREG + | Y QREG + | Y2P QREG + | Y2M QREG + | Z QREG + | Z2P QREG + | Z2M QREG + | Z4P QREG + | Z4M QREG + | S QREG + | SD QREG + | T QREG + | TD QREG + | H QREG""" + self.__qubit_names.add(p[2]) + self.__instructions.append(QCIS_instr(OP_CODE_CONVERTER[p[1]], qubit=p[2])) + + def p_instruction_2_qubit_0_param(self, p): + """instruction : CZ QREG QREG + | CNOT QREG QREG + | SWP QREG QREG + | SSWP QREG QREG + | ISWP QREG QREG + | SISWP QREG QREG""" + self.__qubit_names.update({p[2], p[3]}) + self.__instructions.append( + QCIS_instr(OP_CODE_CONVERTER[p[1]], control_qubit=p[2], target_qubit=p[3]) + ) + + def p_instruction_2_qubit_1_param(self, p): + """instruction : CP QREG QREG FLOAT + | FSIM QREG QREG FLOAT""" + self.__qubit_names.update({p[2], p[3]}) + self.__instructions.append( + QCIS_instr( + OP_CODE_CONVERTER[p[1]], + control_qubit=p[2], + target_qubit=p[3], + azimuth=p[4], + ) + ) + + def p_error(self, p): + """Error handling method skipping error-occurred line.""" + if not p: + error_msg = "Syntax error at the end of program." + self.error_list.append(error_msg) + return + + col = self.lexer.find_column(p) + lines = self.lexer.data.split("\n") + error_msg = "Syntax error: Found unmatched {0} at ({1}, {2}).\nSkip line {1}: {3}".format( + p.type, self.lexer.lineno, col, lines[p.lineno - 1] + ) + self.error_list.append(error_msg) + + # Read ahead looking for a new line + while True: + tok = self.lexer.token() # Get the next token + if not tok or tok.type == "NEWLINE": + break + self.parser.restart() + + def parse(self, data): + self.__instructions = [] # Clear instructions list + self.__qubit_names = set() # Clear qubit names set + self.error_list = [] + self.lexer = QCISLexer() # Reset initial lineno of lexer + self.parser.parse(data, lexer=self.lexer) + + success = True + if len(self.error_list) > 0: + error_msgs = "\n".join(self.error_list) + print("Found errors during parsing QCIS program: {}".format(error_msgs)) + success = False + + qubit_names_list = list(self.__qubit_names) # Turn the set to a list + qubit_names_list.sort() # Sort by alphabetic + return success, self.__instructions, qubit_names_list + diff --git a/real_final/src/__init__.py b/real_final/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/real_final/src/do_sim.py b/real_final/src/do_sim.py new file mode 100644 index 0000000..83ac8f7 --- /dev/null +++ b/real_final/src/do_sim.py @@ -0,0 +1,48 @@ +from .QCIS.parser import QCISParser, QCISOpCode +from sympy import init_printing +from .kernel.ket.qubit import Qsim_ket +from .output.symbol_map import symbol_map +#from ..quantumsim.sparsedm import SparseDM + +""" +The main programme +""" +class PyDraw(object): + def __init__(self): + self.args = None + self.job_arr = None + self.names = None + self.filename = None + self._sdm = None + + + def compiler(self,_prog): + """""" + _parser = QCISParser() + success, instructions, name = _parser.parse(data=_prog) + if not success: + print(_parser.error_list) + raise ValueError("QCIS parser failed to compile the given QCIS program.") + self.job_arr = instructions + self.names = name #工作点在这里 + #self._sdm = SparseDM(name) + return instructions, name + + def excute(self): + maps = symbol_map() + + for instr in self.job_arr: + if instr.op_code == QCISOpCode.RXY: + instr.altitude = maps.store_symbol("theta", instr.altitude) + instr.azimuth = maps.store_symbol("phi", instr.azimuth) + elif instr.op_code == QCISOpCode.XY or instr.op_code == QCISOpCode.XY2P or instr.op_code == QCISOpCode.XY2M: + instr.azimuth = maps.store_symbol("phi", instr.azimuth) + elif instr.op_code == QCISOpCode.RX or instr.op_code == QCISOpCode.RY or instr.op_code == QCISOpCode.RZ: + instr.altitude = maps.store_symbol("theta", instr.altitude) + + Q = Qsim_ket(len(self.names), self.names) + + init_printing() + for instr in self.job_arr: + gate = Q.apply_instr(instr) + return Q.state.map #这里出了一点点问题 diff --git a/real_final/src/kernel/__init__.py b/real_final/src/kernel/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/real_final/src/kernel/circuit.py b/real_final/src/kernel/circuit.py new file mode 100644 index 0000000..a487efd --- /dev/null +++ b/real_final/src/kernel/circuit.py @@ -0,0 +1,83 @@ +import sympy +from utils import gen_subset, get_mark, map_bit + +""" +The implementation of class Circuit +""" + + +class Circuit: + def __init__(self, n): + self.n = n # the number of qubits + self.gates = [] + self.matrix = sympy.eye(2 ** n) + + def add_gates(self, gates: list, init=0): + """Add gates to the circuit""" + if self.matrix == sympy.eye(2 ** self.n): + self.matrix = Circuit.combine_gates(gates, self.n) + else: + self.matrix = Circuit.combine_gates(gates, self.n) * self.matrix + self.gates.append(gates) + + @staticmethod + def make_from_gates_sequence(gates_sequence: list, n=0): + """Make a circuit from a sequence of gates""" + if n == 0: + for gates in gates_sequence: + for gate in gates: + n = max(n, max(gate[1] + gate[2])) + + res = Circuit(n) + for gates in gates_sequence: + res.add_gates(gates) + + return res + + @staticmethod + def combine_gates(gates: list, n): + """Build the utility matrix of these gates""" + vis = [0] * n + mark = 0 + res = sympy.ones(2 ** n, 2 ** n) + blnk = [] + + for g, opt_list, ctrl_list in gates: + mark = 0 + for i in opt_list: + vis[i] = 1 + for i in ctrl_list: + vis[i] = 1 + + blnk = [i for i in range(len(vis)) if vis[i] == 0] + vis = [i for i in range(len(vis)) if vis[i] != 0] + + matI = sympy.eye(2) + + for p in blnk: + + addr = gen_subset(get_mark([p], n)) + for i in range(matI.rows): + for j in range(matI.cols): + for si in addr: + mi = map_bit(i, si, [p]) + for sj in addr: + mj = map_bit(j, sj, [p]) + res[mi, mj] = res[mi, mj] * matI[i, j] + + for g, opt_list, ctrl_list in gates: + bits = opt_list + ctrl_list + + mark = get_mark(bits, n) + addr = gen_subset(mark) + mat = g.get_matrix(range(g.n), range(g.n, g.n + g.ctrl_num), g.n + g.ctrl_num) + + for i in range(mat.rows): + for j in range(mat.cols): + for si in addr: + mi = map_bit(i, si, bits) + for sj in addr: + mj = map_bit(j, sj, bits) + res[mi, mj] = res[mi, mj] * mat[i, j] + + return res diff --git a/real_final/src/kernel/gate.py b/real_final/src/kernel/gate.py new file mode 100644 index 0000000..8d32210 --- /dev/null +++ b/real_final/src/kernel/gate.py @@ -0,0 +1,87 @@ +from math import log2 +import sympy +from .utils import * + + +class Gate: + def __init__(self, mat, ctrl=0): + self.matrix = sympy.Matrix(mat) + assert (self.matrix.cols == self.matrix.rows) + self.n = log2(self.matrix.cols) + assert (self.n == int(self.n)) + self.n = int(self.n) + self.ctrl_num = ctrl + + def get_matrix(self, qubit_map=None, ctrl_map=None, n=0): + if ctrl_map is None: + ctrl_map = [] + if qubit_map is None: + qubit_map = [] + qubit_map = list(qubit_map) + ctrl_map = list(ctrl_map) + + if n == 0: + n = self.n + + if self.ctrl_num == 0: + if not qubit_map: + return self.matrix + else: + if ctrl_map == [] and qubit_map == []: + return self.matrix + + res = sympy.ones(2 ** n, 2 ** n) + + matI = sympy.eye(2) + + for p in range(n): + if p not in qubit_map: + mark = get_mark([p], n) + addr = gen_subset(mark) + for i in range(matI.rows): + for j in range(matI.cols): + for si in addr: + mi = map_bit(i, si, [p]) + for sj in addr: + mj = map_bit(j, sj, [p]) + res[mi, mj] = res[mi, mj] * matI[i, j] + + mark = get_mark(qubit_map, n) + ctrl_mark = get_mark(ctrl_map, 0) + addr = gen_subset(mark) + + for i in range(self.matrix.rows): + for j in range(self.matrix.cols): + for si in addr: + mi = map_bit(i, si, qubit_map) + for sj in addr: + mj = map_bit(j, sj, qubit_map) + if ctrl_map: + if mi & ctrl_mark and mj & ctrl_mark: + res[mi, mj] = res[mi, mj] * self.matrix[i, j] + else: + res[mi, mj] = res[mi, mj] * (i == j) + else: + res[mi, mj] = res[mi, mj] * self.matrix[i, j] + return res + + +# SingleQubitGate, TwoQubitGate, MultiQubitGate + +class ParametersGate(Gate): + def __init__(self, mat, ctrl=0, parameters=None): + Gate.__init__(self, mat, ctrl) + if parameters is None: + parameters = [] + self.parameters = parameters + + def get_matrix(self, qubit_map=None, ctrl_map=None, n=0, parameters=None): + if parameters is None: + parameters = [] + if ctrl_map is None: + ctrl_map = [] + if qubit_map is None: + qubit_map = [] + res = Gate.get_matrix(self, qubit_map, ctrl_map, n) + res = res.subs([(self.parameters[i], parameters[i]) for i in range(len(parameters))]) + return res diff --git a/real_final/src/kernel/gates_lib.py b/real_final/src/kernel/gates_lib.py new file mode 100644 index 0000000..fb90d31 --- /dev/null +++ b/real_final/src/kernel/gates_lib.py @@ -0,0 +1,293 @@ +import sympy +from ..QCIS.instr import QCISOpCode, QCIS_instr + + +sigma_x = sympy.Matrix([[0, 1], [1, 0]]) +sigma_y = sympy.Matrix([[0, -sympy.I], [sympy.I, 0]]) +sigma_z = sympy.Matrix([[1, 0], [0, -1]]) + + +def R(n_head, theta): + sigma_head = sympy.Matrix([sigma_x, sigma_y, sigma_z]) + n1 = n_head[0] + n2 = n_head[1] + n3 = n_head[2] + sigma = sigma_x * n1 + sigma_y * n2 + sigma_z * n3 + return sympy.exp(-sympy.I * theta * sigma / 2) + + +def X(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[0, 1], [1, 0]]) + + +def Y(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[0, -sympy.I], [sympy.I, 0]]) + + +def X2P(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[1, -sympy.I], [-sympy.I, 1]]) * (1 / sympy.sqrt(2)) + + +def X2M(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[1, sympy.I], [sympy.I, 1]]) * (1 / sympy.sqrt(2)) + + +def Y2P(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[1, -1], [1, 1]]) * (1 / sympy.sqrt(2)) + + +def Y2M(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[1, 1], [-1, 1]]) * (1 / sympy.sqrt(2)) + + +def XY(*argv): + if len(argv) != 1: + print("error argv input") + exit(1) + phi = argv[0] + n_head = sympy.Matrix([sympy.cos(phi), sympy.sin(phi), 0]) + return R(n_head, sympy.pi) + + +def XY2P(*argv): + if len(argv) != 1: + print("error argv input") + exit(1) + phi = argv[0] + n_head = sympy.Matrix([sympy.cos(phi), sympy.sin(phi), 0]) + return R(n_head, sympy.pi / 2) + + +def XY2M(*argv): + return XY2P(argv).transpose().conjugate() + + +def Z(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sigma_z + + +def S(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[1, 0], [0, sympy.I]]) + + +def SD(*argv): + return S(argv).transpose().conjugate() + + +def T(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[1, 0], [0, sympy.exp(sympy.I * sympy.pi / 4)]]) + + +def TD(*argv): + return T(argv).transpose().conjugate() + + +def RZ(*argv): + if len(argv) != 1: + print("error argv input") + exit(1) + phi = argv[0] + return sympy.exp(-sympy.pi * sigma_z * phi / 2) + + +def CZ(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[1, 0], [0, -1]]) + + +def M(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[0, 0], [0, 1]]) + + +def B(*argv): + exit(len(argv)) + + +def H(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[1, 1], [1, -1]]) * (1 / sympy.sqrt(2)) + + +def RX(*argv): + if len(argv) != 1: + print("error argv input") + exit(1) + phi = argv[0] + return sympy.exp(-sympy.pi * sigma_x * phi / 2) + + +def RY(*argv): + if len(argv) != 1: + print("error argv input") + exit(1) + phi = argv[0] + return sympy.exp(-sympy.pi * sigma_y * phi / 2) + + +def RXY(*argv): + if len(argv) != 2: + print("error argv input") + exit(1) + theta = argv[0] + phi = argv[1] + n_head = sympy.Matrix([sympy.cos(phi), sympy.sin(phi), 0]) + return R(n_head, theta) + + +def CNOT(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[0, 1], [1, 0]]) + + +def SWP(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[1, 0, 0, 0], + [0, 0, 1, 0], + [0, 1, 0, 0], + [0, 0, 0, 1]]) + + +def SSWP(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[1, 0, 0, 0], + [0, (1 + sympy.I) / 2, (1 - sympy.I) / 2, 0], + [0, (1 - sympy.I) / 2, (1 + sympy.I) / 2, 0], + [0, 0, 0, 1]]) + + +def ISWP(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[1, 0, 0, 0], + [0, 0, sympy.I, 0], + [0, sympy.I, 0, 0], + [0, 0, 0, 1]]) + + +def SISWP(*argv): + if len(argv) != 0: + print("error argv input") + exit(1) + return sympy.Matrix([[1, 0, 0, 0], + [0, 1 / sympy.sqrt(2), sympy.I / sympy.sqrt(2), 0], + [0, sympy.I / sympy.sqrt(2), 1 / sympy.sqrt(2), 0], + [0, 0, 0, 1]]) + + +def CP(*argv): + if len(argv) != 1: + print("error argv input") + exit(1) + phi = argv[0] + return sympy.Matrix([[1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, sympy.exp(sympy.I * phi)]]) + + +delta_plus = 0 +delta_minus = 0 +delta_minus_off = 0 + + +def FSIM(*argv): + if len(argv) != 2: + print("error argv input") + exit(1) + phi = argv[0] + theta = argv[1] + return sympy.Matrix([1, 0, 0, 0], + [0, sympy.exp(sympy.I * (delta_plus + delta_minus)) * sympy.cos(theta), + -sympy.I * sympy.exp(sympy.I * (delta_plus - delta_minus_off)) * sympy.sin(theta), 0], + [0, sympy.exp(sympy.I * (delta_plus + delta_minus_off)) * sympy.sin(theta), + sympy.exp(sympy.I * (delta_plus - delta_minus)) * sympy.cos(theta), 0], + [0, 0, 0, sympy.exp(sympy.I * (2 * delta_plus - phi))]) + + +QCIS_gate = { + QCISOpCode.X: X, + QCISOpCode.Y: Y, + QCISOpCode.X2P: X2P, + QCISOpCode.X2M: X2M, + QCISOpCode.Y2P: Y2P, + QCISOpCode.Y2M: Y2M, + QCISOpCode.XY: XY, + QCISOpCode.XY2P: XY2P, + QCISOpCode.XY2M: XY2M, + QCISOpCode.Z: Z, + QCISOpCode.S: S, + QCISOpCode.SD: SD, + QCISOpCode.T: T, + QCISOpCode.TD: TD, + QCISOpCode.RZ: RZ, + QCISOpCode.CZ: CZ, + QCISOpCode.M: M, + QCISOpCode.B: B, + QCISOpCode.H: H, + QCISOpCode.RX: RX, + QCISOpCode.RY: RY, + QCISOpCode.RXY: RXY, + QCISOpCode.CNOT: CNOT, + QCISOpCode.SWP: SWP, + QCISOpCode.SSWP: SSWP, + QCISOpCode.ISWP: ISWP, + QCISOpCode.SISWP: SISWP, + QCISOpCode.CP: CP, + QCISOpCode.FSIM: FSIM +} + + +def lib_gate(instr: QCIS_instr): + if instr.op_code == QCISOpCode.RXY: + return QCIS_gate[instr.op_code](instr.altitude, instr.azimuth) + elif instr.op_code == QCISOpCode.XY or instr.op_code == QCISOpCode.XY2P or instr.op_code == QCISOpCode.XY2M: + return QCIS_gate[instr.op_code](instr.azimuth) + elif instr.op_code == QCISOpCode.RX or instr.op_code == QCISOpCode.RY or instr.op_code == QCISOpCode.RZ: + return QCIS_gate[instr.op_code](instr.altitude) + else: + return QCIS_gate[instr.op_code]() + + + + diff --git a/real_final/src/kernel/ket/__init__.py b/real_final/src/kernel/ket/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/real_final/src/kernel/ket/entanglement.py b/real_final/src/kernel/ket/entanglement.py new file mode 100644 index 0000000..e69de29 diff --git a/real_final/src/kernel/ket/qubit.py b/real_final/src/kernel/ket/qubit.py new file mode 100644 index 0000000..7418d52 --- /dev/null +++ b/real_final/src/kernel/ket/qubit.py @@ -0,0 +1,65 @@ +from ...QCIS.instr import QCIS_instr, QCISOpCode +from ..gate import Gate +from ..gates_lib import lib_gate +from ..ket.state import State +from ..qubit import Qsim +from ..utils import find_main +from random import random +from sympy import Matrix + + +class Qsim_ket(Qsim): + def __init__(self, n, name): + super().__init__(n) + self.ket_state = State(name) + f = 1 + for ten in self.ket_state.tensor: + f *= ten.state.transpose() * ten.ket + self.state = f + + def apply_instr(self, instr: QCIS_instr): + if instr.op_code.is_single_qubit_op(): + gate = Gate(lib_gate(instr)) + tensor, qubit = self.ket_state.get_pos(instr.qubit) + self.state = self.ket_state.tensor[tensor].state + self.qubits_num = self.ket_state.tensor[tensor].size + self.ket_state.tensor[tensor].state = self.apply_gate(gate, [qubit]) + elif instr.op_code.is_two_qubit_op(): + if instr.op_code == QCISOpCode.CNOT or instr.op_code == QCISOpCode.CZ: + gate = Gate(lib_gate(instr), 1) + tensor, qubit, ctrl = self.ket_state.merge(instr.target_qubit, instr.control_qubit) + self.state = self.ket_state.tensor[tensor].state + self.qubits_num = self.ket_state.tensor[tensor].size + self.ket_state.tensor[tensor].state = self.apply_gate(gate, [ctrl, qubit]) + else: + gate = Gate(lib_gate(instr)) + tensor, qubit, fake_ctrl = self.ket_state.merge(instr.target_qubit, instr.control_qubit) + self.state = self.ket_state.tensor[tensor].state + self.qubits_num = self.ket_state.tensor[tensor].size + self.ket_state.tensor[tensor].state = self.apply_gate(gate, [qubit, fake_ctrl]) + elif instr.op_code.is_measure_op(): + gate = Gate(lib_gate(instr)) + qubit_list = [self.ket_state.get_pos(qubit) for qubit in instr.qubits_list] + for (tensor, state), qubit in zip(qubit_list, instr.qubits_list): + + self.state = self.ket_state.tensor[tensor].state + self.qubits_num = self.ket_state.tensor[tensor].size + tmp = self.state + for a, b in self.ket_state.symbols: + tmp = tmp.subs(a, 1) + tmp = tmp.subs(b, 0) + p0, p1 = find_main(tmp, state) + k = random() + + if k < p0 / (p0 + p1): + print("0") + self.ket_state.tensor[tensor].state = self.apply_gate(Gate(Matrix([[1, 0], [0, 0]])), [state]) + self.ket_state.measure(tensor, state, qubit, 0) + else: + print("1") + self.ket_state.tensor[tensor].state = self.apply_gate(Gate(Matrix([[0, 0], [0, 1]])), [state]) + self.ket_state.measure(tensor, state, qubit, 1) + + self.state = self.ket_state + + return gate diff --git a/real_final/src/kernel/ket/state.py b/real_final/src/kernel/ket/state.py new file mode 100644 index 0000000..b50b19f --- /dev/null +++ b/real_final/src/kernel/ket/state.py @@ -0,0 +1,120 @@ +from sympy import Matrix, symbols, pprint + +from ..utils import kron, make_ket + + +class Qutensor: + def __init__(self, qubit, vec): + self.size = 1 + self.state = vec + self.map = {qubit: 0} + self.ket = Matrix([symbols("\\ket{0_{%s}}" % qubit), symbols("\\ket{1_{%s}}" % qubit)]) + self.pre = sum([i * i for i in self.state]) + self.now = sum([i * i for i in self.state]) + + def insert_tensor(self, tensor): + self.state = kron(self.state, tensor.state) + for key in tensor.map.keys(): + tensor.map[key] += self.size + self.size += tensor.size + self.map.update(tensor.map) + self.update_ket() + self.pre = sum([i * i for i in self.state]) + self.now = sum([i * i for i in self.state]) + + def insert_qubit(self, qubit, vec): + self.map[qubit] = self.size + self.size += 1 + self.state = kron(self.state, vec) + + def clear_zero(self, state, qubit, height): + s = [] + for i in range(len(self.state)): + if ((i >> state) & 0x1) == height: + s.append(self.state[i]) + self.state = Matrix(s) + pre = self.now + now = sum([i * i for i in self.state]) + if self.size == 1: + self.ket = self.ket[height] + return pre, now, False + self.size -= 1 + + for key in self.map.keys(): + if self.map[key] > self.map[qubit]: + self.map[key] -= 1 + del self.map[qubit] + self.update_ket() + return pre, now, True + + def update_ket(self): + l = list(self.map.keys()) + x = make_ket(l) + self.ket = Matrix([symbols("\\ket{%s}" % s) for s in x]) + + +class State: + def __init__(self, names): + self.tensor = [Qutensor(qubit, Matrix([symbols("\\alpha_{%s}" % qubit), symbols("\\beta_{%s}" % qubit)])) + for qubit in names] + self.symbols = [(symbols("\\alpha_{%s}" % Q), symbols("\\beta_{%s}" % Q)) for Q in names] + self.size = len(names) + self.map = dict([(qubit, i) for qubit, i in zip(names, range(self.size))]) + self.empty = set() + + def merge(self, qubit1, qubit2): + tensor1, state1 = self.get_pos(qubit1) + tensor2, state2 = self.get_pos(qubit2) + + if tensor1 == tensor2: + return tensor1, state1, state2 + + if qubit1 < qubit2: + for key in self.tensor[tensor2].map.keys(): + self.map[key] = tensor1 + + self.tensor[tensor1].insert_tensor(self.tensor[tensor2]) + self.tensor[tensor2] = None + self.empty.add(tensor2) + self.size -= 1 + + return tensor1, self.tensor[tensor1].map[qubit1], self.tensor[tensor1].map[qubit2] + else: + for key in self.tensor[tensor1].map.keys(): + self.map[key] = tensor2 + self.tensor[tensor2].insert_tensor(self.tensor[tensor1]) + self.tensor[tensor1] = None + self.empty.add(tensor1) + self.size -= 1 + + return tensor2, self.tensor[tensor2].map[qubit1], self.tensor[tensor2].map[qubit2] + + def measure(self, tensor, state, qubit, height): + pre, now, flag = self.tensor[tensor].clear_zero(state, qubit, height) + if not flag: + self.tensor[tensor].pre = pre + self.tensor[tensor].now = now + return + index = self.empty.pop() + if height: + self.tensor[index] = Qutensor(qubit, Matrix([0, 1])) + else: + self.tensor[index] = Qutensor(qubit, Matrix([1, 0])) + + self.tensor[tensor].pre = now + self.tensor[tensor].now = now + + self.tensor[index].pre = pre + self.tensor[index].now = now + self.map[qubit] = index + + def split(self, qubit1, qubit2): + pass + + def judge(self, qubit1, qubit2): + pass + + def get_pos(self, qubit): + tensor = self.map[qubit] + state = self.tensor[tensor].map[qubit] + return tensor, state diff --git a/real_final/src/kernel/ket/store.py b/real_final/src/kernel/ket/store.py new file mode 100644 index 0000000..3e844f9 --- /dev/null +++ b/real_final/src/kernel/ket/store.py @@ -0,0 +1,50 @@ +from sympy import latex, sqrt, factor, simplify, pprint, cancel + +from QCIS.instr import QCIS_instr, QCISOpCode +from kernel.gate import Gate +from kernel.ket.qubit import Qsim_ket +from kernel.ket.state import State +from output.store import store +from output.symbol_map import symbol_map + + +class store_ket(store): + def __init__(self, init: Qsim_ket, mapping: symbol_map, output_list): + super().__init__(init, mapping, output_list) + self.init_state = init.state + + def save_instr(self, state: State, instr: QCIS_instr, gate: Gate): + ins_str = str(instr.op_code).removeprefix("QCISOpCode.") + if instr.op_code.is_single_qubit_op(): + ins_str += '\t' + str(instr.qubit) + elif instr.op_code.is_two_qubit_op(): + if instr.op_code == QCISOpCode.CNOT or instr.op_code == QCISOpCode.CZ: + ins_str += '\t' + str(instr.control_qubit) + '\t' + str(instr.target_qubit) + else: + ins_str += '\t' + str(instr.control_qubit) + '\t' + str(instr.target_qubit) + elif instr.op_code.is_measure_op(): + tmp = '\t' + ins_str += '\t' + tmp.join([str(qubit) for qubit in instr.qubits_list]) + + self.instr_save.append(ins_str) + + f = 1 + A = 1 + for tensor in state.tensor: + if tensor: + f *= (tensor.state.transpose() * tensor.ket) + A *= factor(tensor.pre) / factor(tensor.now) + self.state_save.append(latex((f[0] * sqrt(factor(A))))) + self.gate_save.append(latex(gate.matrix)) + + def save_final(self, state: State): + f = 1 + A = 1 + for tensor in state.tensor: + if tensor: + f *= (tensor.state.transpose() * tensor.ket) + A *= factor(tensor.pre) / factor(tensor.now) + self.final_state = latex(f[0] * sqrt(factor(A))) + + def write_init(self): + return self.init_state[0] diff --git a/real_final/src/kernel/qubit.py b/real_final/src/kernel/qubit.py new file mode 100644 index 0000000..9b0149a --- /dev/null +++ b/real_final/src/kernel/qubit.py @@ -0,0 +1,88 @@ +from .utils import * +import sympy +from .gate import Gate, ParametersGate +from ..QCIS.instr import QCIS_instr, QCISOpCode +from .gates_lib import lib_gate + + +class Qsim: + def __init__(self, n): + self.state = None + self.qubits_num = n + + self.global_circuit = None + + def apply(self): + pass + + def apply_gate(self, gate: Gate, target_qubits: list, parameters=None, extra_optional_control_qubits=None) \ + -> sympy.Matrix: + + if extra_optional_control_qubits is None: + extra_optional_control_qubits = [] + if parameters is None: + parameters = [] + + qubit_map = target_qubits[gate.ctrl_num:] + ctrl_map = target_qubits[0: gate.ctrl_num] + extra_optional_control_qubits + + if isinstance(gate, ParametersGate): + G = gate.get_matrix(get_discrete(qubit_map), parameters=parameters) + else: + G = gate.get_matrix(get_discrete(qubit_map)) + # 合并俩操作 + qubit_map.sort() + + marki = get_mark(qubit_map, 0) + mark = get_mark(qubit_map, self.qubits_num) + + ctrl_mark = get_mark(ctrl_map, 0) + + addr = gen_subset(mark) + addri = sorted(gen_subset(marki)) + + for s in addr: + if ctrl_mark == 0 or s & ctrl_mark: + addrs = [(s | i) for i in addri] + x = sympy.Matrix([self.state[i] for i in addrs]) + x = G * x + for i, j in zip(addrs, x): + self.state[i] = j + return self.state + + +class Qsim_state(Qsim): + def __init__(self, n, name): + super().__init__(n) + self.state = sympy.Matrix(sympy.symbols('a:' + "%d" % (1 << n))) + + self.map = {} + self.in_use = 0 + for qubit in name: + self.map[qubit] = self.in_use + self.in_use += 1 + + def apply_instr(self, instr: QCIS_instr): + if instr.op_code.is_single_qubit_op(): + gate = Gate(lib_gate(instr)) + qubit = self.map[instr.qubit] + self.apply_gate(gate, [qubit]) + elif instr.op_code.is_two_qubit_op(): + if instr.op_code == QCISOpCode.CNOT or instr.op_code == QCISOpCode.CZ: + gate = Gate(lib_gate(instr), 1) + qubit = self.map[instr.target_qubit] + ctrl = self.map[instr.control_qubit] + self.apply_gate(gate, [ctrl, qubit]) + else: + gate = Gate(lib_gate(instr)) + qubit = self.map[instr.target_qubit] + fake_ctrl = self.map[instr.control_qubit] + self.apply_gate(gate, [qubit, fake_ctrl]) + elif instr.op_code.is_measure_op(): + gate = Gate(lib_gate(instr)) + qubit_list = [self.map[qubit] for qubit in instr.qubits_list] + for qubit in qubit_list: + self.apply_gate(gate, [qubit]) + + + return gate diff --git a/real_final/src/kernel/utils.py b/real_final/src/kernel/utils.py new file mode 100644 index 0000000..b91b3a6 --- /dev/null +++ b/real_final/src/kernel/utils.py @@ -0,0 +1,78 @@ +from sympy import Matrix +from math import log2, ceil + + +def find_main(state, qubit): + p0 = 0 + p1 = 0 + for i in range(len(state)): + num = state[i] + if (i >> qubit) & 0x1: + p1 += num * num + else: + p0 += num * num + return p0, p1 + + +def kron(A, B): + """Return the Kronecker product of matrix A and matrix B""" + return Matrix( + [[A.row(i // B.rows)[j // B.cols] * B.row(i % B.rows)[j % B.cols] + for j in range(A.cols * B.cols)] + for i in range(A.rows * B.rows)] + ) + + +def gen_subset(s): + res = [] + now = s + while now: + res.append(now) + now = (now - 1) & s + res.append(now) + return res + + +def map_bit(x, s, mapp): + for i in range(len(mapp)): + s |= ((x >> i) & 1) << mapp[i] + return s + + +def get_mark(num, l): + """ + + """ + mark = 0 + for i in num: + mark |= 1 << i + if l != 0: + mark = (~mark) & ((1 << l) - 1) + return mark + + +def get_discrete(x): + rx = sorted([(i, j) for i, j in zip(x, range(len(x)))]) + res = [0] * len(x) + for i in range(len(rx)): + res[rx[i][1]] = i + return res + + +def str_bin(x, n): + s = bin(x)[2:] + return reversed("0" * (n - len(s)) + s) + + +def make_bin(x, n, keys): + s = str_bin(x, n) + return "".join(["%s_{%s}" % (i, j) for i, j in zip(s, keys)]) + + +def make_ket(keys): + n = len(keys) + return [make_bin(i, n, keys) for i in range(1 << n)] + + + + diff --git a/real_final/src/output/__init__.py b/real_final/src/output/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/real_final/src/output/store.py b/real_final/src/output/store.py new file mode 100644 index 0000000..99cfc26 --- /dev/null +++ b/real_final/src/output/store.py @@ -0,0 +1,59 @@ +from sympy import Matrix, latex +from kernel.gate import Gate +from QCIS.instr import QCIS_instr, QCISOpCode +from output.symbol_map import symbol_map + + +class store: + def __init__(self, init, mapping: symbol_map, output_list): + self.instr_save = [] + self.state_save = [] + self.circuit_save = [] + self.gate_save = [] + self.init_state = init.state.copy() + self.final_state = None + self.symbol_map = mapping + self.out_list = output_list + + def save_final(self, state): + self.final_state = latex(state.transpose()) + + def save_instr(self, state: Matrix, instr: QCIS_instr, gate: Gate): + ins_str = str(instr.op_code).removeprefix("QCISOpCode.") + if instr.op_code.is_single_qubit_op(): + ins_str += '\t' + str(instr.qubit) + elif instr.op_code.is_two_qubit_op(): + if instr.op_code == QCISOpCode.CNOT or instr.op_code == QCISOpCode.CZ: + ins_str += '\t' + str(instr.control_qubit) + '\t' + str(instr.target_qubit) + else: + ins_str += '\t' + str(instr.control_qubit) + '\t' + str(instr.target_qubit) + elif instr.op_code.is_measure_op(): + tmp = '\t' + ins_str += '\t' + tmp.join([str(qubit) for qubit in instr.qubits_list]) + + self.instr_save.append(ins_str) + self.state_save.append(latex(state.transpose())) + self.gate_save.append(latex(gate.matrix)) + + def write_init(self): + return self.init_state.transpose() + + def output_markdown(self, qcis_name="test.qcis", name='a.md'): + file = open(name, 'w') + file.write("# The ans of %s\n\n" % qcis_name) + file.write("**Init state** is: \n$$\n%s\n$$\n\n" % latex(self.write_init())) + for i in range(len(self.instr_save)): + file.write("```assembly\n%d. %s\n```\n\n" % (self.out_list[i], self.instr_save[i])) + file.write("$$\n%s\n$$\n" % self.gate_save[i]) + file.write("$$\n%s\n$$\n" % self.state_save[i]) + + file.write("**Final state** is: \n$$\n%s\n$$\n\n" % self.final_state) + + if self.symbol_map.use: + file.write("**symbols** is:\n\n") + for x, y in self.symbol_map.symbol_table.items(): + file.write("$%s$ : %f\t\t" % (latex(x), y)) + file.close() + + + diff --git a/real_final/src/output/symbol_map.py b/real_final/src/output/symbol_map.py new file mode 100644 index 0000000..e1dd098 --- /dev/null +++ b/real_final/src/output/symbol_map.py @@ -0,0 +1,25 @@ +from sympy import symbols + + +class symbol_map: + def __init__(self): + self.symbol_table = {} + self.theta = 0 + self.phi = 0 + self.use = False + + def store_symbol(self, type, val) -> symbols: + self.use = True + if type == 'theta': + symbol = symbols('theta' + str(self.theta)) + self.theta += 1 + self.symbol_table[symbol] = val + return symbol + elif type == 'phi': + symbol = symbols('phi' + str(self.phi)) + self.phi += 1 + self.symbol_table[symbol] = val + return symbol + + def get_symbol(self, symbol: symbols): + return self.symbol_table[symbol] -- Gitee From 117794e12cbe9dd96c040069d819d72a0c7a2114 Mon Sep 17 00:00:00 2001 From: chunhui2333 <1772662323@qq.com> Date: Mon, 18 Jul 2022 00:45:23 +0800 Subject: [PATCH 3/5] first --- real_final/src/do_sim.py | 2 +- src/examples/bell_state/host.py | 6 +++--- src/quingo/if_backend/backend_hub.py | 4 ++-- .../{pyqdraw_quantumsim.py => symqc_quantumsim.py} | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) rename src/quingo/if_backend/non_arch_backend/{pyqdraw_quantumsim.py => symqc_quantumsim.py} (92%) diff --git a/real_final/src/do_sim.py b/real_final/src/do_sim.py index 83ac8f7..7f485ef 100644 --- a/real_final/src/do_sim.py +++ b/real_final/src/do_sim.py @@ -7,7 +7,7 @@ from .output.symbol_map import symbol_map """ The main programme """ -class PyDraw(object): +class SymQC(object): def __init__(self): self.args = None self.job_arr = None diff --git a/src/examples/bell_state/host.py b/src/examples/bell_state/host.py index b1e72db..4e612cf 100644 --- a/src/examples/bell_state/host.py +++ b/src/examples/bell_state/host.py @@ -6,18 +6,18 @@ from pathlib import Path # qi.set_log_level(logging.DEBUG) qi.set_compiler('mlir') -if qi.connect_backend('pyqcisim_quantumsim') is False: +if qi.connect_backend('symqc_quantumsim') is False: exit(-1) qu_file = Path(__file__).parent / "kernel.qu" def routine(circ_name, num_shots=1): - qi.set_num_shots(num_shots) + if not qi.call_quingo(qu_file, circ_name): print("Failed to call {}".format(circ_name)) print("The result of {} is:".format(circ_name)) print(qi.read_result()) -routine("bell_state", 1000) +routine("bell_state") diff --git a/src/quingo/if_backend/backend_hub.py b/src/quingo/if_backend/backend_hub.py index be2d377..10c1ea3 100755 --- a/src/quingo/if_backend/backend_hub.py +++ b/src/quingo/if_backend/backend_hub.py @@ -50,8 +50,8 @@ class Backend_hub(): 'PyQCISim_quantumsim', 'pyqcisim_quantumsim', with_timing=False, is_simulator=True) - self.backends['pyqdraw_quantumsim'] = Backend_info( - 'PyDRAW_quantumsim', 'pyqdraw_quantumsim', with_timing=False, + self.backends['symqc_quantumsim'] = Backend_info( + 'SymQC_quantumsim', 'symqc_quantumsim', with_timing=False, is_simulator=True) def support(self, backend_name): diff --git a/src/quingo/if_backend/non_arch_backend/pyqdraw_quantumsim.py b/src/quingo/if_backend/non_arch_backend/symqc_quantumsim.py similarity index 92% rename from src/quingo/if_backend/non_arch_backend/pyqdraw_quantumsim.py rename to src/quingo/if_backend/non_arch_backend/symqc_quantumsim.py index 547f5f9..08136f9 100644 --- a/src/quingo/if_backend/non_arch_backend/pyqdraw_quantumsim.py +++ b/src/quingo/if_backend/non_arch_backend/symqc_quantumsim.py @@ -7,14 +7,14 @@ from src import do_sim; logger = get_logger((__name__).split('.')[-1]) -class PyDraw_quantumsim(If_backend): +class SymQC_quantumsim(If_backend): """A functional QCIS simulation backend using PyQCISim and QuantumSim.""" def __init__(self, **kwargs): #关键字参数 - super().__init__("PyDraw_QuantumSim", is_simaultor=True) - self.sim = do_sim.PyDraw() - self.pyqcisim_dir = gc.qgrtsys_root_dir / "if_backend" / "pydraw" + super().__init__("SymQC_QuantumSim", is_simaultor=True) + self.sim = do_sim.SymQC() + self.pyqcisim_dir = gc.qgrtsys_root_dir / "if_backend" / "symqc" self.verbose = kwargs.pop('verbose', False) #没有就返回False self.loglevel = kwargs.pop('loglevel', logging.INFO) #没有就返回logging.INFO logger.setLevel(self.loglevel) -- Gitee From f40190d11ea74e42b00d20555aa6819937ba8107 Mon Sep 17 00:00:00 2001 From: chunhui2333 <1772662323@qq.com> Date: Mon, 18 Jul 2022 18:42:53 +0800 Subject: [PATCH 4/5] tested --- real_final/src/do_sim.py | 4 ---- src/examples/bell_state/host.py | 2 +- src/quingo/if_backend/non_arch_backend/symqc_quantumsim.py | 6 +++++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/real_final/src/do_sim.py b/real_final/src/do_sim.py index 7f485ef..b4a61f6 100644 --- a/real_final/src/do_sim.py +++ b/real_final/src/do_sim.py @@ -41,8 +41,4 @@ class SymQC(object): instr.altitude = maps.store_symbol("theta", instr.altitude) Q = Qsim_ket(len(self.names), self.names) - - init_printing() - for instr in self.job_arr: - gate = Q.apply_instr(instr) return Q.state.map #这里出了一点点问题 diff --git a/src/examples/bell_state/host.py b/src/examples/bell_state/host.py index 4e612cf..c3fd755 100644 --- a/src/examples/bell_state/host.py +++ b/src/examples/bell_state/host.py @@ -8,7 +8,7 @@ qi.set_compiler('mlir') if qi.connect_backend('symqc_quantumsim') is False: exit(-1) - + qu_file = Path(__file__).parent / "kernel.qu" diff --git a/src/quingo/if_backend/non_arch_backend/symqc_quantumsim.py b/src/quingo/if_backend/non_arch_backend/symqc_quantumsim.py index 08136f9..d49f37f 100644 --- a/src/quingo/if_backend/non_arch_backend/symqc_quantumsim.py +++ b/src/quingo/if_backend/non_arch_backend/symqc_quantumsim.py @@ -2,7 +2,10 @@ from pathlib import Path from quingo.if_backend.if_backend import If_backend import quingo.global_config as gc from quingo.core.utils import * -from src import do_sim; +from symqc import do_sim +# from SymQC import do_sim; +# from symqc.output.symbol_map import symbol_map + logger = get_logger((__name__).split('.')[-1]) @@ -51,6 +54,7 @@ class SymQC_quantumsim(If_backend): def execute(self): try: self.res=self.sim.excute() + return True except Exception as e: quingo_err("Error in PyQCISim Simulation: {}".format(e)) return False -- Gitee From 54935b096cb6f14a9108473352cea644cc0708d7 Mon Sep 17 00:00:00 2001 From: chunhui2333 <1772662323@qq.com> Date: Mon, 18 Jul 2022 19:00:39 +0800 Subject: [PATCH 5/5] second --- real_final/setup.py | 10 - real_final/src/QCIS/__init__.py | 0 real_final/src/QCIS/instr.py | 151 ----------- real_final/src/QCIS/lexer.py | 125 --------- real_final/src/QCIS/parser.py | 199 --------------- real_final/src/__init__.py | 0 real_final/src/do_sim.py | 44 ---- real_final/src/kernel/__init__.py | 0 real_final/src/kernel/circuit.py | 83 ------ real_final/src/kernel/gate.py | 87 ------- real_final/src/kernel/gates_lib.py | 293 ---------------------- real_final/src/kernel/ket/__init__.py | 0 real_final/src/kernel/ket/entanglement.py | 0 real_final/src/kernel/ket/qubit.py | 65 ----- real_final/src/kernel/ket/state.py | 120 --------- real_final/src/kernel/ket/store.py | 50 ---- real_final/src/kernel/qubit.py | 88 ------- real_final/src/kernel/utils.py | 78 ------ real_final/src/output/__init__.py | 0 real_final/src/output/store.py | 59 ----- real_final/src/output/symbol_map.py | 25 -- 21 files changed, 1477 deletions(-) delete mode 100644 real_final/setup.py delete mode 100644 real_final/src/QCIS/__init__.py delete mode 100644 real_final/src/QCIS/instr.py delete mode 100644 real_final/src/QCIS/lexer.py delete mode 100644 real_final/src/QCIS/parser.py delete mode 100644 real_final/src/__init__.py delete mode 100644 real_final/src/do_sim.py delete mode 100644 real_final/src/kernel/__init__.py delete mode 100644 real_final/src/kernel/circuit.py delete mode 100644 real_final/src/kernel/gate.py delete mode 100644 real_final/src/kernel/gates_lib.py delete mode 100644 real_final/src/kernel/ket/__init__.py delete mode 100644 real_final/src/kernel/ket/entanglement.py delete mode 100644 real_final/src/kernel/ket/qubit.py delete mode 100644 real_final/src/kernel/ket/state.py delete mode 100644 real_final/src/kernel/ket/store.py delete mode 100644 real_final/src/kernel/qubit.py delete mode 100644 real_final/src/kernel/utils.py delete mode 100644 real_final/src/output/__init__.py delete mode 100644 real_final/src/output/store.py delete mode 100644 real_final/src/output/symbol_map.py diff --git a/real_final/setup.py b/real_final/setup.py deleted file mode 100644 index 82d403e..0000000 --- a/real_final/setup.py +++ /dev/null @@ -1,10 +0,0 @@ -import setuptools -setuptools.setup(name='symqc', - version='0.0.1', - description='Quantum computing simulator based on symbolic operation', - url='https://gitee.com/huang-zixiao/qsim', - author='13974811840', - author_email='1245949348@qq.com', - license='MIT', - packages=setuptools.find_packages(), - zip_safe=False) \ No newline at end of file diff --git a/real_final/src/QCIS/__init__.py b/real_final/src/QCIS/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/real_final/src/QCIS/instr.py b/real_final/src/QCIS/instr.py deleted file mode 100644 index d166276..0000000 --- a/real_final/src/QCIS/instr.py +++ /dev/null @@ -1,151 +0,0 @@ -from enum import Enum, auto - - -class QCISOpCode(Enum): - # The first single-qubit operation - RZ = auto() - XYARB = auto() - XY = auto() - XY2P = auto() - XY2M = auto() - X = auto() - X2P = auto() - X2M = auto() - Y = auto() - Y2P = auto() - Y2M = auto() - Z = auto() - Z2P = auto() - Z2M = auto() - Z4P = auto() - Z4M = auto() - S = auto() - SD = auto() - T = auto() - TD = auto() - H = auto() - RX = auto() - RY = auto() - RXY = auto() - # The last single-qubit operation - - # The first two-qubit operation - CZ = auto() - CNOT = auto() - SWP = auto() - SSWP = auto() - ISWP = auto() - SISWP = auto() - CP = auto() - FSIM = auto() - # The last two-qubit operation - - # The first measurement operation - MEASURE = auto() - M = auto() - # The last measurement operation - - B = auto() - - def is_single_qubit_op(self): - return self.RZ.value <= self.value <= self.RXY.value - - def is_two_qubit_op(self): - return self.CZ.value <= self.value <= self.FSIM.value - - def is_measure_op(self): - return self.MEASURE.value <= self.value <= self.M.value - - -class QCIS_instr(object): - def __init__(self, op_code, **kwargs): - """ - Data structure for representing QCIS instructions. - - Attributes: - op_code: The operation code of the QCIS instruction. - azimuth: The angle between the axis to rotate along and z-axis. - altitude: The angle of rotation along a given axis. - - Single-qubit operation only attributes: - qubit: The name string of target qubit. - - Two-qubit operation only attributes: - control_qubit: The name string of control qubit. - target_qubit: The name string of target qubit. - - Measurement operation only attributes: - qubits_list: The names of all qubits to be measured. - """ - self.op_code = op_code - - if op_code.is_two_qubit_op(): - if self.op_code == QCISOpCode.CP or self.op_code == QCISOpCode.FSIM: - self.azimuth = kwargs["azimuth"] - self.control_qubit = kwargs["control_qubit"] - self.target_qubit = kwargs["target_qubit"] - return - - if op_code.is_single_qubit_op(): - self.qubit = kwargs["qubit"] - - if self.op_code == QCISOpCode.XYARB or self.op_code == QCISOpCode.RXY: - self.azimuth = kwargs["azimuth"] - self.altitude = kwargs["altitude"] - return - - if ( - self.op_code == QCISOpCode.XY - or self.op_code == QCISOpCode.XY2P - or self.op_code == QCISOpCode.XY2M - or self.op_code == QCISOpCode.RZ - ): - self.azimuth = kwargs["azimuth"] - return - - if self.op_code == QCISOpCode.RX or self.op_code == QCISOpCode.RY: - self.altitude = kwargs["altitude"] - return - - return - - if op_code.is_measure_op(): - # Should be a list even measuring only one qubit - self.qubits_list = kwargs["qubits_list"] - self.qubits_list.sort() - return - - if op_code == QCISOpCode.B: - self.qubits_list = kwargs["qubits_list"] - self.qubits_list.sort() - return - - raise ValueError("Found unrecognized opcode: ", op_code) - - def __str__(self): - if self.op_code.is_two_qubit_op(): - return "Two-qubit op: {}, control: {}, target: {}".format( - self.op_code, self.control_qubit, self.target_qubit - ) - - if self.op_code.is_single_qubit_op(): - params_str = "" - if self.op_code == QCISOpCode.XYARB: - params_str = ", azimuth: {}, altitude: {}".format( - self.azimuth, self.altitude - ) - return "Single-qubit op: {}, qubit: {}{}".format( - self.op_code, self.qubit, params_str - ) - - if self.op_code.is_measure_op(): - qubits_list_str = " ".join([qubit for qubit in self.qubits_list]) - return "Measure op: {}, qubits list: {}".format( - self.op_code, qubits_list_str - ) - - raise ValueError("Unrecognized instruction.") - - def __eq__(self, other): - # Two QCISInst instances with same values of attributes will be identical - return self.__dict__ == other.__dict__ diff --git a/real_final/src/QCIS/lexer.py b/real_final/src/QCIS/lexer.py deleted file mode 100644 index a0b0aad..0000000 --- a/real_final/src/QCIS/lexer.py +++ /dev/null @@ -1,125 +0,0 @@ -import ply.lex as lex - - -class QCISLexer(object): - """QCIS lexer""" - - def __init__(self): - """Create a ply lexer.""" - self.data = None - self.lexer = lex.lex(module=self, debug=False, errorlog=lex.NullLogger()) - self.lineno = 1 - - def input(self, data): - """Set the input text data.""" - self.data = data - self.lexer.input(data) - - def token(self): - """Return the next token.""" - ret = self.lexer.token() - return ret - - reserved = { - # ---Basic Operations--- - "CZ": "CZ", - "MEASURE": "MEASURE", # Deprecated measurement, use `M` - "M": "M", # Recommended measurement - "RZ": "RZ", - "XYARB": "XYARB", # Deprecated arbitrary xy-plane axis rotation, use `RXY` - "XY": "XY", - "XY2P": "XY2P", - "XY2M": "XY2M", - "X": "X", - "X2P": "X2P", - "X2M": "X2M", - "Y": "Y", - "Y2P": "Y2P", - "Y2M": "Y2M", - "Z": "Z", - "Z2P": "Z2P", # Deprecated z-axis rotation, use `S` - "Z2M": "Z2M", # Deprecated z-axis rotation, use `SD` - "Z4P": "Z4P", # Deprecated z-axis rotation, use `T` - "Z4M": "Z4M", # Deprecated z-axis rotation , use `TD` - "S": "S", - "SD": "SD", - "T": "T", - "TD": "TD", - "B": "B", # Time barrier for two qubits (useless in simulator) - # ---Extended Operations--- - "H": "H", - "RX": "RX", - "RY": "RY", - "RXY": "RXY", - "CNOT": "CNOT", - "SWP": "SWP", - "SSWP": "SSWP", - "ISWP": "ISWP", - "SISWP": "SISWP", - "CP": "CP", - "FSIM": "FSIM", - # ---Advanced Operations--- - # ! Note: Not supported now! - # "SET": "SET", - # "CMT": "CMT", - # "I": "I", - # "X12": "X12", - # "X23": "X23", - # "AXY": "AXY", - # "DTN": "DTN", - # "PLS": "PLS", - # "PLSXY": "PLSXY", - # "SWD": "SWD", - # "SWA": "SWA", - # "MOV": "MOV", - } - - tokens = ["FLOAT", "QREG", "NEWLINE"] + list(reserved.values()) - - def t_FLOAT(self, t): - r"""[-+]?[0-9]+(\.([0-9]+)?([eE][-+]?[0-9]+)?|[eE][-+]?[0-9]+)?""" - # r"[-]?\d+(\.\d+)?" - t.value = float(t.value) - - return t - - def t_QREG(self, t): - r"""[a-zA-Z_][\.a-zA-Z_0-9]*""" - # If it is an identifier but not a reserved word, then it must be QREG - t.type = self.reserved.get(t.value, "QREG") - return t - - def t_NEWLINE(self, t): - r"""\n""" - self.lineno += len(t.value) - t.lexer.lineno = self.lineno - return t - - t_ignore = " \t" - # Note that `.` can not match \n - t_ignore_COMMENT = r"\#.*" - - def find_column(self, t): - """Compute the column of the token t.""" - if t is None: - return 0 - last_line_end = self.data.rfind("\n", 0, t.lexpos) - column = t.lexpos - last_line_end - return column - - def t_error(self, t): - # When a token has no matching rule, `t.value` will contain the rest of input. - # Thus we usually only report the string before the first space, \n or \t. - raise ValueError( - "Give string ({}) at (line {}, col {}) cannot match any QCIS token rule".format( - t.value.split(" ")[0].split("\n")[0].split("\t")[0], - t.lexer.lineno, - self.find_column(t), - ) - ) - - def get_all_token(self): - return [tok for tok in self.lexer] - - def get_all_token_info(self): - return [(tok.type, tok.value, tok.lineno, tok.lexpos) for tok in self.lexer] diff --git a/real_final/src/QCIS/parser.py b/real_final/src/QCIS/parser.py deleted file mode 100644 index 2d1ced1..0000000 --- a/real_final/src/QCIS/parser.py +++ /dev/null @@ -1,199 +0,0 @@ -import tempfile - -import ply.yacc as yacc - -from .instr import QCISOpCode, QCIS_instr -from .lexer import QCISLexer - -OP_CODE_CONVERTER = { - "MEASURE": QCISOpCode.MEASURE, - "M": QCISOpCode.M, - "B": QCISOpCode.B, - "XY": QCISOpCode.XY, - "XY2P": QCISOpCode.XY2P, - "XY2M": QCISOpCode.XY2M, - "X": QCISOpCode.X, - "X2P": QCISOpCode.X2P, - "X2M": QCISOpCode.X2M, - "Y": QCISOpCode.Y, - "Y2P": QCISOpCode.Y2P, - "Y2M": QCISOpCode.Y2M, - "Z": QCISOpCode.Z, - "Z2P": QCISOpCode.Z2P, - "Z2M": QCISOpCode.Z2M, - "Z4P": QCISOpCode.Z4P, - "Z4M": QCISOpCode.Z4M, - "S": QCISOpCode.S, - "SD": QCISOpCode.SD, - "T": QCISOpCode.T, - "TD": QCISOpCode.TD, - "H": QCISOpCode.H, - "RX": QCISOpCode.RX, - "RY": QCISOpCode.RY, - "RZ": QCISOpCode.RZ, - "XYARB": QCISOpCode.XYARB, - "RXY": QCISOpCode.RXY, - "CZ": QCISOpCode.CZ, - "CNOT": QCISOpCode.CNOT, - "SWP": QCISOpCode.SWP, - "SSWP": QCISOpCode.SSWP, - "ISWP": QCISOpCode.ISWP, - "SISWP": QCISOpCode.SISWP, - "CP": QCISOpCode.CP, - "FSIM": QCISOpCode.FSIM, -} - - -class QCISParser(object): - """QCIS parser""" - start = "root" - - def __init__(self): - self.error_list = None - self.lexer = QCISLexer() - self.tokens = self.lexer.tokens # Import all defined tokens in lexer - self.parse_dir = tempfile.mkdtemp(prefix="sim-test") - self.parser = yacc.yacc(module=self, debug=False, outputdir=self.parse_dir) - self.__instructions = [] # To save all instructions extracted from program - self.__qubit_names = set() # A set for all qubit names occurred in program - - # As instructions are generated when specific rules are matched, these two method do not need to do any thing! - def p_root(self, p): - """root : program""" - pass - - def p_program(self, p): - """program : instruction NEWLINE program - | instruction - | NEWLINE program - | - """ - pass - - def p_instruction_n_qubit(self, p): - """instruction : MEASURE qlist - | M qlist - | B qlist""" - self.__qubit_names.update(p[2]) - self.__instructions.append(QCIS_instr(OP_CODE_CONVERTER[p[1]], qubits_list=p[2])) - - def p_qlist(self, p): - """qlist : QREG qlist - | QREG - """ - if len(p) == 3: # Matching rule 1 - # Extending qlist.value (a list, p[2]) with QREG.value (a number, p[1]) - p[0] = [p[1]] + p[2] - else: # Matching rule 2 - # Create the starting qubits list for all qubits to be measured - p[0] = [p[1]] - - def p_instruction_1_qubit_2_param(self, p): - """instruction : XYARB QREG FLOAT FLOAT - | RXY QREG FLOAT FLOAT""" - self.__qubit_names.add(p[2]) - self.__instructions.append( - QCIS_instr(OP_CODE_CONVERTER[p[1]], qubit=p[2], azimuth=p[3], altitude=p[4]) - ) - - def p_instruction_1_qubit_1_altitude(self, p): - """instruction : RX QREG FLOAT - | RY QREG FLOAT""" - self.__qubit_names.add(p[2]) - self.__instructions.append( - QCIS_instr(OP_CODE_CONVERTER[p[1]], qubit=p[2], altitude=p[3]) - ) - - def p_instruction_1_qubit_1_azimuth(self, p): - """instruction : XY QREG FLOAT - | XY2P QREG FLOAT - | XY2M QREG FLOAT - | RZ QREG FLOAT""" - self.__qubit_names.add(p[2]) - self.__instructions.append( - QCIS_instr(OP_CODE_CONVERTER[p[1]], qubit=p[2], azimuth=p[3]) - ) - - def p_instruction_1_qubit_0_param(self, p): - """instruction : X QREG - | X2P QREG - | X2M QREG - | Y QREG - | Y2P QREG - | Y2M QREG - | Z QREG - | Z2P QREG - | Z2M QREG - | Z4P QREG - | Z4M QREG - | S QREG - | SD QREG - | T QREG - | TD QREG - | H QREG""" - self.__qubit_names.add(p[2]) - self.__instructions.append(QCIS_instr(OP_CODE_CONVERTER[p[1]], qubit=p[2])) - - def p_instruction_2_qubit_0_param(self, p): - """instruction : CZ QREG QREG - | CNOT QREG QREG - | SWP QREG QREG - | SSWP QREG QREG - | ISWP QREG QREG - | SISWP QREG QREG""" - self.__qubit_names.update({p[2], p[3]}) - self.__instructions.append( - QCIS_instr(OP_CODE_CONVERTER[p[1]], control_qubit=p[2], target_qubit=p[3]) - ) - - def p_instruction_2_qubit_1_param(self, p): - """instruction : CP QREG QREG FLOAT - | FSIM QREG QREG FLOAT""" - self.__qubit_names.update({p[2], p[3]}) - self.__instructions.append( - QCIS_instr( - OP_CODE_CONVERTER[p[1]], - control_qubit=p[2], - target_qubit=p[3], - azimuth=p[4], - ) - ) - - def p_error(self, p): - """Error handling method skipping error-occurred line.""" - if not p: - error_msg = "Syntax error at the end of program." - self.error_list.append(error_msg) - return - - col = self.lexer.find_column(p) - lines = self.lexer.data.split("\n") - error_msg = "Syntax error: Found unmatched {0} at ({1}, {2}).\nSkip line {1}: {3}".format( - p.type, self.lexer.lineno, col, lines[p.lineno - 1] - ) - self.error_list.append(error_msg) - - # Read ahead looking for a new line - while True: - tok = self.lexer.token() # Get the next token - if not tok or tok.type == "NEWLINE": - break - self.parser.restart() - - def parse(self, data): - self.__instructions = [] # Clear instructions list - self.__qubit_names = set() # Clear qubit names set - self.error_list = [] - self.lexer = QCISLexer() # Reset initial lineno of lexer - self.parser.parse(data, lexer=self.lexer) - - success = True - if len(self.error_list) > 0: - error_msgs = "\n".join(self.error_list) - print("Found errors during parsing QCIS program: {}".format(error_msgs)) - success = False - - qubit_names_list = list(self.__qubit_names) # Turn the set to a list - qubit_names_list.sort() # Sort by alphabetic - return success, self.__instructions, qubit_names_list - diff --git a/real_final/src/__init__.py b/real_final/src/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/real_final/src/do_sim.py b/real_final/src/do_sim.py deleted file mode 100644 index b4a61f6..0000000 --- a/real_final/src/do_sim.py +++ /dev/null @@ -1,44 +0,0 @@ -from .QCIS.parser import QCISParser, QCISOpCode -from sympy import init_printing -from .kernel.ket.qubit import Qsim_ket -from .output.symbol_map import symbol_map -#from ..quantumsim.sparsedm import SparseDM - -""" -The main programme -""" -class SymQC(object): - def __init__(self): - self.args = None - self.job_arr = None - self.names = None - self.filename = None - self._sdm = None - - - def compiler(self,_prog): - """""" - _parser = QCISParser() - success, instructions, name = _parser.parse(data=_prog) - if not success: - print(_parser.error_list) - raise ValueError("QCIS parser failed to compile the given QCIS program.") - self.job_arr = instructions - self.names = name #工作点在这里 - #self._sdm = SparseDM(name) - return instructions, name - - def excute(self): - maps = symbol_map() - - for instr in self.job_arr: - if instr.op_code == QCISOpCode.RXY: - instr.altitude = maps.store_symbol("theta", instr.altitude) - instr.azimuth = maps.store_symbol("phi", instr.azimuth) - elif instr.op_code == QCISOpCode.XY or instr.op_code == QCISOpCode.XY2P or instr.op_code == QCISOpCode.XY2M: - instr.azimuth = maps.store_symbol("phi", instr.azimuth) - elif instr.op_code == QCISOpCode.RX or instr.op_code == QCISOpCode.RY or instr.op_code == QCISOpCode.RZ: - instr.altitude = maps.store_symbol("theta", instr.altitude) - - Q = Qsim_ket(len(self.names), self.names) - return Q.state.map #这里出了一点点问题 diff --git a/real_final/src/kernel/__init__.py b/real_final/src/kernel/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/real_final/src/kernel/circuit.py b/real_final/src/kernel/circuit.py deleted file mode 100644 index a487efd..0000000 --- a/real_final/src/kernel/circuit.py +++ /dev/null @@ -1,83 +0,0 @@ -import sympy -from utils import gen_subset, get_mark, map_bit - -""" -The implementation of class Circuit -""" - - -class Circuit: - def __init__(self, n): - self.n = n # the number of qubits - self.gates = [] - self.matrix = sympy.eye(2 ** n) - - def add_gates(self, gates: list, init=0): - """Add gates to the circuit""" - if self.matrix == sympy.eye(2 ** self.n): - self.matrix = Circuit.combine_gates(gates, self.n) - else: - self.matrix = Circuit.combine_gates(gates, self.n) * self.matrix - self.gates.append(gates) - - @staticmethod - def make_from_gates_sequence(gates_sequence: list, n=0): - """Make a circuit from a sequence of gates""" - if n == 0: - for gates in gates_sequence: - for gate in gates: - n = max(n, max(gate[1] + gate[2])) - - res = Circuit(n) - for gates in gates_sequence: - res.add_gates(gates) - - return res - - @staticmethod - def combine_gates(gates: list, n): - """Build the utility matrix of these gates""" - vis = [0] * n - mark = 0 - res = sympy.ones(2 ** n, 2 ** n) - blnk = [] - - for g, opt_list, ctrl_list in gates: - mark = 0 - for i in opt_list: - vis[i] = 1 - for i in ctrl_list: - vis[i] = 1 - - blnk = [i for i in range(len(vis)) if vis[i] == 0] - vis = [i for i in range(len(vis)) if vis[i] != 0] - - matI = sympy.eye(2) - - for p in blnk: - - addr = gen_subset(get_mark([p], n)) - for i in range(matI.rows): - for j in range(matI.cols): - for si in addr: - mi = map_bit(i, si, [p]) - for sj in addr: - mj = map_bit(j, sj, [p]) - res[mi, mj] = res[mi, mj] * matI[i, j] - - for g, opt_list, ctrl_list in gates: - bits = opt_list + ctrl_list - - mark = get_mark(bits, n) - addr = gen_subset(mark) - mat = g.get_matrix(range(g.n), range(g.n, g.n + g.ctrl_num), g.n + g.ctrl_num) - - for i in range(mat.rows): - for j in range(mat.cols): - for si in addr: - mi = map_bit(i, si, bits) - for sj in addr: - mj = map_bit(j, sj, bits) - res[mi, mj] = res[mi, mj] * mat[i, j] - - return res diff --git a/real_final/src/kernel/gate.py b/real_final/src/kernel/gate.py deleted file mode 100644 index 8d32210..0000000 --- a/real_final/src/kernel/gate.py +++ /dev/null @@ -1,87 +0,0 @@ -from math import log2 -import sympy -from .utils import * - - -class Gate: - def __init__(self, mat, ctrl=0): - self.matrix = sympy.Matrix(mat) - assert (self.matrix.cols == self.matrix.rows) - self.n = log2(self.matrix.cols) - assert (self.n == int(self.n)) - self.n = int(self.n) - self.ctrl_num = ctrl - - def get_matrix(self, qubit_map=None, ctrl_map=None, n=0): - if ctrl_map is None: - ctrl_map = [] - if qubit_map is None: - qubit_map = [] - qubit_map = list(qubit_map) - ctrl_map = list(ctrl_map) - - if n == 0: - n = self.n - - if self.ctrl_num == 0: - if not qubit_map: - return self.matrix - else: - if ctrl_map == [] and qubit_map == []: - return self.matrix - - res = sympy.ones(2 ** n, 2 ** n) - - matI = sympy.eye(2) - - for p in range(n): - if p not in qubit_map: - mark = get_mark([p], n) - addr = gen_subset(mark) - for i in range(matI.rows): - for j in range(matI.cols): - for si in addr: - mi = map_bit(i, si, [p]) - for sj in addr: - mj = map_bit(j, sj, [p]) - res[mi, mj] = res[mi, mj] * matI[i, j] - - mark = get_mark(qubit_map, n) - ctrl_mark = get_mark(ctrl_map, 0) - addr = gen_subset(mark) - - for i in range(self.matrix.rows): - for j in range(self.matrix.cols): - for si in addr: - mi = map_bit(i, si, qubit_map) - for sj in addr: - mj = map_bit(j, sj, qubit_map) - if ctrl_map: - if mi & ctrl_mark and mj & ctrl_mark: - res[mi, mj] = res[mi, mj] * self.matrix[i, j] - else: - res[mi, mj] = res[mi, mj] * (i == j) - else: - res[mi, mj] = res[mi, mj] * self.matrix[i, j] - return res - - -# SingleQubitGate, TwoQubitGate, MultiQubitGate - -class ParametersGate(Gate): - def __init__(self, mat, ctrl=0, parameters=None): - Gate.__init__(self, mat, ctrl) - if parameters is None: - parameters = [] - self.parameters = parameters - - def get_matrix(self, qubit_map=None, ctrl_map=None, n=0, parameters=None): - if parameters is None: - parameters = [] - if ctrl_map is None: - ctrl_map = [] - if qubit_map is None: - qubit_map = [] - res = Gate.get_matrix(self, qubit_map, ctrl_map, n) - res = res.subs([(self.parameters[i], parameters[i]) for i in range(len(parameters))]) - return res diff --git a/real_final/src/kernel/gates_lib.py b/real_final/src/kernel/gates_lib.py deleted file mode 100644 index fb90d31..0000000 --- a/real_final/src/kernel/gates_lib.py +++ /dev/null @@ -1,293 +0,0 @@ -import sympy -from ..QCIS.instr import QCISOpCode, QCIS_instr - - -sigma_x = sympy.Matrix([[0, 1], [1, 0]]) -sigma_y = sympy.Matrix([[0, -sympy.I], [sympy.I, 0]]) -sigma_z = sympy.Matrix([[1, 0], [0, -1]]) - - -def R(n_head, theta): - sigma_head = sympy.Matrix([sigma_x, sigma_y, sigma_z]) - n1 = n_head[0] - n2 = n_head[1] - n3 = n_head[2] - sigma = sigma_x * n1 + sigma_y * n2 + sigma_z * n3 - return sympy.exp(-sympy.I * theta * sigma / 2) - - -def X(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[0, 1], [1, 0]]) - - -def Y(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[0, -sympy.I], [sympy.I, 0]]) - - -def X2P(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[1, -sympy.I], [-sympy.I, 1]]) * (1 / sympy.sqrt(2)) - - -def X2M(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[1, sympy.I], [sympy.I, 1]]) * (1 / sympy.sqrt(2)) - - -def Y2P(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[1, -1], [1, 1]]) * (1 / sympy.sqrt(2)) - - -def Y2M(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[1, 1], [-1, 1]]) * (1 / sympy.sqrt(2)) - - -def XY(*argv): - if len(argv) != 1: - print("error argv input") - exit(1) - phi = argv[0] - n_head = sympy.Matrix([sympy.cos(phi), sympy.sin(phi), 0]) - return R(n_head, sympy.pi) - - -def XY2P(*argv): - if len(argv) != 1: - print("error argv input") - exit(1) - phi = argv[0] - n_head = sympy.Matrix([sympy.cos(phi), sympy.sin(phi), 0]) - return R(n_head, sympy.pi / 2) - - -def XY2M(*argv): - return XY2P(argv).transpose().conjugate() - - -def Z(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sigma_z - - -def S(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[1, 0], [0, sympy.I]]) - - -def SD(*argv): - return S(argv).transpose().conjugate() - - -def T(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[1, 0], [0, sympy.exp(sympy.I * sympy.pi / 4)]]) - - -def TD(*argv): - return T(argv).transpose().conjugate() - - -def RZ(*argv): - if len(argv) != 1: - print("error argv input") - exit(1) - phi = argv[0] - return sympy.exp(-sympy.pi * sigma_z * phi / 2) - - -def CZ(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[1, 0], [0, -1]]) - - -def M(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[0, 0], [0, 1]]) - - -def B(*argv): - exit(len(argv)) - - -def H(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[1, 1], [1, -1]]) * (1 / sympy.sqrt(2)) - - -def RX(*argv): - if len(argv) != 1: - print("error argv input") - exit(1) - phi = argv[0] - return sympy.exp(-sympy.pi * sigma_x * phi / 2) - - -def RY(*argv): - if len(argv) != 1: - print("error argv input") - exit(1) - phi = argv[0] - return sympy.exp(-sympy.pi * sigma_y * phi / 2) - - -def RXY(*argv): - if len(argv) != 2: - print("error argv input") - exit(1) - theta = argv[0] - phi = argv[1] - n_head = sympy.Matrix([sympy.cos(phi), sympy.sin(phi), 0]) - return R(n_head, theta) - - -def CNOT(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[0, 1], [1, 0]]) - - -def SWP(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[1, 0, 0, 0], - [0, 0, 1, 0], - [0, 1, 0, 0], - [0, 0, 0, 1]]) - - -def SSWP(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[1, 0, 0, 0], - [0, (1 + sympy.I) / 2, (1 - sympy.I) / 2, 0], - [0, (1 - sympy.I) / 2, (1 + sympy.I) / 2, 0], - [0, 0, 0, 1]]) - - -def ISWP(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[1, 0, 0, 0], - [0, 0, sympy.I, 0], - [0, sympy.I, 0, 0], - [0, 0, 0, 1]]) - - -def SISWP(*argv): - if len(argv) != 0: - print("error argv input") - exit(1) - return sympy.Matrix([[1, 0, 0, 0], - [0, 1 / sympy.sqrt(2), sympy.I / sympy.sqrt(2), 0], - [0, sympy.I / sympy.sqrt(2), 1 / sympy.sqrt(2), 0], - [0, 0, 0, 1]]) - - -def CP(*argv): - if len(argv) != 1: - print("error argv input") - exit(1) - phi = argv[0] - return sympy.Matrix([[1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, sympy.exp(sympy.I * phi)]]) - - -delta_plus = 0 -delta_minus = 0 -delta_minus_off = 0 - - -def FSIM(*argv): - if len(argv) != 2: - print("error argv input") - exit(1) - phi = argv[0] - theta = argv[1] - return sympy.Matrix([1, 0, 0, 0], - [0, sympy.exp(sympy.I * (delta_plus + delta_minus)) * sympy.cos(theta), - -sympy.I * sympy.exp(sympy.I * (delta_plus - delta_minus_off)) * sympy.sin(theta), 0], - [0, sympy.exp(sympy.I * (delta_plus + delta_minus_off)) * sympy.sin(theta), - sympy.exp(sympy.I * (delta_plus - delta_minus)) * sympy.cos(theta), 0], - [0, 0, 0, sympy.exp(sympy.I * (2 * delta_plus - phi))]) - - -QCIS_gate = { - QCISOpCode.X: X, - QCISOpCode.Y: Y, - QCISOpCode.X2P: X2P, - QCISOpCode.X2M: X2M, - QCISOpCode.Y2P: Y2P, - QCISOpCode.Y2M: Y2M, - QCISOpCode.XY: XY, - QCISOpCode.XY2P: XY2P, - QCISOpCode.XY2M: XY2M, - QCISOpCode.Z: Z, - QCISOpCode.S: S, - QCISOpCode.SD: SD, - QCISOpCode.T: T, - QCISOpCode.TD: TD, - QCISOpCode.RZ: RZ, - QCISOpCode.CZ: CZ, - QCISOpCode.M: M, - QCISOpCode.B: B, - QCISOpCode.H: H, - QCISOpCode.RX: RX, - QCISOpCode.RY: RY, - QCISOpCode.RXY: RXY, - QCISOpCode.CNOT: CNOT, - QCISOpCode.SWP: SWP, - QCISOpCode.SSWP: SSWP, - QCISOpCode.ISWP: ISWP, - QCISOpCode.SISWP: SISWP, - QCISOpCode.CP: CP, - QCISOpCode.FSIM: FSIM -} - - -def lib_gate(instr: QCIS_instr): - if instr.op_code == QCISOpCode.RXY: - return QCIS_gate[instr.op_code](instr.altitude, instr.azimuth) - elif instr.op_code == QCISOpCode.XY or instr.op_code == QCISOpCode.XY2P or instr.op_code == QCISOpCode.XY2M: - return QCIS_gate[instr.op_code](instr.azimuth) - elif instr.op_code == QCISOpCode.RX or instr.op_code == QCISOpCode.RY or instr.op_code == QCISOpCode.RZ: - return QCIS_gate[instr.op_code](instr.altitude) - else: - return QCIS_gate[instr.op_code]() - - - - diff --git a/real_final/src/kernel/ket/__init__.py b/real_final/src/kernel/ket/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/real_final/src/kernel/ket/entanglement.py b/real_final/src/kernel/ket/entanglement.py deleted file mode 100644 index e69de29..0000000 diff --git a/real_final/src/kernel/ket/qubit.py b/real_final/src/kernel/ket/qubit.py deleted file mode 100644 index 7418d52..0000000 --- a/real_final/src/kernel/ket/qubit.py +++ /dev/null @@ -1,65 +0,0 @@ -from ...QCIS.instr import QCIS_instr, QCISOpCode -from ..gate import Gate -from ..gates_lib import lib_gate -from ..ket.state import State -from ..qubit import Qsim -from ..utils import find_main -from random import random -from sympy import Matrix - - -class Qsim_ket(Qsim): - def __init__(self, n, name): - super().__init__(n) - self.ket_state = State(name) - f = 1 - for ten in self.ket_state.tensor: - f *= ten.state.transpose() * ten.ket - self.state = f - - def apply_instr(self, instr: QCIS_instr): - if instr.op_code.is_single_qubit_op(): - gate = Gate(lib_gate(instr)) - tensor, qubit = self.ket_state.get_pos(instr.qubit) - self.state = self.ket_state.tensor[tensor].state - self.qubits_num = self.ket_state.tensor[tensor].size - self.ket_state.tensor[tensor].state = self.apply_gate(gate, [qubit]) - elif instr.op_code.is_two_qubit_op(): - if instr.op_code == QCISOpCode.CNOT or instr.op_code == QCISOpCode.CZ: - gate = Gate(lib_gate(instr), 1) - tensor, qubit, ctrl = self.ket_state.merge(instr.target_qubit, instr.control_qubit) - self.state = self.ket_state.tensor[tensor].state - self.qubits_num = self.ket_state.tensor[tensor].size - self.ket_state.tensor[tensor].state = self.apply_gate(gate, [ctrl, qubit]) - else: - gate = Gate(lib_gate(instr)) - tensor, qubit, fake_ctrl = self.ket_state.merge(instr.target_qubit, instr.control_qubit) - self.state = self.ket_state.tensor[tensor].state - self.qubits_num = self.ket_state.tensor[tensor].size - self.ket_state.tensor[tensor].state = self.apply_gate(gate, [qubit, fake_ctrl]) - elif instr.op_code.is_measure_op(): - gate = Gate(lib_gate(instr)) - qubit_list = [self.ket_state.get_pos(qubit) for qubit in instr.qubits_list] - for (tensor, state), qubit in zip(qubit_list, instr.qubits_list): - - self.state = self.ket_state.tensor[tensor].state - self.qubits_num = self.ket_state.tensor[tensor].size - tmp = self.state - for a, b in self.ket_state.symbols: - tmp = tmp.subs(a, 1) - tmp = tmp.subs(b, 0) - p0, p1 = find_main(tmp, state) - k = random() - - if k < p0 / (p0 + p1): - print("0") - self.ket_state.tensor[tensor].state = self.apply_gate(Gate(Matrix([[1, 0], [0, 0]])), [state]) - self.ket_state.measure(tensor, state, qubit, 0) - else: - print("1") - self.ket_state.tensor[tensor].state = self.apply_gate(Gate(Matrix([[0, 0], [0, 1]])), [state]) - self.ket_state.measure(tensor, state, qubit, 1) - - self.state = self.ket_state - - return gate diff --git a/real_final/src/kernel/ket/state.py b/real_final/src/kernel/ket/state.py deleted file mode 100644 index b50b19f..0000000 --- a/real_final/src/kernel/ket/state.py +++ /dev/null @@ -1,120 +0,0 @@ -from sympy import Matrix, symbols, pprint - -from ..utils import kron, make_ket - - -class Qutensor: - def __init__(self, qubit, vec): - self.size = 1 - self.state = vec - self.map = {qubit: 0} - self.ket = Matrix([symbols("\\ket{0_{%s}}" % qubit), symbols("\\ket{1_{%s}}" % qubit)]) - self.pre = sum([i * i for i in self.state]) - self.now = sum([i * i for i in self.state]) - - def insert_tensor(self, tensor): - self.state = kron(self.state, tensor.state) - for key in tensor.map.keys(): - tensor.map[key] += self.size - self.size += tensor.size - self.map.update(tensor.map) - self.update_ket() - self.pre = sum([i * i for i in self.state]) - self.now = sum([i * i for i in self.state]) - - def insert_qubit(self, qubit, vec): - self.map[qubit] = self.size - self.size += 1 - self.state = kron(self.state, vec) - - def clear_zero(self, state, qubit, height): - s = [] - for i in range(len(self.state)): - if ((i >> state) & 0x1) == height: - s.append(self.state[i]) - self.state = Matrix(s) - pre = self.now - now = sum([i * i for i in self.state]) - if self.size == 1: - self.ket = self.ket[height] - return pre, now, False - self.size -= 1 - - for key in self.map.keys(): - if self.map[key] > self.map[qubit]: - self.map[key] -= 1 - del self.map[qubit] - self.update_ket() - return pre, now, True - - def update_ket(self): - l = list(self.map.keys()) - x = make_ket(l) - self.ket = Matrix([symbols("\\ket{%s}" % s) for s in x]) - - -class State: - def __init__(self, names): - self.tensor = [Qutensor(qubit, Matrix([symbols("\\alpha_{%s}" % qubit), symbols("\\beta_{%s}" % qubit)])) - for qubit in names] - self.symbols = [(symbols("\\alpha_{%s}" % Q), symbols("\\beta_{%s}" % Q)) for Q in names] - self.size = len(names) - self.map = dict([(qubit, i) for qubit, i in zip(names, range(self.size))]) - self.empty = set() - - def merge(self, qubit1, qubit2): - tensor1, state1 = self.get_pos(qubit1) - tensor2, state2 = self.get_pos(qubit2) - - if tensor1 == tensor2: - return tensor1, state1, state2 - - if qubit1 < qubit2: - for key in self.tensor[tensor2].map.keys(): - self.map[key] = tensor1 - - self.tensor[tensor1].insert_tensor(self.tensor[tensor2]) - self.tensor[tensor2] = None - self.empty.add(tensor2) - self.size -= 1 - - return tensor1, self.tensor[tensor1].map[qubit1], self.tensor[tensor1].map[qubit2] - else: - for key in self.tensor[tensor1].map.keys(): - self.map[key] = tensor2 - self.tensor[tensor2].insert_tensor(self.tensor[tensor1]) - self.tensor[tensor1] = None - self.empty.add(tensor1) - self.size -= 1 - - return tensor2, self.tensor[tensor2].map[qubit1], self.tensor[tensor2].map[qubit2] - - def measure(self, tensor, state, qubit, height): - pre, now, flag = self.tensor[tensor].clear_zero(state, qubit, height) - if not flag: - self.tensor[tensor].pre = pre - self.tensor[tensor].now = now - return - index = self.empty.pop() - if height: - self.tensor[index] = Qutensor(qubit, Matrix([0, 1])) - else: - self.tensor[index] = Qutensor(qubit, Matrix([1, 0])) - - self.tensor[tensor].pre = now - self.tensor[tensor].now = now - - self.tensor[index].pre = pre - self.tensor[index].now = now - self.map[qubit] = index - - def split(self, qubit1, qubit2): - pass - - def judge(self, qubit1, qubit2): - pass - - def get_pos(self, qubit): - tensor = self.map[qubit] - state = self.tensor[tensor].map[qubit] - return tensor, state diff --git a/real_final/src/kernel/ket/store.py b/real_final/src/kernel/ket/store.py deleted file mode 100644 index 3e844f9..0000000 --- a/real_final/src/kernel/ket/store.py +++ /dev/null @@ -1,50 +0,0 @@ -from sympy import latex, sqrt, factor, simplify, pprint, cancel - -from QCIS.instr import QCIS_instr, QCISOpCode -from kernel.gate import Gate -from kernel.ket.qubit import Qsim_ket -from kernel.ket.state import State -from output.store import store -from output.symbol_map import symbol_map - - -class store_ket(store): - def __init__(self, init: Qsim_ket, mapping: symbol_map, output_list): - super().__init__(init, mapping, output_list) - self.init_state = init.state - - def save_instr(self, state: State, instr: QCIS_instr, gate: Gate): - ins_str = str(instr.op_code).removeprefix("QCISOpCode.") - if instr.op_code.is_single_qubit_op(): - ins_str += '\t' + str(instr.qubit) - elif instr.op_code.is_two_qubit_op(): - if instr.op_code == QCISOpCode.CNOT or instr.op_code == QCISOpCode.CZ: - ins_str += '\t' + str(instr.control_qubit) + '\t' + str(instr.target_qubit) - else: - ins_str += '\t' + str(instr.control_qubit) + '\t' + str(instr.target_qubit) - elif instr.op_code.is_measure_op(): - tmp = '\t' - ins_str += '\t' + tmp.join([str(qubit) for qubit in instr.qubits_list]) - - self.instr_save.append(ins_str) - - f = 1 - A = 1 - for tensor in state.tensor: - if tensor: - f *= (tensor.state.transpose() * tensor.ket) - A *= factor(tensor.pre) / factor(tensor.now) - self.state_save.append(latex((f[0] * sqrt(factor(A))))) - self.gate_save.append(latex(gate.matrix)) - - def save_final(self, state: State): - f = 1 - A = 1 - for tensor in state.tensor: - if tensor: - f *= (tensor.state.transpose() * tensor.ket) - A *= factor(tensor.pre) / factor(tensor.now) - self.final_state = latex(f[0] * sqrt(factor(A))) - - def write_init(self): - return self.init_state[0] diff --git a/real_final/src/kernel/qubit.py b/real_final/src/kernel/qubit.py deleted file mode 100644 index 9b0149a..0000000 --- a/real_final/src/kernel/qubit.py +++ /dev/null @@ -1,88 +0,0 @@ -from .utils import * -import sympy -from .gate import Gate, ParametersGate -from ..QCIS.instr import QCIS_instr, QCISOpCode -from .gates_lib import lib_gate - - -class Qsim: - def __init__(self, n): - self.state = None - self.qubits_num = n - - self.global_circuit = None - - def apply(self): - pass - - def apply_gate(self, gate: Gate, target_qubits: list, parameters=None, extra_optional_control_qubits=None) \ - -> sympy.Matrix: - - if extra_optional_control_qubits is None: - extra_optional_control_qubits = [] - if parameters is None: - parameters = [] - - qubit_map = target_qubits[gate.ctrl_num:] - ctrl_map = target_qubits[0: gate.ctrl_num] + extra_optional_control_qubits - - if isinstance(gate, ParametersGate): - G = gate.get_matrix(get_discrete(qubit_map), parameters=parameters) - else: - G = gate.get_matrix(get_discrete(qubit_map)) - # 合并俩操作 - qubit_map.sort() - - marki = get_mark(qubit_map, 0) - mark = get_mark(qubit_map, self.qubits_num) - - ctrl_mark = get_mark(ctrl_map, 0) - - addr = gen_subset(mark) - addri = sorted(gen_subset(marki)) - - for s in addr: - if ctrl_mark == 0 or s & ctrl_mark: - addrs = [(s | i) for i in addri] - x = sympy.Matrix([self.state[i] for i in addrs]) - x = G * x - for i, j in zip(addrs, x): - self.state[i] = j - return self.state - - -class Qsim_state(Qsim): - def __init__(self, n, name): - super().__init__(n) - self.state = sympy.Matrix(sympy.symbols('a:' + "%d" % (1 << n))) - - self.map = {} - self.in_use = 0 - for qubit in name: - self.map[qubit] = self.in_use - self.in_use += 1 - - def apply_instr(self, instr: QCIS_instr): - if instr.op_code.is_single_qubit_op(): - gate = Gate(lib_gate(instr)) - qubit = self.map[instr.qubit] - self.apply_gate(gate, [qubit]) - elif instr.op_code.is_two_qubit_op(): - if instr.op_code == QCISOpCode.CNOT or instr.op_code == QCISOpCode.CZ: - gate = Gate(lib_gate(instr), 1) - qubit = self.map[instr.target_qubit] - ctrl = self.map[instr.control_qubit] - self.apply_gate(gate, [ctrl, qubit]) - else: - gate = Gate(lib_gate(instr)) - qubit = self.map[instr.target_qubit] - fake_ctrl = self.map[instr.control_qubit] - self.apply_gate(gate, [qubit, fake_ctrl]) - elif instr.op_code.is_measure_op(): - gate = Gate(lib_gate(instr)) - qubit_list = [self.map[qubit] for qubit in instr.qubits_list] - for qubit in qubit_list: - self.apply_gate(gate, [qubit]) - - - return gate diff --git a/real_final/src/kernel/utils.py b/real_final/src/kernel/utils.py deleted file mode 100644 index b91b3a6..0000000 --- a/real_final/src/kernel/utils.py +++ /dev/null @@ -1,78 +0,0 @@ -from sympy import Matrix -from math import log2, ceil - - -def find_main(state, qubit): - p0 = 0 - p1 = 0 - for i in range(len(state)): - num = state[i] - if (i >> qubit) & 0x1: - p1 += num * num - else: - p0 += num * num - return p0, p1 - - -def kron(A, B): - """Return the Kronecker product of matrix A and matrix B""" - return Matrix( - [[A.row(i // B.rows)[j // B.cols] * B.row(i % B.rows)[j % B.cols] - for j in range(A.cols * B.cols)] - for i in range(A.rows * B.rows)] - ) - - -def gen_subset(s): - res = [] - now = s - while now: - res.append(now) - now = (now - 1) & s - res.append(now) - return res - - -def map_bit(x, s, mapp): - for i in range(len(mapp)): - s |= ((x >> i) & 1) << mapp[i] - return s - - -def get_mark(num, l): - """ - - """ - mark = 0 - for i in num: - mark |= 1 << i - if l != 0: - mark = (~mark) & ((1 << l) - 1) - return mark - - -def get_discrete(x): - rx = sorted([(i, j) for i, j in zip(x, range(len(x)))]) - res = [0] * len(x) - for i in range(len(rx)): - res[rx[i][1]] = i - return res - - -def str_bin(x, n): - s = bin(x)[2:] - return reversed("0" * (n - len(s)) + s) - - -def make_bin(x, n, keys): - s = str_bin(x, n) - return "".join(["%s_{%s}" % (i, j) for i, j in zip(s, keys)]) - - -def make_ket(keys): - n = len(keys) - return [make_bin(i, n, keys) for i in range(1 << n)] - - - - diff --git a/real_final/src/output/__init__.py b/real_final/src/output/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/real_final/src/output/store.py b/real_final/src/output/store.py deleted file mode 100644 index 99cfc26..0000000 --- a/real_final/src/output/store.py +++ /dev/null @@ -1,59 +0,0 @@ -from sympy import Matrix, latex -from kernel.gate import Gate -from QCIS.instr import QCIS_instr, QCISOpCode -from output.symbol_map import symbol_map - - -class store: - def __init__(self, init, mapping: symbol_map, output_list): - self.instr_save = [] - self.state_save = [] - self.circuit_save = [] - self.gate_save = [] - self.init_state = init.state.copy() - self.final_state = None - self.symbol_map = mapping - self.out_list = output_list - - def save_final(self, state): - self.final_state = latex(state.transpose()) - - def save_instr(self, state: Matrix, instr: QCIS_instr, gate: Gate): - ins_str = str(instr.op_code).removeprefix("QCISOpCode.") - if instr.op_code.is_single_qubit_op(): - ins_str += '\t' + str(instr.qubit) - elif instr.op_code.is_two_qubit_op(): - if instr.op_code == QCISOpCode.CNOT or instr.op_code == QCISOpCode.CZ: - ins_str += '\t' + str(instr.control_qubit) + '\t' + str(instr.target_qubit) - else: - ins_str += '\t' + str(instr.control_qubit) + '\t' + str(instr.target_qubit) - elif instr.op_code.is_measure_op(): - tmp = '\t' - ins_str += '\t' + tmp.join([str(qubit) for qubit in instr.qubits_list]) - - self.instr_save.append(ins_str) - self.state_save.append(latex(state.transpose())) - self.gate_save.append(latex(gate.matrix)) - - def write_init(self): - return self.init_state.transpose() - - def output_markdown(self, qcis_name="test.qcis", name='a.md'): - file = open(name, 'w') - file.write("# The ans of %s\n\n" % qcis_name) - file.write("**Init state** is: \n$$\n%s\n$$\n\n" % latex(self.write_init())) - for i in range(len(self.instr_save)): - file.write("```assembly\n%d. %s\n```\n\n" % (self.out_list[i], self.instr_save[i])) - file.write("$$\n%s\n$$\n" % self.gate_save[i]) - file.write("$$\n%s\n$$\n" % self.state_save[i]) - - file.write("**Final state** is: \n$$\n%s\n$$\n\n" % self.final_state) - - if self.symbol_map.use: - file.write("**symbols** is:\n\n") - for x, y in self.symbol_map.symbol_table.items(): - file.write("$%s$ : %f\t\t" % (latex(x), y)) - file.close() - - - diff --git a/real_final/src/output/symbol_map.py b/real_final/src/output/symbol_map.py deleted file mode 100644 index e1dd098..0000000 --- a/real_final/src/output/symbol_map.py +++ /dev/null @@ -1,25 +0,0 @@ -from sympy import symbols - - -class symbol_map: - def __init__(self): - self.symbol_table = {} - self.theta = 0 - self.phi = 0 - self.use = False - - def store_symbol(self, type, val) -> symbols: - self.use = True - if type == 'theta': - symbol = symbols('theta' + str(self.theta)) - self.theta += 1 - self.symbol_table[symbol] = val - return symbol - elif type == 'phi': - symbol = symbols('phi' + str(self.phi)) - self.phi += 1 - self.symbol_table[symbol] = val - return symbol - - def get_symbol(self, symbol: symbols): - return self.symbol_table[symbol] -- Gitee