diff --git a/config/.gitignore b/config/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ffc1da3f3eab889b6702e8536d9d600c76cb511f --- /dev/null +++ b/config/.gitignore @@ -0,0 +1 @@ +*.tokens \ No newline at end of file diff --git a/config/README.md b/config/README.md new file mode 100644 index 0000000000000000000000000000000000000000..54973958f92505491f6b5cac7958fbcb879b7c4b --- /dev/null +++ b/config/README.md @@ -0,0 +1,8 @@ +请在此文件下保存在对接各云平台时使用的token,这些token可用于测试。此文件夹中`*.tokens`文件不会被git同步。 + +云平台与文件名的对应关系如下: + +| 云平台 | token文件名 | +|---|---| +| 中电信天衍量子云平台 | `tianyan.tokens` | +| 国盾量子云平台 | `quantumctek.tokens` | diff --git a/examples/xiaohong/host.py b/examples/xiaohong/host.py index ff22041c98d20645000764fd108eed5eea26bea5..d14c2e02b9617101d79d048c817181ae1d0755cd 100644 --- a/examples/xiaohong/host.py +++ b/examples/xiaohong/host.py @@ -1,6 +1,6 @@ -from quingo import * from pathlib import Path +from quingo import * qu_file = Path(__file__).parent / "kernel.qu" @@ -10,8 +10,8 @@ def routine(circ_name, num_shots=1): cfg = ExeConfig( ExeMode.RealMachine, num_shots, - xh_login_key="7e6999bab11453428b8ded1fac00b3ea", - xh_machine_name="Transpose", + qcloud_platform_login_key="7e6999bab11453428b8ded1fac00b3ea", + qcloud_machine_name="Transpose", ) qasm_fn = compile(task, params=(), config_file="", target="qcloud_sh") res = execute(qasm_fn, BackendType.XIAOHONG, cfg) diff --git a/setup.py b/setup.py index edb2f7d7663fee840f37811967afc918334ae1db..ae980f90a7c7db8b8c4336f05a3e3c868afb1a84 100755 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ with open("README.md", "r", encoding="utf-8") as fh: setup( name="quingo", - version="0.3.4", + version="0.3.5", author="Xiang Fu", author_email="gtaifu@gmail.com", description="Quingo Runtime System", diff --git a/src/quingo/backend/backend_hub.py b/src/quingo/backend/backend_hub.py index d1fb3751ef744e5a99ce669d584a51a35df8b04e..87fe27fccca7a406694837c3a5e865ab75c5460b 100755 --- a/src/quingo/backend/backend_hub.py +++ b/src/quingo/backend/backend_hub.py @@ -10,6 +10,7 @@ class BackendType(enum.Enum): SYMQC = enum.auto() QUANTIFY = enum.auto() XIAOHONG = enum.auto() + TIANYAN = enum.auto() QUALESIM_TEQUILA = enum.auto() QUALESIM_QUANTUMSIM = enum.auto() QOS = enum.auto() @@ -49,6 +50,12 @@ class Backend_hub: False, Qisa.QCIS, ), + BackendType.TIANYAN: ( + "ZDXLZ_Tianyan", + "tianyan", + False, + Qisa.QCIS, + ), BackendType.QUALESIM_TEQUILA: ( "QuaLeSim_tequila", "qualesim", diff --git a/src/quingo/backend/tianyan.py b/src/quingo/backend/tianyan.py new file mode 100644 index 0000000000000000000000000000000000000000..e97bfe12ad5f55cdbab279fc5fcde77f7b761a7c --- /dev/null +++ b/src/quingo/backend/tianyan.py @@ -0,0 +1,112 @@ +from datetime import datetime + +from cqlib import TianYanPlatform + +from quingo.core.exe_config import ExeConfig, ExeMode +from quingo.utils import ensure_path + +from .backend_hub import BackendType +from .if_backend import If_backend + + +class ZDXLZ_Tianyan(If_backend): + def __init__(self): + super().__init__(BackendType.TIANYAN) + self.ty_platform = None + self.qcis_circuit = None + + def upload_program(self, prog_fn): + """ + Upload assembly or binary program to the simulator. + + Args: + prog_fn: the name of the assembly or binary file. + """ + prog_fn = ensure_path(prog_fn) + lines = [] + with prog_fn.open("r") as f: + lines = f.readlines() + + if len(lines) == 0: + raise ValueError("The program file is empty.") + + trimed_lines = [] + for line in lines: + trimed_lines.append(" ".join(line.split())) + + self.qcis_circuit = "\n".join( + [ + line.strip() + for line in trimed_lines + if line.strip() and not line.startswith("#") + ] + ) + # self.qcis_circuit = prog_fn.open("r").read() + + def upload_program_str(self, program: str): + """upload the program string to the simulator.""" + self.qcis_circuit = program + + def execute(self, exe_config: ExeConfig): + """Execute the given quantum circuit. + Args: + - mode (str): the simulation mode to use: + - "one_shot": the simulation result is a dictionary with each key being a qubit + measured, and the value is the outcome of measuring this qubit. + - num_shots (int): the number of iterations performed in `one_shot` mode. + - xh_login_key (str): login key to connect XiaoHong + - xh_machine_name (str): name of machine name to execute qcis + """ + if not exe_config.mode == ExeMode.RealMachine: + raise ValueError( + f"Unsupported execution mode ({exe_config.mode}) for Tianyan." + ) + + # connect Tianyan + self.configure_platform( + exe_config.qcloud_platform_login_key, exe_config.qcloud_machine_name + ) + + # submit job + print(f"\n===================== Start execute: ===================== ") + + print("circuit:\n", self.qcis_circuit, sep="") + print( + "type of circuit:", + type(self.qcis_circuit), + " length:", + len(self.qcis_circuit), + ) + print("machine name:", exe_config.qcloud_machine_name) + print(f"num shots = {exe_config.num_shots}") + + print("") + + query_id = self.ty_platform.submit_job( + circuit=self.qcis_circuit, + exp_name=f'quingo_exp.{datetime.now().strftime("%Y%m%d%H%M%S")}', + num_shots=exe_config.num_shots, + ) + + # invalid query + if not query_id: + raise EnvironmentError("Fail to connect Tianyan!") + + # read result + result = self.ty_platform.query_experiment( + query_id=query_id, max_wait_time=3600, sleep_time=5 + ) + result = self.format_result(result) + return result + + def configure_platform(self, login_key, machine_name): + self.ty_platform = TianYanPlatform(login_key=login_key) + print(f"Set account successfully:") + print(f" login key = {login_key[0:5]}" + "*" * (len(login_key) - 5)) + self.ty_platform.set_machine(machine_name) + print(f" machine name = {machine_name}") + + def format_result(self, result): + print("result:", result) + # origin_result = result[0]["results"] + # return {"qubits": origin_result[0], "results": origin_result[1:]} diff --git a/src/quingo/backend/xiaohong.py b/src/quingo/backend/xiaohong.py index b0a4cf11d01dfa978dd5e8a4d436a181cbdc2533..33dd627f065fad2e69bcdf4e476021024f6a1ce2 100644 --- a/src/quingo/backend/xiaohong.py +++ b/src/quingo/backend/xiaohong.py @@ -1,8 +1,9 @@ +from quingo.core.exe_config import ExeConfig, ExeMode +from quingo.lib.pyezQ import Account from quingo.utils import ensure_path + from .backend_hub import BackendType from .if_backend import If_backend -from quingo.core.exe_config import ExeConfig, ExeMode -from quingo.lib.pyezQ import Account class XiaoHong(If_backend): @@ -41,7 +42,9 @@ class XiaoHong(If_backend): ) # connect XiaoHong - self.set_account(exe_config.xh_login_key, exe_config.xh_machine_name) + self.set_account( + exe_config.qcloud_platform_login_key, exe_config.qcloud_machine_name + ) # submit job print(f"Start execute:") diff --git a/src/quingo/core/compile.py b/src/quingo/core/compile.py index b49bff7fd2125f38b9665653a2b07607257f13a1..d194c7c502966a66543e95f5c289502b1a17f7e5 100644 --- a/src/quingo/core/compile.py +++ b/src/quingo/core/compile.py @@ -103,6 +103,7 @@ def compose_cl_cmd( cmd_eles = [ cl_path, + "-u", cl_entry_fn, opt_inc_dirs, config_fn, @@ -114,6 +115,7 @@ def compose_cl_cmd( opt_out_fn, ] + compile_cmd = " ".join([ele for ele in cmd_eles if ele.strip() != ""]) return compile_cmd diff --git a/src/quingo/core/exe_config.py b/src/quingo/core/exe_config.py index 56c4e2d074293427d9b7dc97f9d6d5844bda259c..e31477d28c5085c85d26989369e0d64c83a1a6d8 100644 --- a/src/quingo/core/exe_config.py +++ b/src/quingo/core/exe_config.py @@ -25,15 +25,15 @@ class ExeConfig: self, mode: ExeMode = ExeMode.SimShots, num_shots: int = 1, - xh_login_key: str = None, # use for connecting XIAOHONG - xh_machine_name: str = None, # use for connecting XIAOHONG + qcloud_platform_login_key: str = None, # use for connecting XIAOHONG + qcloud_machine_name: str = None, # use for connecting XIAOHONG qos_circuit_times: int = 100, # use for connecting QOS noise_config=None, ): self.mode = mode self.num_shots = num_shots - self.xh_login_key = xh_login_key - self.xh_machine_name = xh_machine_name + self.qcloud_platform_login_key = qcloud_platform_login_key + self.qcloud_machine_name = qcloud_machine_name self.qos_circuit_times = qos_circuit_times self.noise_config = noise_config diff --git a/src/quingo/global_config.py b/src/quingo/global_config.py index af5db04ce7a81df5c4ecdca42e1f606936757da9..a535d34752f5356d06ad2aa4b85a4c7b9ae749a8 100755 --- a/src/quingo/global_config.py +++ b/src/quingo/global_config.py @@ -1,6 +1,8 @@ from pathlib import Path -qgrtsys_root_dir = Path(__file__).absolute().parent +qgrtsys_root_dir = Path(__file__).absolute().parent # corresponds to `/src/quingo` +qgrtsys_repo_dir = qgrtsys_root_dir.parent.parent # corresponds to `` + mlir_compiler_config_path = qgrtsys_root_dir / "core" / "mlir_compiler_path.txt" default_mlir_compiler_path = Path.home() / ".quingo" / "quingoc" diff --git a/unittest/backends/test_backends.py b/unittest/backends/test_backends.py index 522729bfa8bed9d20924ef25e8b44dcb92dd49db..2fe6ce1d7f13dbe0a79777c72cc406cf20151fc0 100644 --- a/unittest/backends/test_backends.py +++ b/unittest/backends/test_backends.py @@ -1,14 +1,15 @@ -from quingo.backend.pyqcisim_tequila import PyQCISim_tequila +import threading +from pathlib import Path + +from quingo.backend.backend_hub import Backend_hub, BackendType from quingo.backend.pyqcisim_quantumsim import PyQCISim_quantumsim +from quingo.backend.pyqcisim_tequila import PyQCISim_tequila +from quingo.backend.qisa import Qisa from quingo.backend.qualesim import QuaLeSim_quantumsim, QuaLeSim_tequila from quingo.backend.symqc import IfSymQC -from quingo.backend.backend_hub import BackendType, Backend_hub -from quingo.backend.qisa import Qisa +from quingo.backend.tianyan import ZDXLZ_Tianyan from quingo.core.exe_config import * -import threading from quingo.utils import number_distance -from pathlib import Path - unittest_dir = Path(__file__).parent / ".." qcis_fn = unittest_dir / "test_qcis" / "bell.qcis" @@ -33,6 +34,7 @@ class Test_backends: single(PyQCISim_tequila, BackendType.TEQUILA, Qisa.QCIS, True) single(PyQCISim_quantumsim, BackendType.QUANTUM_SIM, Qisa.QCIS, True) single(IfSymQC, BackendType.SYMQC, Qisa.QCIS, True) + single(ZDXLZ_Tianyan, BackendType.TIANYAN, Qisa.QCIS, False) def test_upload_program(self): def single(BackendClass, qasm_fn): @@ -49,6 +51,7 @@ class Test_backends: single(PyQCISim_tequila, qcis_fn) single(PyQCISim_quantumsim, qcis_fn) single(IfSymQC, qcis_fn) + single(ZDXLZ_Tianyan, qcis_fn) def test_upload_program_str(self): def single(BackendClass, qasm): @@ -62,6 +65,7 @@ class Test_backends: single(PyQCISim_tequila, qasm_str) single(PyQCISim_quantumsim, qasm_str) single(IfSymQC, qasm_str) + single(ZDXLZ_Tianyan, qcis_fn) def test_get_from_hub(self): def single(backend_type, simulator_class): @@ -74,6 +78,7 @@ class Test_backends: single(BackendType.QUALESIM_QUANTUMSIM, QuaLeSim_quantumsim) single(BackendType.QUALESIM_TEQUILA, QuaLeSim_tequila) single(BackendType.SYMQC, IfSymQC) + single(BackendType.TIANYAN, ZDXLZ_Tianyan) if __name__ == "__main__": diff --git a/unittest/backends/test_tianyan.py b/unittest/backends/test_tianyan.py new file mode 100644 index 0000000000000000000000000000000000000000..7edf4a14199f4bd804f170590bcc289b2d97d01b --- /dev/null +++ b/unittest/backends/test_tianyan.py @@ -0,0 +1,36 @@ +from pathlib import Path + +from quingo.backend.backend_hub import BackendType +from quingo.backend.qisa import Qisa +from quingo.backend.tianyan import ZDXLZ_Tianyan +from quingo.core.exe_config import * +from quingo.global_config import qgrtsys_repo_dir + +cur_dir = Path(__file__).parent +qcis_fn = qgrtsys_repo_dir / "unittest" / "test_qcis" / "bell_cz.qcis" +token_fn = qgrtsys_repo_dir / "config" / "tianyan.tokens" + + +def test_execute(): + platform = ZDXLZ_Tianyan() + platform.upload_program(qcis_fn) + exe_config = ExeConfig( + mode=ExeMode.RealMachine, + num_shots=10, + qcloud_platform_login_key=token_fn.read_text().strip(), + qcloud_machine_name="tianyan_sw", + ) + results = platform.execute(exe_config) + # assert isinstance(results, list) + # res = results[0] + # assert "resultStatus" in list(res.keys()) + # assert "probability" in list(res.keys()) + # assert ( + # len(res["probability"]) == 2 + # and "00" in res["probability"] + # and "11" in res["probability"] + # ) + + +if __name__ == "__main__": + test_execute() diff --git a/unittest/test_compile_cmd.py b/unittest/test_compile_cmd.py index 9b27dc34baddda5b7924279a34c1baa10f01130b..398ac889b491ec7179460f926071d5d555d79e04 100644 --- a/unittest/test_compile_cmd.py +++ b/unittest/test_compile_cmd.py @@ -25,13 +25,14 @@ class TestCompileCmd: mlir_path = Path(get_mlir_path()) cmd = compose_cl_cmd(task, qasm_fn, mlir_path) cmd_eles = cmd.split() - assert len(cmd_eles) == 12 + assert len(cmd_eles) == 13 assert mlir_path.resolve().samefile(cmd_eles[0].strip('"')) - assert cmd_eles[1] == '"{}"'.format(task.cl_entry_fn.resolve()) - assert cmd_eles[2] == "-I" - assert cmd_eles[4] == "-I" - assert cmd_eles[9] == "--isa=qcis" - assert cmd_eles[10] == "-o" + assert cmd_eles[1] == '-u' + assert cmd_eles[2] == '"{}"'.format(task.cl_entry_fn.resolve()) + assert cmd_eles[3] == "-I" + assert cmd_eles[5] == "-I" + assert cmd_eles[10] == "--isa=qcis" + assert cmd_eles[11] == "-o" # assert Path(qasm_fn).samefile(cmd_eles[8].strip('"')) def test_compile(self): diff --git a/unittest/test_qcis/bell_cz.qcis b/unittest/test_qcis/bell_cz.qcis new file mode 100644 index 0000000000000000000000000000000000000000..6bb88f7b37664e8bc0fd92c082e29a0c2c56c2bf --- /dev/null +++ b/unittest/test_qcis/bell_cz.qcis @@ -0,0 +1,6 @@ + H Q14 + H Q15 + CZ Q14 Q15 + H Q15 + M Q14 + M Q15 \ No newline at end of file