diff --git a/README.md b/README.md index 1a0ceb07f7ae59b136685d89c4a896094481c2d2..46b2df661801ebf0b3a34fcca49c7d489655c778 100755 --- a/README.md +++ b/README.md @@ -14,19 +14,12 @@ pip install -e . ```sh # for simulators used: +# The Tequila backend is not yet open source and needs to be installed separately. git clone https://gitee.com/hpcl_quanta/tequila.git -git checkout xbackend -pip install -e . - -git clone https://gitee.com/quingo/pyqcisim.git -git checkout bug-fix -pip install -e . - -git clone https://gitee.com/quingo/SymQC.git pip install -e . ``` -Upon success, it will automatically install the Quingo runtime system (this package), the PyQCAS simulator and the PyQCISim simulator. +Upon success, it will automatically install the Quingo runtime system (this package), the SymQC simulator, the PyQCISim simulator and the QuaLeSim simulator. ### Install the Quingo compiler @@ -61,22 +54,24 @@ For different simulation backend, please refer to `src/examples/sim_backend`, wh For different simulation modes, please refer to `src/examples/sim_exemode`, which displays the output of two different simulation results currently available. ## APIs of the Quingo runtime system -The `Quingo_interface` class expose the following methods: - - `set_log_level()`: `` can be one of `DEBUG`, `INFO`, `WARNING`, `ERROR`, or `CRITICAL`. - - `connect_backend()`: `` currently can be `'pyqcas_quantumsim'` or `'pyqcisim_quantumsim'`. -- `get_backend_name()`: return the name of the backend that is being used. An empty string will be returned if no backend has been set. -- `get_last_qasm()`: get the qasm code generated by the last execution. -- `config_execution(, )`: - - Configure the execution mode to `'one_shot'` or `'state_vector'`. - - When the execution mode is `'one_shot'`, the number of times to run the uploaded quantum circuit can be configured using the parameter `num_shots` at the same time. -- `call_quingo(, , *args)`: - - the main entry to call Quingo operation. - - `` : the name of the Qingo file which contains the quantum function called by the host program. - - `` : the name of the quantum function - - ``: a variable length of parameters used to call the Quingo operation in the form `qg_func_name()`. - - `read_result()`: read the computation result from the quantum kernel. - - For eQASM-based backend, the result is a binary block which encodes the quantum computation result. - - For QCIS-based backend, the result format is defined by PyQCISim. Please refer to the docstring of `quingo.if_backend.non_arch_backend.pyqcisim_quantumsim.PyQCISim_quantumsim::execute()` +1. `class Quingo_task`: + - 输入: + - `called_qu_fn`: `Path`,qu文件路径。 + - `called_func`: `str`,调用 quingo 函数名。 + - `debug_mode`(optional): `True` or `False`。 + - `qisa`(optional): 前端指令集类型。 + - `backend`(optional): 后端模拟器类型。 +2. `function compile()`: + - 输入: + - `Quingo_task`: 待编译 qu 任务 + - `params`: `Quingo_task` 中调用函数 `called_func` 所需参数 + - 输出:`qasm_fn`:输出对应指令集文件(.qcis / .qi) +3. `function execute()`: + - 输入: + - `qasm_fn`: `Path`,对应指令集文件(.qcis / .qi) + - `be_type`: `BackendType`,模拟器后端类型 + - `exe_config`: 执行模式,`ExeMode.SimShots`、`ExeMode.SimFinalResult`、`ExeMode.SimStateVector` + - 输出:`sim_result`:具体输出格式详见`src/quingo/backend/quingo_result_format_spec.md` ## Quingo programming tutorial At present, Qingguo runtime system has included sample programs such as `Bell_state`, `GHZ`, `VQE`, etc. Details can be found [here](https://gitee.com/quingo/quingo-runtime/tree/master/src/examples). \ No newline at end of file diff --git a/README_ZH.md b/README_ZH.md index 5e92c7b9df5c121e35a179dda1c549f96e36d0bc..d7f2367547f1cf40b54f1031dccf47f2c907d962 100755 --- a/README_ZH.md +++ b/README_ZH.md @@ -8,22 +8,15 @@ ### 安装运行时系统以及模拟器 -依次执行以下命令便可以安装青果运行时系统、PyQCAS模拟器以及PyQCISim模拟器。 +依次执行以下命令便可以安装青果运行时系统、`SymQC` 模拟器、`PyQCISim` 模拟器以及 `QuaLeSim` 模拟器。 ```sh pip install -e . ``` ```sh # for simulators used: +# Tequila 后端尚未开源,需要单独安装。 git clone https://gitee.com/hpcl_quanta/tequila.git -git checkout xbackend -pip install -e . - -git clone https://gitee.com/quingo/pyqcisim.git -git checkout bug-fix -pip install -e . - -git clone https://gitee.com/quingo/SymQC.git pip install -e . ``` @@ -58,25 +51,27 @@ sim res: (['Q1', 'Q2'], [[0, 0], [0, 0], [1, 1], [1, 1], [0, 0], [0, 0], [0, 0] ``` 针对不同的模拟后端,详见`src/examples/sim_backend`,其中展示了目前稳定运行的SymQC、QuantumSim何Tequila后端的使用。 -针对不同的模拟模式,详见`src/examples/sim_exemode`,展示了对于目前的两种不同的模拟结果的输出。 +针对不同模式的输出格式,详见`src/quingo/backend/quingo_result_format_spec.md` ## 青果运行时系统提供的API -`Quingo_interface`类提供了以下方法: - - `set_log_level()`: 该方法中``的值可以是`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`中的任意一个。 - - `connect_backend()`: 该方法中``的值目前可以是`'pyqcas_quantumsim'`或者`'pyqcisim_quantumsim'`。 -- `get_backend_name()`方法返回正在使用的后端名称。如果没有设置后端,将返回一个空字符串。 -- `get_last_qasm()`用来获取上次执行生成的qasm指令代码。 -- `config_execution(, )`: - - `config_execution`能够将执行模式配置为`'one_shot'`或`'state_vector'`. - - 当执行模式为`'one_shot'`时,可以同时使用参数`num_shots`来配置量子线路的运行次数。 -- `call_quingo(, , *args)`: - - `call_quingo`方法是调用Quingo操作的主要入口。 - - ``中的值为青果文件的名称,该青果文件中包含被宿主程序调用的量子操作。 - - ``中的值为量子操作的名称。 - - ``中的值为可变长度的参数,这些参数用来以 `qg_func_name()` 形式来调用青果操作。 -- `read_result()`方法负责从量子内核中读取计算结果。 - - 对于能够执行eQASM指令的后端,结果是对量子计算结果进行编码的二进制块。 - - 对于能够执行QCIS指令的后端,结果的格式由PyQCISim进行定义。详情请参考`quingo.if_backend.non_arch_backend.pyqcisim_quantumsim.PyQCISim_quantumsim::execute()`中的文档描述。 +1. `Quingo_task`类: + - 输入: + - `called_qu_fn`: `Path`,qu文件路径。 + - `called_func`: `str`,调用 quingo 函数名。 + - `debug_mode`(optional): `True` or `False`。 + - `qisa`(optional): 前端指令集类型。 + - `backend`(optional): 后端模拟器类型。 +2. `compile`: + - 输入: + - `Quingo_task`: 待编译 qu 任务 + - `params`: `Quingo_task` 中调用函数 `called_func` 所需参数 + - 输出:`qasm_fn`:输出对应指令集文件(.qcis / .qi) +3. `execute`: + - 输入: + - `qasm_fn`: `Path`,对应指令集文件(.qcis / .qi) + - `be_type`: `BackendType`,模拟器后端类型 + - `exe_config`: 执行模式,`ExeMode.SimShots`、`ExeMode.SimFinalResult`、`ExeMode.SimStateVector` + - 输出:`sim_result`:具体输出格式详见`src/quingo/backend/quingo_result_format_spec.md` ## 青果示例程序 目前青果运行时系统中已经包含了`Bell_state`、`GHZ`、`VQE`等示例程序,详情可见[此处](https://gitee.com/quingo/quingo-runtime/tree/master/src/examples)。 \ No newline at end of file diff --git a/examples/adder/__init__.py b/examples/adder/__init__.py deleted file mode 100755 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/examples/adder/adder.py b/examples/adder/adder.py deleted file mode 100755 index b9072e916a336db4c53ff6f758b4a492ff3198fc..0000000000000000000000000000000000000000 --- a/examples/adder/adder.py +++ /dev/null @@ -1,97 +0,0 @@ -import logging -from quingo import * -import sys -from os.path import abspath, dirname -import termcolor as tc -import threading -from pathlib import Path -from my_utils import * - -sys.path.append(dirname(dirname(abspath(__file__)))) - - -def get_first_non_zero_res(sim_result, integer_format=True): - """This function is used to get the first non-zero result from the measurement results. - - sim_result format: (qubit_list, msmt res list). - An Example result of a simulation with num_shots=3: - ``` - (['Q3', 'Q4', 'Q5', 'Q6', 'Q7'], - [[1, 1, 0, 0, 0], - [1, 1, 0, 0, 0], - [1, 1, 0, 0, 0]]) - ``` - return: the first non-zero result (in integer format) in the measurement results. - """ - if sim_result is None: - raise ValueError("No measure results found") - _, msmt_res = sim_result - - if msmt_res is None: - raise ValueError("No measure results found") - - res = msmt_res[0] - res.reverse() - if integer_format: - return int("".join(map(str, res)), 2) - else: - return msmt_res[0] - - -logger = get_logger("adder_test") -logger.setLevel(logging.INFO) - -dir_path = Path(__file__).parent.resolve() -kernel_file = Path(__file__).parent / "draper_test.qu" -print("kernel_file: ", kernel_file.resolve()) - - -def trigger_task(func, args, multi_threading): - if multi_threading: - t = threading.Thread(target=func, args=args) - t.start() - else: - func(*args) - - -class Test_Draper_adder: - def add_or_sub(i, j, num_qubits, subtract=False): - task = Quingo_task(kernel_file, "test_sc_adder") - i_bits = int2bit_list(i, num_qubits) - j_bits = int2bit_list(j, num_qubits) - logger.debug("a: {} '{}' b: {} '{}'".format(i, bin(i), j, bin(j))) - - sim_result = call(task, (i_bits, j_bits, subtract)) - logger.debug(sim_result) - res = get_first_non_zero_res(sim_result) - logger.debug("res: {}".format(res)) - logger.debug(" {} {} {}".format(i, j, res)) - - if subtract: - assert res == subtracter_behavior(i, j, num_qubits) - else: - assert res == adder_behavior(i, j, num_qubits) - - logger.info( - tc.colored("passed:", "green") - + " {} {} {} = {}".format(i, "-" if subtract else "+", j, res) - ) - - def test_adder(self, subtract=False): - num_qubits = 3 - for i in range(1 << 2): - for j in range(1 << 2): - trigger_task(Test_Draper_adder.add_or_sub, (i, j, num_qubits), True) - - def test_subtracter(self): - num_qubits = 3 - for i in range(1 << 2): - for j in range(1 << 2): - trigger_task( - Test_Draper_adder.add_or_sub, (i, j, num_qubits, True), True - ) - - -if __name__ == "__main__": - Test_Draper_adder().test_adder() - Test_Draper_adder().test_subtracter() diff --git a/examples/adder/cphases.qu b/examples/adder/cphases.qu deleted file mode 100755 index e6a58be4d769137bb68c33a38eb9edf549be3454..0000000000000000000000000000000000000000 --- a/examples/adder/cphases.qu +++ /dev/null @@ -1,23 +0,0 @@ -import std_ops - -operation power_of_2(k: int): int { - int res = 1; - for (int i = 0; i < k; i += 1) { - res = res * 2; - } - return res; -} - -operation CPhase(ctrl_qubit: qubit, target_qubit: qubit, angle: double): unit { - ctrl P(target_qubit, angle); -} - -operation c_phase_k(ctrl_qubit: qubit, target_qubit: qubit, k: int): unit { - double angle = 2.0 * pi / toDouble(power_of_2(k)); - ctrl P(target_qubit, angle); -} - -operation c_phase_k_m(ctrl_qubit: qubit, target_qubit: qubit, k: int): unit { - double angle = - 2.0 * pi / toDouble(power_of_2(k)); - ctrl P(target_qubit, angle); -} \ No newline at end of file diff --git a/examples/adder/draper.qu b/examples/adder/draper.qu deleted file mode 100755 index 5a6cb64e899c7cf1c9fd7d41430264a584e331c2..0000000000000000000000000000000000000000 --- a/examples/adder/draper.qu +++ /dev/null @@ -1,49 +0,0 @@ -import std_ops -import cphases -import qft - -// paper order -operation draper_adder(a: qubit[], b: qubit[]) : unit { - int size = a.length; - for (int i = size - 1; i >= 0; i -= 1) { // qubit b_{n-1} - - for (int j = i; j >= 0; j -= 1) { // qubit a{j} - c_phase_k(a[j], b[i], i - j + 1); - } - } -} - -// cross order: -// a[n-1] corresponds to b[0] -// a[n-2] corresponds to b[1] -// ... -// a[ 0] corresponds to b[n-1] -operation draper_adder_reverse(a: qubit[], b: qubit[]) : unit { - int size = a.length; - for (int i = size - 1; i >= 0; i -= 1) { // qubit b_{n-1} - for (int j = i; j >= 0; j -= 1) { // qubit a{j} - c_phase_k(a[j], b[size - i - 1], i - j + 1); - } - } -} - - -// if reverse is true, and perform b - a -> b -// if reverse is false, and perform b + a -> b -operation sc_adder(qb: qubit[], a: int[], reverse: bool) : unit { - int size = a.length; - for (int i = size - 1; i >= 0; i -= 1) { // qubit b_{n-1} - double sum = 0.0; - for (int j = i; j >= 0; j -= 1) { // qubit a{j} - if (a[j] == 1) { - sum += 1.0 / toDouble(power_of_2(i - j + 1)); - } - } - double angle = 2.0 * pi * sum; - if (reverse) { - angle = - angle; - } - P(qb[i], angle); - } -} - diff --git a/examples/adder/draper_test.qu b/examples/adder/draper_test.qu deleted file mode 100755 index c909414048b85d63120567996f00d99c89fee4c5..0000000000000000000000000000000000000000 --- a/examples/adder/draper_test.qu +++ /dev/null @@ -1,53 +0,0 @@ -import draper -import qft -import std_ops - -operation test_adder(a: int[], b: int[]) : bool[] { - int num_qubits = a.length; - bool[num_qubits * 2] result; - using (qa: qubit[num_qubits], qb: qubit[num_qubits]) { - // load a and b into qubits - for (int i = 0; i < num_qubits; i += 1) { - if (b[i] == 1) { - X(qb[i]); - } - if (a[i] == 1) { - X(qa[i]); - } - } - - qft_ns(qb); - draper_adder(qa, qb); - iqft_ns(qb); - - // qft(qb); - // draper_adder_reverse(qa, qb); - // iqft(qb); - - for (int i = 0; i < num_qubits; i += 1) { - result[i+num_qubits] = measure(qb[i]); - } - } - return result; -} - -operation test_sc_adder(a: int[], b: int[], is_subtract: bool) : bool[] { - int num_qubits = b.length; - bool[num_qubits] result; - using (qa: qubit[num_qubits]) { - for (int i = 0; i < num_qubits; i += 1) { - if (a[i] == 1) { - X(qa[i]); - } - } - - qft_ns(qa); - sc_adder(qa, b, is_subtract); - iqft_ns(qa); - - for (int i = 0; i < num_qubits; i += 1) { - result[i] = measure(qa[i]); - } - } - return result; -} diff --git a/examples/adder/my_utils.py b/examples/adder/my_utils.py deleted file mode 100755 index 78a1f1161e3b1536b676d006d42ea54470ffec07..0000000000000000000000000000000000000000 --- a/examples/adder/my_utils.py +++ /dev/null @@ -1,112 +0,0 @@ -def adder_behavior(a, b, num_qubits): - return (a + b) % (1 << num_qubits) - - -def subtracter_behavior(a, b, num_qubits): - if a >= b: - return a - b - else: - return (1 << num_qubits) - (b - a) - - -def is_number(s): - try: - float(s) - return True - except ValueError: - return False - - -def get_bin(x, n): - if not is_number(x): - raise ValueError("get_bin: parameter is not a number.") - - return "{0:{fill}{width}b}".format((int(x) + 2**n) % 2**n, fill="0", width=n) - - -def int2bit_list(x, n): - """Convert an interger `x` to a `n`-bit bit list.""" - if not (0 <= x < 2**n): - raise ValueError( - "int2bit_list: x ({}) is not in the range [0, {}).".format(x, 2**n) - ) - bits = [x >> i & 1 for i in range(n)] - return bits - - -def test_int2bits(): - assert int2bit_list(0, 3) == [0, 0, 0] - assert int2bit_list(1, 3) == [1, 0, 0] - assert int2bit_list(3, 3) == [1, 1, 0] - assert int2bit_list(7, 3) == [1, 1, 1] - assert int2bit_list(1089, 15) == [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0] - - -import logging -from logging.handlers import TimedRotatingFileHandler -import sys -import colorama as cm -import termcolor as tc -from pathlib import Path - -cm.init() - -# Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. -# Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. -# Style: DIM, NORMAL, BRIGHT, RESET_ALL - - -def quingo_info(arg, **kwargs): - print(arg, **kwargs) - - -def quingo_msg(arg, **kwargs): - print(tc.colored(arg, "green"), **kwargs) - - -def quingo_warning(arg, **kwargs): - print(tc.colored(arg, "yellow"), **kwargs) - - -def quingo_err(arg, **kwargs): - print(tc.colored(arg, "red"), **kwargs) - - -FORMATTER = logging.Formatter( - "%(asctime)s %(name)s %(lineno)d(%(levelname)s): %(message)s", datefmt="%H:%M:%S" -) -# LOG_FILE = "my_app.log" - - -def get_console_handler(): - console_handler = logging.StreamHandler(sys.stdout) - console_handler.setFormatter(FORMATTER) - return console_handler - - -# def get_file_handler(): -# file_handler = TimedRotatingFileHandler(LOG_FILE, when='midnight') -# file_handler.setFormatter(FORMATTER) -# return file_handler - - -def get_logger(logger_name): - logger = logging.getLogger(logger_name) - # better to have too much log than not enough - logger.setLevel(logging.DEBUG) - logger.addHandler(get_console_handler()) - # logger.addHandler(get_file_handler()) - # with this pattern, it's rarely necessary to propagate the error up to parent - logger.propagate = False - return logger - - -def ensure_path(fn) -> Path: - assert isinstance(fn, (str, Path)) - if isinstance(fn, str): - fn = Path(fn).resolve() - return fn - - -if __name__ == "__main__": - test_int2bits() diff --git a/examples/adder/qft.qu b/examples/adder/qft.qu deleted file mode 100755 index 7fd146c7a6409f80d77592e34fa792191834e8f5..0000000000000000000000000000000000000000 --- a/examples/adder/qft.qu +++ /dev/null @@ -1,47 +0,0 @@ -import std_ops -import cphases - -// QFT without the trailing swap gates -// least significant bit is 0, and the most significant bit is n - 1 -operation qft_ns(qubits: qubit[]): unit { - int num_qubits = qubits.length; - for (int i = num_qubits - 1; i >= 0; i -= 1) { - H(qubits[i]); - for (int j = i - 1; j >= 0; j -= 1) { - c_phase_k(qubits[j], qubits[i], i - j + 1); - } - } -} - -// IQFT without the leading swap gates -// Note, the qubits are assumed to be arranged in the little endian format, -// i.e., least significant qubit is 0, and most significant qubit is n - 1 -operation iqft_ns(qubits : qubit[]) : unit { - int num_qubits = qubits.length; - for (int i = 0; i < num_qubits; i += 1) { - for (int j = 0; j < i; j += 1) { - c_phase_k_m(qubits[j], qubits[i], i - j + 1); - } - H(qubits[i]); - } -} - -operation rev_qubit_order(qubits: qubit[]): unit { - int num_qubits = qubits.length; - for (int i = 0; i < num_qubits / 2; i += 1) { - SWAP(qubits[i], qubits[num_qubits - i - 1]); - } -} - -// least significant bit is 0, and the most significant bit is n - 1 -operation qft(qubits: qubit[]): unit { - qft_ns(qubits); - rev_qubit_order(qubits); -} - -// Note, the qubits are assumed to be arranged in the little endian format, -// i.e., least significant qubit is 0, and most significant qubit is n - 1 -operation iqft(qubits : qubit[]) : unit { - rev_qubit_order(qubits); - iqft_ns(qubits); -} \ No newline at end of file diff --git a/examples/bell_state/host.py b/examples/bell_state/host.py index a1a7d31b8b3fd82b8b8a5dd659ac1e092b499fd2..18b9d2369f3bd8292c54b6b67b252f448ac03ad6 100644 --- a/examples/bell_state/host.py +++ b/examples/bell_state/host.py @@ -7,10 +7,14 @@ qu_file = Path(__file__).parent / "kernel.qu" def routine(circ_name, num_shots=1): task = Quingo_task(qu_file, circ_name) - cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) + cfg = ExeConfig(ExeMode.SimFinalResult, num_shots=num_shots) qasm_fn = compile(task, params=(), config_file="") - res = execute(qasm_fn, BackendType.TEQUILA, cfg) # QuantumSim, SymQC - print("sim res: ", res) + sim_result = execute(qasm_fn, BackendType.QUALESIM_QUANTUMSIM, cfg) + print(sim_result) + names, values = sim_result + # print("sim res: ", res) + print("names: ", names) + print("values ({}): ".format(type(values)), values) routine("bell_state", 10) diff --git a/examples/compile_info/host.py b/examples/compile_info/host.py index 946c3b96b0dd371c969eeb28774f75b55f1ae388..48a5de712da5162d79d3c339f5423a416ace3900 100644 --- a/examples/compile_info/host.py +++ b/examples/compile_info/host.py @@ -9,7 +9,7 @@ circ_name = "ghz" # configure the execution mode num_shots = 4 -cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) +cfg = ExeConfig(ExeMode.SimShots, num_shots) # the input param num_qubits num_qubits = 5 diff --git a/examples/ctrl_qubit/host.py b/examples/ctrl_qubit/host.py index ae46361e00e2739f4a0ca2c8bcce32dba93fad9a..ac9ce24eeedae3ea531b74047e40288063f31b7c 100644 --- a/examples/ctrl_qubit/host.py +++ b/examples/ctrl_qubit/host.py @@ -7,7 +7,7 @@ qu_file = Path(__file__).parent / "kernel.qu" def routine(circ_name, num_shots=1): task = Quingo_task(qu_file, circ_name) - cfg = ExeConfig(ExeMode.SimFinalResult, 10) + cfg = ExeConfig(ExeMode.SimShots, 10) # exemod 1 res = call(task, (), BackendType.QUANTUM_SIM, cfg) print("sim res: ", res) diff --git a/examples/ghz/host.py b/examples/ghz/host.py index 6b0b7b46a62baf563dcf7fc84d4433c451251920..454ffc9b4d4c025a2d1a03ee00af377e391bd785 100644 --- a/examples/ghz/host.py +++ b/examples/ghz/host.py @@ -9,7 +9,7 @@ circ_name = "ghz" # configure the execution mode num_shots = 4 -cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) +cfg = ExeConfig(ExeMode.SimShots, num_shots) # the input param num_qubits num_qubits = 5 diff --git a/examples/sim_backend/SimQuantumsim.py b/examples/sim_backend/SimQuantumsim.py index 4ec472bd22cc6ab0c3ff40efeac5df4756c83b0b..eadd3fcd4dd277c08c1048bbe1e797e2e3c51668 100644 --- a/examples/sim_backend/SimQuantumsim.py +++ b/examples/sim_backend/SimQuantumsim.py @@ -7,7 +7,7 @@ qu_file = Path(__file__).parent / "kernel.qu" def SimQuantumsim(circ_name, num_shots=1): task = Quingo_task(qu_file, circ_name) - cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) + cfg = ExeConfig(ExeMode.SimShots, num_shots) qasm_fn = compile(task, params=(), config_file="") res = execute(qasm_fn, BackendType.QUANTUM_SIM, cfg) print("sim res: ", res) diff --git a/examples/sim_backend/SimSymQC.py b/examples/sim_backend/SimSymQC.py index 9ca023e6dc293397ddf3f5874fdde2e3345bb0a5..d5fcb3281804d6b6fbf1df3cacff84eb184938f1 100644 --- a/examples/sim_backend/SimSymQC.py +++ b/examples/sim_backend/SimSymQC.py @@ -7,7 +7,7 @@ qu_file = Path(__file__).parent / "kernel.qu" def SimSymQC(circ_name, num_shots=1): task = Quingo_task(qu_file, circ_name) - cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) + cfg = ExeConfig(ExeMode.SimShots, num_shots) qasm_fn = compile(task, params=(), config_file="") res = execute(qasm_fn, BackendType.SYMQC, cfg) print("sim res: ", res) diff --git a/examples/sim_backend/SimTequila.py b/examples/sim_backend/SimTequila.py index 5a3dd07d0b1f2455feeb3fcd8bc25e9e7f1e0104..b8861d2c7f4408166b0f034fc22bbd216ee39935 100644 --- a/examples/sim_backend/SimTequila.py +++ b/examples/sim_backend/SimTequila.py @@ -7,7 +7,7 @@ qu_file = Path(__file__).parent / "kernel.qu" def SimTequila(circ_name, num_shots=1): task = Quingo_task(qu_file, circ_name) - cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) + cfg = ExeConfig(ExeMode.SimShots, num_shots) qasm_fn = compile(task, params=(), config_file="") res = execute(qasm_fn, BackendType.TEQUILA, cfg) # QuantumSim, SymQC print("sim res: ", res) diff --git a/examples/sim_exemode/SimFinalResult.py b/examples/sim_exemode/SimFinalResult.py index 60850b60e9eb9e15ecc32091e739c654d86190e5..c3063b5ca1767bb657101ec68cd0d0301d1ddffa 100644 --- a/examples/sim_exemode/SimFinalResult.py +++ b/examples/sim_exemode/SimFinalResult.py @@ -5,12 +5,12 @@ from pathlib import Path qu_file = Path(__file__).parent / "kernel.qu" -def SimFinalResult(circ_name, num_shots=1): +def SimFinalResult(circ_name): task = Quingo_task(qu_file, circ_name) - cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) + cfg = ExeConfig(ExeMode.SimFinalResult) qasm_fn = compile(task, params=(), config_file="") res = execute(qasm_fn, BackendType.QUANTUM_SIM, cfg) # QuantumSim, SymQC print("sim res: ", res) -SimFinalResult("bell_state", 10) +SimFinalResult("bell_state") diff --git a/examples/sim_exemode/SimShots.py b/examples/sim_exemode/SimShots.py new file mode 100644 index 0000000000000000000000000000000000000000..777f221716ff2f5a10bd7e43df3203efd456b5f5 --- /dev/null +++ b/examples/sim_exemode/SimShots.py @@ -0,0 +1,16 @@ +from quingo import * +from pathlib import Path + + +qu_file = Path(__file__).parent / "kernel.qu" + + +def SimShots(circ_name, num_shots=1): + task = Quingo_task(qu_file, circ_name) + cfg = ExeConfig(ExeMode.SimShots, num_shots) + qasm_fn = compile(task, params=(), config_file="") + res = execute(qasm_fn, BackendType.QUANTUM_SIM, cfg) # QuantumSim, SymQC + print("sim res: ", res) + + +SimShots("bell_state", 10) diff --git a/examples/sim_exemode/SimStateVector.py b/examples/sim_exemode/SimStateVector.py index 35b6182631ecc4a4c8ad95d8220b251d2b48bcc8..9bc525d450ddf3725c09e23ef7eac7ea8972f094 100644 --- a/examples/sim_exemode/SimStateVector.py +++ b/examples/sim_exemode/SimStateVector.py @@ -9,10 +9,8 @@ def SimStateVector(circ_name): task = Quingo_task(qu_file, circ_name) cfg = ExeConfig(ExeMode.SimStateVector) qasm_fn = compile(task, params=(), config_file="") - res = execute(qasm_fn, BackendType.SYMQC, cfg) - print("sim res for bell state is:") - print("classical:", res["classical"]) - print("quantum:", res["quantum"]) + res = execute(qasm_fn, BackendType.QUANTUM_SIM, cfg) + print(res) SimStateVector("bell_state") diff --git a/setup.cfg b/setup.cfg index a495744fadad4b0aa4ef7ef1461ef74644b44d96..5bb5b89214f0bb1de87fefcd933e4bb2622a3f76 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = quingo -version = 0.2.2 +version = 0.3.2 author = Xiang Fu author_email = gtaifu@gmail.com use_2to3 = False @@ -22,14 +22,15 @@ packages =find: python_requires = >=3.7 install_requires = numpy - pyqcas - pyqcisim - symqc + pyqcisim >= 1.3.1 + symqc >= 1.1.1 colorama termcolor requests tqdm - pyezq + qualesim >= 1.0.2 + qualesim-tequila >= 1.0.2 + pyquiet >= 0.0.4 [options.packages.find] where = src \ No newline at end of file diff --git a/src/global_config.py b/src/global_config.py deleted file mode 100644 index 10606108746c4a2a3263e6d55b3a3c4124053ead..0000000000000000000000000000000000000000 --- a/src/global_config.py +++ /dev/null @@ -1,3 +0,0 @@ -from pathlib import Path - -SRC_PATH = cur_dir = Path(__file__).parent.parent diff --git a/src/quingo/__init__.py b/src/quingo/__init__.py index ff685c5f5ac4c601edd8ead3f7b3a277d9fce4ae..236e12467998d5a5514e696195182e9c989083eb 100755 --- a/src/quingo/__init__.py +++ b/src/quingo/__init__.py @@ -2,5 +2,5 @@ from quingo.core.exe_config import ExeConfig, ExeMode from quingo.core.compile import compile from quingo.core.manager import execute, call from quingo.core.quingo_task import Quingo_task -from quingo.backend.backend_hub import * -from quingo.backend.qisa import * +from quingo.backend.backend_hub import BackendType +from quingo.backend.qisa import Qisa diff --git a/src/quingo/backend/__init__.py b/src/quingo/backend/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3a7fb7a538c8990627c711473e27cb56e2cdd3b3 100755 --- a/src/quingo/backend/__init__.py +++ b/src/quingo/backend/__init__.py @@ -0,0 +1,6 @@ +from quingo.backend.backend_hub import BackendType +from quingo.backend.pyqcisim_tequila import PyQCISim_tequila +from quingo.backend.pyqcisim_quantumsim import PyQCISim_quantumsim +from quingo.backend.qualesim import QuaLeSim +from quingo.backend.symqc import IfSymQC +from quingo.backend.qisa import Qisa diff --git a/src/quingo/backend/backend_hub.py b/src/quingo/backend/backend_hub.py index 46ca22e6e8b24cf3761dc9c7f4b9fc812ad2dc61..a576e44079639c26d1d5b9ef89cbf954ab501a5c 100755 --- a/src/quingo/backend/backend_hub.py +++ b/src/quingo/backend/backend_hub.py @@ -1,6 +1,7 @@ import importlib import enum -from .qisa import Qisa +from quingo.backend.qisa import Qisa +from quingo.utils import singleton class BackendType(enum.Enum): @@ -9,19 +10,8 @@ class BackendType(enum.Enum): SYMQC = enum.auto() QUANTIFY = enum.auto() XIAOHONG = enum.auto() - # QUALESIM_TEQUILA = enum.auto() - # QUALESIM_QUANTUMSIM = enum.auto() - - -def singleton(cls): - _instance = {} - - def inner(): - if cls not in _instance: - _instance[cls] = cls() - return _instance[cls] - - return inner + QUALESIM_TEQUILA = enum.auto() + QUALESIM_QUANTUMSIM = enum.auto() @singleton @@ -58,18 +48,18 @@ class Backend_hub: False, Qisa.QCIS, ), - # BackendType.QUALESIM_TEQUILA: ( - # "QuaLeSim_tequila", - # "qualesim_tequila", - # True, - # Qisa.QCIS, - # ), - # BackendType.QUALESIM_QUANTUMSIM: ( - # "QuaLeSim_quantumsim", - # "qualesim_quantumsim", - # True, - # Qisa.QCIS, - # ), + BackendType.QUALESIM_TEQUILA: ( + "QuaLeSim", + "qualesim", + True, + Qisa.QCIS, + ), + BackendType.QUALESIM_QUANTUMSIM: ( + "QuaLeSim", + "qualesim", + True, + Qisa.QCIS, + ), } def support(self, backend_type): diff --git a/src/quingo/backend/if_backend.py b/src/quingo/backend/if_backend.py index 11898b0d679e03f738df2eb9dd47059a3b831ef3..35543fc0741b14843e192d894e60e68c0cd0bc47 100755 --- a/src/quingo/backend/if_backend.py +++ b/src/quingo/backend/if_backend.py @@ -1,9 +1,5 @@ -import re -from quingo.core.utils import * -import logging -from pathlib import Path from .backend_hub import BackendType, Backend_hub -from quingo.core.exe_config import * +from quingo.core.exe_config import ExeConfig class If_backend: diff --git a/src/quingo/backend/pyqcisim_quantumsim.py b/src/quingo/backend/pyqcisim_quantumsim.py index 1a6bae1fe544c1af29976d06775bace5311e2adb..5f3c7e8fc1cb5e1a39cbd44b345e8178c469e90c 100755 --- a/src/quingo/backend/pyqcisim_quantumsim.py +++ b/src/quingo/backend/pyqcisim_quantumsim.py @@ -1,7 +1,12 @@ +from __future__ import annotations +from numpy.typing import NDArray +from typing import List, Union + + +from quingo.utils import ensure_path from .backend_hub import BackendType from .if_backend import If_backend -from quingo.core.exe_config import * -from quingo.core.utils import * +from quingo.core.exe_config import ExeMode, ExeConfig from pyqcisim.simulator import PyQCISim @@ -24,25 +29,25 @@ class PyQCISim_quantumsim(If_backend): program = prog_fn.open("r").read() self.sim.compile(program) - def execute(self, exe_config: ExeConfig): + def execute(self, exe_config: ExeConfig) -> Union[List | NDArray]: """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. - - "final_state": the simulation result is a two-level dictionary: - { - 'classical': {'Q1': 1, 'Q2': 0}, - 'quantum': (['Q3', 'Q4'], array([0, 1, 0, 0])) - } - - num_shots (int): the number of iterations performed in `one_shot` mode. + + The number of shots is specified in exe_config.num_shots, which is only valid for + ExeMode.SimShots. """ - if exe_config.mode == ExeMode.SimStateVector: - raw_res = self.sim.simulate("final_state") + if exe_config.mode == ExeMode.SimShots: + raw_res = self.sim.simulate("one_shot", exe_config.num_shots) return raw_res if exe_config.mode == ExeMode.SimFinalResult: - return self.sim.simulate("one_shot", exe_config.num_shots) + raw_res = self.sim.simulate("final_result") + return raw_res + + if exe_config.mode == ExeMode.SimStateVector: + raw_res = self.sim.simulate("state_vector") + return raw_res raise ValueError( "Unsupported execution mode ({}) for quantumsim.".format(exe_config.mode) diff --git a/src/quingo/backend/pyqcisim_tequila.py b/src/quingo/backend/pyqcisim_tequila.py index e3ed043fa57801f91cb1c7a5a98aafdb7ad75dc6..42a20052ff41e3172a9bab78d63c8ad9dc78299d 100644 --- a/src/quingo/backend/pyqcisim_tequila.py +++ b/src/quingo/backend/pyqcisim_tequila.py @@ -1,10 +1,9 @@ +from quingo.utils import ensure_path from .backend_hub import BackendType from .if_backend import If_backend -from quingo.core.exe_config import * -from quingo.core.utils import * +from quingo.core.exe_config import ExeConfig, ExeMode from pyqcisim.simulator import PyQCISim - -logger = get_logger((__name__).split(".")[-1]) +import numpy as np class PyQCISim_tequila(If_backend): @@ -23,9 +22,24 @@ class PyQCISim_tequila(If_backend): self.sim.compile(program) def execute(self, exe_config: ExeConfig): - if exe_config.mode == ExeMode.SimFinalResult: + """Execute the given quantum circuit. + Args: + - exe_config (ExeConfig): the configuration used to perform simulation by SymQC. + + The number of shots is specified in exe_config.num_shots, which is only valid for + ExeMode.SimShots. + """ + + if exe_config.mode == ExeMode.SimShots: return self.sim.simulate("one_shot", exe_config.num_shots) + if exe_config.mode == ExeMode.SimFinalResult: + return self.sim.simulate("final_result") + + if exe_config.mode == ExeMode.SimStateVector: + names, nd_array_values = self.sim.simulate("state_vector") + return (names, nd_array_values) + raise ValueError( "Unsupported execution mode ({}) for TEQUILA.".format(exe_config.mode) ) diff --git a/src/quingo/backend/qualesim.py b/src/quingo/backend/qualesim.py new file mode 100644 index 0000000000000000000000000000000000000000..7abcf00d2543ccd5641bd164df03e1922147ff5c --- /dev/null +++ b/src/quingo/backend/qualesim.py @@ -0,0 +1,101 @@ +from __future__ import annotations +from typing import Union +from quingo.utils import ensure_path +from pathlib import Path +from quingo.backend.backend_hub import BackendType +from quingo.backend.if_backend import If_backend +from quingo.core.exe_config import ExeConfig, ExeMode +from qualesim.plugin import Loglevel +from qualesim.host import Simulator + + +class QuaLeSim(If_backend): + + def __init__(self, backend_type=BackendType.QUALESIM_QUANTUMSIM): + super().__init__(backend_type) + self.sim = Simulator(stderr_verbosity=Loglevel.OFF) + if backend_type == BackendType.QUALESIM_QUANTUMSIM: + self.sim.with_backend("quantumsim", verbosity=Loglevel.OFF) + elif backend_type == BackendType.QUALESIM_TEQUILA: + self.sim.with_backend("tequila", verbosity=Loglevel.OFF) + else: + raise ValueError( + "The QuaLeSim backend only supports QUALESIM_QUANTUMSIM and QUALESIM_TEQUILA." + ) + + self.res = None + + def upload_program(self, prog_fn: Union[Path | str]): + prog_fn = ensure_path(prog_fn) + + if prog_fn.suffix in [".qcis", ".qi"]: + self.sim.with_frontend(str(prog_fn), verbosity=Loglevel.OFF) + else: + raise TypeError( + "found unsupported file suffix ({}). Currently supported are " + "'.qcis' (for QCIS) and '.qi' (for QUIET-s)".format(prog_fn.suffix) + ) + + def execute(self, exe_config: ExeConfig): + if exe_config.mode == ExeMode.SimShots: + measure_mod = "one_shot" + try: + self.sim.simulate() + res = self.sim.run( + measure_mod=measure_mod, num_shots=exe_config.num_shots + ) + self.sim.stop() + + final_state = res["res"] + final_state["quantum"] = tuple(final_state["quantum"]) + result = final_state["quantum"] + + return result + + except Exception as e: + raise ValueError( + "error in QuaLeSim simulation with mode ({}): {}".format( + exe_config.mode, e + ) + ) + + if exe_config.mode == ExeMode.SimFinalResult: + measure_mod = "one_shot" + try: + self.sim.simulate() + res = self.sim.run( + measure_mod=measure_mod, num_shots=exe_config.num_shots + ) + self.sim.stop() + final_state = res["res"] + final_state["quantum"] = tuple(final_state["quantum"]) + return final_state["quantum"] + + except Exception as e: + raise ValueError( + "error in QuaLeSim simulation with mode ({}): {}".format( + exe_config.mode, e + ) + ) + + if exe_config.mode == ExeMode.SimStateVector: + measure_mod = "state_vector" + try: + self.sim.simulate() + res = self.sim.run(measure_mod=measure_mod) + self.sim.stop() + final_state = eval(res["res"]) + return final_state["quantum"] + + except Exception as e: + raise ValueError( + "error in QuaLeSim simulation with mode ({}): {}".format( + exe_config.mode, e + ) + ) + + raise ValueError( + "Unsupported execution mode ({}) for QuaLeSim_QuantumSim.".format( + exe_config.mode + ) + ) diff --git a/src/quingo/backend/qualesim_quantumsim.py b/src/quingo/backend/qualesim_quantumsim.py deleted file mode 100644 index 7536f266ba99c51a25100b98c09a3779f29c7b2e..0000000000000000000000000000000000000000 --- a/src/quingo/backend/qualesim_quantumsim.py +++ /dev/null @@ -1,67 +0,0 @@ -# from .backend_hub import BackendType -# from .if_backend import If_backend -# from quingo.core.exe_config import * -# from quingo.core.utils import * -# from dqcsim.plugin import * -# from dqcsim.host import * - -# logger = get_logger((__name__).split(".")[-1]) - - -# class QuaLeSim_quantumsim(If_backend): -# """A functional QCIS simulation backend using PyQCISim and Tequila.""" - -# def __init__(self): -# super().__init__(BackendType.QUALESIM_QUANTUMSIM) -# self.sim = Simulator(stderr_verbosity=Loglevel.OFF) -# self.sim.with_backend("quantumsim", verbosity=Loglevel.OFF) -# self.res = None - -# def upload_program(self, prog_fn): -# prog_fn = ensure_path(prog_fn) -# if str(prog_fn).endswith(".qcis") or str(prog_fn).endswith(".qi"): -# self.sim.with_frontend(str(prog_fn), verbosity=Loglevel.OFF) -# else: -# raise TypeError( -# "The quantumsim simulator can only accept QCIS or QUIET-S instructions." -# ) - -# def execute(self, exe_config: ExeConfig): -# if exe_config.mode == ExeMode.SimFinalResult: -# measure_mod = "one_shot" -# try: -# self.sim.simulate() -# res = self.sim.run( -# measure_mod=measure_mod, num_shots=exe_config.num_shots -# ) -# self.sim.stop() -# final_state = res["res"] -# final_state["quantum"] = tuple(final_state["quantum"]) -# return final_state["quantum"] -# except: -# raise ValueError( -# "Here is some wrong with ({}) for QUALESIM_QUANTUMSIM.".format( -# exe_config.mode -# ) -# ) - -# if exe_config.mode == ExeMode.SimStateVector: -# measure_mod = "state_vector" -# try: -# self.sim.simulate() -# res = self.sim.run(measure_mod=measure_mod) -# self.sim.stop() -# final_state = eval(res["res"]) -# return final_state -# except: -# raise ValueError( -# "Here is some wrong with ({}) for QUALESIM_QUANTUMSIM.".format( -# exe_config.mode -# ) -# ) - -# raise ValueError( -# "Here is some wrong with ({}) for QUALESIM_QUANTUMSIM.".format( -# exe_config.mode -# ) -# ) diff --git a/src/quingo/backend/qualesim_tequila.py b/src/quingo/backend/qualesim_tequila.py deleted file mode 100644 index 2dce574411fa9ebaaad2607913ed6e74db6fbb3f..0000000000000000000000000000000000000000 --- a/src/quingo/backend/qualesim_tequila.py +++ /dev/null @@ -1,78 +0,0 @@ -# from .backend_hub import BackendType -# from .if_backend import If_backend -# from quingo.core.exe_config import * -# from quingo.core.utils import * -# from dqcsim.plugin import * -# from dqcsim.host import * - -# logger = get_logger((__name__).split(".")[-1]) - - -# def bitwise_reverse_sort(lst, k): -# sorted_lst = [] -# for i in range(len(lst)): -# sorted_lst.append(lst[int("0b" + bin(i)[2:].zfill(k)[::-1], 2)]) -# return sorted_lst - - -# class QuaLeSim_tequila(If_backend): -# """A functional QCIS simulation backend using PyQCISim and Tequila.""" - -# def __init__(self): -# super().__init__(BackendType.QUALESIM_TEQUILA) -# self.sim = Simulator(stderr_verbosity=Loglevel.OFF) -# self.sim.with_backend("tequila", verbosity=Loglevel.OFF) -# self.res = None - -# def upload_program(self, prog_fn): -# prog_fn = ensure_path(prog_fn) -# if str(prog_fn).endswith(".qcis") or str(prog_fn).endswith(".qi"): -# self.sim.with_frontend(str(prog_fn), verbosity=Loglevel.OFF) -# else: -# raise TypeError( -# "The tequila simulator can only accept QCIS or QUIET-S instructions." -# ) - -# def execute(self, exe_config: ExeConfig): -# if exe_config.mode == ExeMode.SimFinalResult: -# measure_mod = "one_shot" -# try: -# self.sim.simulate() -# res = self.sim.run( -# measure_mod=measure_mod, num_shots=exe_config.num_shots -# ) -# self.sim.stop() -# final_state = res["res"] -# final_state["quantum"] = tuple(final_state["quantum"]) -# return final_state["quantum"] -# except: -# raise ValueError( -# "Here is some wrong with ({}) for QUALESIM_TEQUILA.".format( -# exe_config.mode -# ) -# ) - -# if exe_config.mode == ExeMode.SimStateVector: -# measure_mod = "state_vector" -# try: -# self.sim.simulate() -# res = self.sim.run(measure_mod=measure_mod) -# self.sim.stop() -# final_state = eval(res["res"]) -# qu = bitwise_reverse_sort( -# final_state["quantum"][1], len(final_state["quantum"][0]) -# ) -# final_state["quantum"] = (final_state["quantum"][0], qu) -# return final_state -# except: -# raise ValueError( -# "Here is some wrong with ({}) for QUALESIM_TEQUILA.".format( -# exe_config.mode -# ) -# ) - -# raise ValueError( -# "Unsupported execution mode ({}) for QUALESIM_TEQUILA.".format( -# exe_config.mode -# ) -# ) diff --git a/src/quingo/backend/quingo_result_format_spec.md b/src/quingo/backend/quingo_result_format_spec.md new file mode 100644 index 0000000000000000000000000000000000000000..1df899487f2e7a36db1aba00e87b765119d9ba66 --- /dev/null +++ b/src/quingo/backend/quingo_result_format_spec.md @@ -0,0 +1,80 @@ +# Quingo Backend Result Format +Currently, Quingo supports four kinds of result format: +- SimShots (shot) +- SimFinalResult (final result) +- SimStateVector (state vector) +- SymbolicStateVector (symbolic state vector) + +The real machine can only return the result in the shot mode. + +## SimShot +In this mode, only classical information will be recorded, and the quantum state will be dropped. An extra parameter `num_shots` is accepted for this mode, which tells how many times this experiment will be repeated for. + +The output is a 2-element tuple: + - a list of qubit names or classical variables (`names`) + - a 2-d list, with i-th value in the j-th inner list corresponding to the i-th qubit or classical variable in `names` in the j-th run. + +An Example result of a simulation with num_shots=3: +```python +(['Q3', 'Q4', 'Q5', 'Q6', 'Q7'], + [[1, 1, 0, 0, 0], + [1, 1, 0, 0, 0], + [1, 1, 0, 0, 0]]) +``` + +## SimStateVector +In this mode, measurements are only allowed at the end of the entire program, and no mid-circuit measurement is allowed. All measurements in the end will be dropped while performing the simulation. + +result is a tuple that contains two elements: +- The first element is a list of qubits, and +- the second element is a complex array representing the state of the quantum system (which is a 1-d list). + +Example: +For the following QUIET-s program: +```quiet +func main()->(int c1, int c2): + qubit q1 + qubit q2 + H q1 + CNOT q1, q2 +end +``` + +The result shall be: +```python +{ + 'classical': {}, + 'quantum': (['q1', 'q2'], + [(0.7071067811865474+0j), 0j, 0j, (0.7071067811865476+0j)]) +} +``` + +## SymbolicStateVector +Everything is the same as `SimStateVector`, except that the state is represented using symbols in sympy. + +## SimFinalResult +In this mode, both classical result and quantum result will be returned in a dictionary. The `num_shots` parameter is not allowed in this mode. + +- The `classical` result is a dictionary that maps classical variables to their values. Each key-value pair represents a classical variable and its corresponding value. + +- The `quantum` result is a tuple that contains two elements. The first element is a list of qubits, and the second element is a complex array representing the state of the quantum system. The qubits are represented as strings in the list. The complex array represents the amplitudes of the quantum states, where each element corresponds to a specific quantum state. + +For example: +```quiet +func main()->(int c1, int c2): + qubit q1 + qubit q2 + H q1 + CNOT q1, q2 + measure(q1)->c1 +end +``` + +Two runs of this program returns different results: +```python + {'classical': {'q1': 1}, 'quantum': (['q2'], [0j, (1+0j)])} +``` + +```python +{'classical': {'q1': 0}, 'quantum': (['q2'], [(1+0j), 0j])} +``` diff --git a/src/quingo/backend/readme.md b/src/quingo/backend/readme.md deleted file mode 100644 index 2f06f0461f93906134e336be9bea15240b9ef309..0000000000000000000000000000000000000000 --- a/src/quingo/backend/readme.md +++ /dev/null @@ -1,40 +0,0 @@ -## the result -1. 对于state_vector模式 - - 结果如下: - ``` - 模拟: - .file: - .gate: - .body: - func main()->(int c1, int c2): - qubit q1 - qubit q2 - H q1 - CNOT q1, q2 - end - res = {'classical': {}, 'quantum': (['q1', 'q2'], [(0.7071067811865474+0j), 0j, 0j, (0.7071067811865476+0j)])} - - 模拟: - .file: - .gate: - .body: - func main()->(int c1, int c2): - qubit q1 - qubit q2 - H q1 - CNOT q1, q2 - measure(q1)->c1 - end - res = {'classical': {'q1': 1}, 'quantum': (['q2'], [0j, (1+0j)])} - // - res = {'classical': {'q1': 0}, 'quantum': (['q2'], [(1+0j), 0j])} - ``` - - 对于未测量的量子比特,返回量子比特序列及其对应的状态向量 - - 对于已测量的量子比特,将其及对应的测量值存入classical中,quantum中存储未测量的量子比特的状态向量。(暂时未考虑重复利用已测量的量子比特的情况……) - -2. RealMachine模式 - ```python - res = {'qubit':[0,6], 'result':[[0,1], [1,0], [1,0], [0,1]]} - ``` - - `'qubits'`字段:所有qubit的物理编号 - - `'results'`字段:按`'qubits'`字段中的顺序,每次实验测量的结果 \ No newline at end of file diff --git a/src/quingo/backend/result_formatter.py b/src/quingo/backend/result_formatter.py index c9bc9c74f8c3e29bd226cafdf71b3054e600e32d..667fb3deca2062fa3f4bd4eb9ed159bd51a76c99 100644 --- a/src/quingo/backend/result_formatter.py +++ b/src/quingo/backend/result_formatter.py @@ -1,31 +1,93 @@ -def reorder_bits(qubit_list, str_bit_list, Ascending=True): - """Reorder the bits in str_bit_list according to the order of qubit_list. - Given qubit list ["Q2", "Q1", "Q4", "Q3"] and `str_bit_list` "0001", - the ordered result is "0010", which corresponds to ["Q1", "Q2", "Q3", "Q4"]. +from typing import List, Tuple + + +def reorder_bits(qubit_list, qubit_msmt_res, Ascending=True): """ + Given the measurement result `qubit_msmt_res` of `qubit_list`, reorder the bits in the + result according to the qubit name order. + + Args: + qubit_list (list): A list of qubit names in the desired order. + qubit_msmt_res (list): A list of measurement results corresponding to the qubits. + Ascending (bool, optional): Specifies whether the bits should be reordered in ascending order. + Defaults to True. + + Returns: + list: A list of reordered measurement results. + Example: + Given qubit list ["Q3", "Q1", "Q4", "Q2"] and `qubit_msmt_res` [1, 1, 0, 0], + the ordered result is [1, 0, 1, 0], which corresponds to ["Q1", "Q2", "Q3", "Q4"]. + """ num_qubits = len(qubit_list) - qubit_result_pair = [(qubit_list[i], str_bit_list[i]) for i in range(num_qubits)] + qubit_result_pair = [ + (qubit_list[i].lower(), qubit_msmt_res[i]) for i in range(num_qubits) + ] qubit_result_pair.sort(key=lambda x: int(x[0][1:]), reverse=not Ascending) print(qubit_result_pair) - return "".join([x[1] for x in qubit_result_pair]) + return [x[1] for x in qubit_result_pair] + + +def get_first_non_zero_res( + shots_result: Tuple[List[str], List[List[int]]], + qubits: List[str] = None, + integer_format=True, + little_endian=True, +): + """ + This function is used to get the first non-zero result from the measurement results. + + Args: + shots_result (tuple): A tuple containing two elements: a list of qubit names and a list + of measurement results. + An example shots result of a simulation with num_shots = 3: + (['Q3', 'Q4', 'Q5', 'Q6', 'Q7'], + [[1, 1, 0, 0, 0], + [1, 1, 0, 0, 0], + [1, 1, 0, 0, 0]]) + qubits (list, optional): A list of qubit names. If provided, the function will only consider + the measurement results of the specified qubits. + Defaults to None. -def get_first_non_zero_res(qcis_result): - """This function is used to get the first non-zero result from the measurement results. + integer_format (bool, optional): Specifies whether the result should be returned as an + integer or as a list of bits. + Defaults to True. - qcis_result format: (qubit_list, msmt_count), where qubit_list is a list of qubit names, and msmt_count is a dictionary of measurement results. + little_endian (bool, optional): Specifies whether the result should be in little-endian + format. If False, the result is in big-endian format. + Defaults to True. + Little-endian: [Q0, Q1, Q2] [1, 0, 0] -> 1 + Big-endian: [Q0, Q1, Q2] [1, 0, 0] -> 4 - return: the first non-zero result (in integer format) in the measurement results. + Returns: + int or list: The first non-zero result in the measurement results. If `integer_format` is + True, the result is returned as an integer. + Otherwise, the result is returned as a list of bits. + + Raises: + ValueError: If `shots_result` is None or if the measurement results are None. """ - if qcis_result is None: - print("No measure results found") - qubit_list, msmt_count = qcis_result - for k, v in msmt_count.items(): - if v > 0: - ordered_str = reorder_bits(qubit_list, k) - return int(ordered_str, 2) + if shots_result is None: + raise ValueError("No measure results found") + names, msmt_res = shots_result + + if msmt_res is None: + raise ValueError("No measure results found") + + res = msmt_res[0] + if qubits is not None: + indices = [names.index(q) for q in qubits] + res = [res[idx] for idx in indices] + + if little_endian: + res.reverse() + + if integer_format: + return int("".join(map(str, res)), 2) + else: + return msmt_res[0] diff --git a/src/quingo/backend/symqc.py b/src/quingo/backend/symqc.py index 88923d1d8bb220060b7ceb52f5841a598eebe312..8e39be100d42b96ae12e8635a26fbff6ce893ffd 100644 --- a/src/quingo/backend/symqc.py +++ b/src/quingo/backend/symqc.py @@ -1,13 +1,10 @@ +from quingo.utils import ensure_path from .backend_hub import BackendType from .if_backend import If_backend -from quingo.core.exe_config import * -from quingo.core.utils import * +from quingo.core.exe_config import ExeConfig, ExeMode from symqc.simulator import SymQC -logger = get_logger((__name__).split(".")[-1]) - - class IfSymQC(If_backend): """A functional QCIS simulation backend based on symbolic computation.""" @@ -31,27 +28,21 @@ class IfSymQC(If_backend): 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. - - "final_state": the simulation result is a two-level dictionary: - { - 'classical': {'Q1': 1, 'Q2': 0}, - 'quantum': (['Q3', 'Q4'], array([0, 1, 0, 0])) - } - - num_shots (int): the number of iterations performed in `one_shot` mode. + - exe_config (ExeConfig): the configuration used to perform simulation by SymQC. + + The number of shots is specified in exe_config.num_shots, which is only valid for + ExeMode.SimShots. """ - if exe_config.mode == ExeMode.SimStateVector: - raw_res = self.sim.simulate("final_state") - return raw_res + if exe_config.mode == ExeMode.SimShots: + return self.sim.simulate("one_shot", exe_config.num_shots) if exe_config.mode == ExeMode.SimFinalResult: - return self.sim.simulate("one_shot", exe_config.num_shots) + raw_res = self.sim.simulate("final_state") + return raw_res - if exe_config.mode == ExeMode.SimMatrix: - raise NotImplementedError( - "Runtime has not supported SimMatrix with SymQC yet." - ) + if exe_config.mode == ExeMode.SimStateVector: + raw_res = self.sim.simulate("final_state") + return raw_res["quantum"] raise ValueError( "Unsupported execution mode ({}) for symqc.".format(exe_config.mode) diff --git a/src/quingo/backend/xiaohong.py b/src/quingo/backend/xiaohong.py index 5c3506da64170207f55de707d3d8916f3f50b7dc..d170d6368fb8028c1b4381d5cecb2f6f5866c371 100644 --- a/src/quingo/backend/xiaohong.py +++ b/src/quingo/backend/xiaohong.py @@ -1,11 +1,8 @@ +from quingo.utils import ensure_path from .backend_hub import BackendType from .if_backend import If_backend -from quingo.core.exe_config import * -from quingo.core.utils import * -from pyezQ import * - - -logger = get_logger((__name__).split(".")[-1]) +from quingo.core.exe_config import ExeConfig, ExeMode +import pyezQ class XiaoHong(If_backend): @@ -59,7 +56,7 @@ class XiaoHong(If_backend): return result def set_account(self, login_key, machine_name): - self.account = Account(login_key=login_key, machine_name=machine_name) + self.account = pyezQ.Account(login_key=login_key, machine_name=machine_name) print(f"Set account successfully:") print(f" login key = {login_key[0:5]}" + "*" * (len(login_key) - 5)) print(f" machine name = {machine_name}") diff --git a/src/quingo/core/compile.py b/src/quingo/core/compile.py index cfe5bca9d60bc40e8786b8e84daee655154b4fca..07d6c41d30016ed2f9a1c851b8d86eee928936a0 100644 --- a/src/quingo/core/compile.py +++ b/src/quingo/core/compile.py @@ -1,10 +1,11 @@ -import subprocess, logging from pathlib import Path -from .compiler_config import get_mlir_path +import subprocess, logging +from quingo.core.compiler_config import get_mlir_path from quingo.core.quingo_task import Quingo_task from quingo.core.preparation import gen_main_file -from quingo.core.utils import quingo_err, get_logger, ensure_path -from quingo.backend.qisa import * +from quingo.core.quingo_logger import quingo_err, get_logger +from quingo.utils import ensure_path +from quingo.backend.qisa import Qisa, get_qisa_name, get_suffix logger = get_logger((__name__).split(".")[-1]) diff --git a/src/quingo/core/compiler_config.py b/src/quingo/core/compiler_config.py index 4334d0224e75305d2caf447c72b266b2412c8a91..6be46f83ecaf44aec92f271fc7d7113d303b87f4 100644 --- a/src/quingo/core/compiler_config.py +++ b/src/quingo/core/compiler_config.py @@ -1,5 +1,5 @@ from pathlib import Path -from .utils import quingo_err, quingo_info +from quingo.core.quingo_logger import quingo_err, quingo_info import quingo.global_config as gc import distutils.spawn import requests diff --git a/src/quingo/core/data_transfer.py b/src/quingo/core/data_transfer.py index 96284cd8bbd2abaea8008f5935c0a1f50c5c4d72..70ac59506c44bb249a1c4593e7330bab87218880 100755 --- a/src/quingo/core/data_transfer.py +++ b/src/quingo/core/data_transfer.py @@ -4,7 +4,8 @@ import numpy import quingo.global_config as gc from quingo.core.data import Time -from quingo.core.utils import * +import logging +from quingo.core.quingo_logger import get_logger from typing import Tuple logger = get_logger((__name__).split(".")[-1]) diff --git a/src/quingo/core/exe_config.py b/src/quingo/core/exe_config.py index db9804ec77e8fe53e9a5153c49ab02d6a9aa608c..0c84518aa5ff1f495a0f6057307390022dc58163 100644 --- a/src/quingo/core/exe_config.py +++ b/src/quingo/core/exe_config.py @@ -2,24 +2,27 @@ import enum class ExeMode(enum.Enum): + """ + Enumeration representing different result format. + + Attributes: + SimFinalResult: for obtaining the final result. + SimStateVector: Simulation mode for obtaining the state vector. + SimMatrix: Simulation mode for obtaining the matrix representation. + RealMachine: Mode for executing on a real quantum machine. + """ + + SimShots = enum.auto() SimFinalResult = enum.auto() SimStateVector = enum.auto() - SimMatrix = enum.auto() + SymbolicStateVector = enum.auto() RealMachine = enum.auto() -def is_simulation(exe_mode): - return exe_mode in [ - ExeMode.SimFinalResult, - ExeMode.SimStateVector, - ExeMode.SimMatrix, - ] - - class ExeConfig: def __init__( self, - mode: ExeMode = ExeMode.SimFinalResult, + 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 diff --git a/src/quingo/core/manager.py b/src/quingo/core/manager.py index 76e56427f03aa05eeed0a926ff8be89629f372dc..994550e450a40b0a56cc53f3095b6b754d68038b 100755 --- a/src/quingo/core/manager.py +++ b/src/quingo/core/manager.py @@ -1,18 +1,21 @@ +from __future__ import annotations +from numpy.typing import NDArray +from typing import List, Union +import numpy as np +import array +import sympy as sp + from pathlib import Path -import quingo.core.data_transfer as dt -from .exe_config import * -from .quingo_task import Quingo_task -from .compile import compile -from .utils import get_logger -from quingo.backend.backend_hub import BackendType, Backend_hub -from quingo.backend.qisa import * -logger = get_logger((__name__).split(".")[-1]) +from quingo.core.exe_config import ExeConfig, ExeMode +from quingo.core.quingo_task import Quingo_task +from quingo.core.compile import compile +from quingo.backend.backend_hub import BackendType, Backend_hub def verify_backend_config(backend: BackendType, exe_config: ExeConfig) -> bool: """Check if the combination of backend and execution configuration is valid.""" - if backend == BackendType.XIAOHONG and is_simulation(exe_config.mode): + if (backend == BackendType.XIAOHONG) and (exe_config.mode != ExeMode.RealMachine): return False if backend == BackendType.QUANTIFY: @@ -20,7 +23,9 @@ def verify_backend_config(backend: BackendType, exe_config: ExeConfig) -> bool: return True -def execute(qasm_fn: Path, be_type: BackendType, exe_config: ExeConfig = ExeConfig()): +def execute( + qasm_fn: Path, be_type: BackendType, exe_config: ExeConfig = ExeConfig() +) -> Union[List | NDArray]: """Execute the quingo task on the specified backend and return the result.""" if not verify_backend_config(be_type, exe_config): @@ -30,7 +35,31 @@ def execute(qasm_fn: Path, be_type: BackendType, exe_config: ExeConfig = ExeConf backend = Backend_hub().get_instance(be_type) backend.upload_program(qasm_fn) - return backend.execute(exe_config) + result = backend.execute(exe_config) + if exe_config.mode == ExeMode.SimStateVector: + names, array_values = result + if len(names) == 0: + return ([], 1) + + if isinstance(array_values, list): + if len(array_values) == 0: + return ([], 1) + + array_values = np.array(array_values) + + elif isinstance(array_values, array.array): + array_values = np.array(array_values) + + elif isinstance(array_values, sp.Matrix): + array_values = np.array(array_values).astype(np.complex64) + + else: + assert isinstance(array_values, np.ndarray) + + array_values = array_values.flatten() + return (names, array_values) + + return result def call( diff --git a/src/quingo/core/preparation.py b/src/quingo/core/preparation.py index d3cdb109329d5b622e54b14021b46ad67d06fdc9..d9ec44e469c72b1351c39ba8eb45151c051ee847 100644 --- a/src/quingo/core/preparation.py +++ b/src/quingo/core/preparation.py @@ -1,11 +1,10 @@ """The task of this module is to prepare the Quingo source file for the compilation. """ - import re from pathlib import Path -from quingo.core.utils import get_logger import logging +from quingo.core.quingo_logger import get_logger import quingo.core.data_transfer as dt logger = get_logger((__name__).split(".")[-1]) diff --git a/src/quingo/core/utils.py b/src/quingo/core/quingo_logger.py similarity index 89% rename from src/quingo/core/utils.py rename to src/quingo/core/quingo_logger.py index 27bf1ee9f655b7e5b3ef2a789036c12f4447ea1d..5ef257e2645d177ecdc03bc5bbd5c26b0b820483 100755 --- a/src/quingo/core/utils.py +++ b/src/quingo/core/quingo_logger.py @@ -3,7 +3,6 @@ from logging.handlers import TimedRotatingFileHandler import sys import colorama as cm import termcolor as tc -from pathlib import Path cm.init() @@ -55,10 +54,3 @@ def get_logger(logger_name): # with this pattern, it's rarely necessary to propagate the error up to parent logger.propagate = False return logger - - -def ensure_path(fn) -> Path: - assert isinstance(fn, (str, Path)) - if isinstance(fn, str): - fn = Path(fn).resolve() - return fn diff --git a/src/quingo/core/quingo_task.py b/src/quingo/core/quingo_task.py index 1d4b587912167ceb68886556dec6253d6c6c0824..c662ae4f7c06ab4e19bf75efb6f07b2d5b0e33d7 100644 --- a/src/quingo/core/quingo_task.py +++ b/src/quingo/core/quingo_task.py @@ -4,7 +4,7 @@ import quingo.global_config as gc import tempfile from quingo.backend.backend_hub import BackendType from quingo.backend.qisa import Qisa -from quingo.core.utils import ensure_path +from quingo.utils import ensure_path DEBUG_MODE = False @@ -107,8 +107,8 @@ class Quingo_task: BackendType.TEQUILA, BackendType.SYMQC, BackendType.XIAOHONG, - # BackendType.QUALESIM_QUANTUMSIM, - # BackendType.QUALESIM_TEQUILA, + BackendType.QUALESIM_QUANTUMSIM, + BackendType.QUALESIM_TEQUILA, ]: return Qisa.QCIS diff --git a/src/quingo/lib/config-quingo.qfg b/src/quingo/lib/config-quingo.qfg deleted file mode 100755 index c34a2b88dceef4c0d06e5d4ccf2cda261e032081..0000000000000000000000000000000000000000 --- a/src/quingo/lib/config-quingo.qfg +++ /dev/null @@ -1,69 +0,0 @@ -package config.json - - -{ - "Rx90": { - "duration": 20, - "matrix": [ [0.0,0.0], [1.0,0.0], [1.0,0.0], [0.0,0.0] ], - "type": "single-qubit", - "eqasm": "rx90" - }, - "X": { - "duration": 20, - "matrix": [ [0.0,0.0], [1.0,0.0], [1.0,0.0], [0.0,0.0] ], - "type": "single-qubit", - "eqasm": "rx180" - }, - "Y": { - "duration": 20, - "matrix": [ [0.0,0.0], [0.0,-1.0], [0.0,1.0], [0.0,0.0] ], - "type": "single-qubit", - "eqasm": "ry180" - }, - "Z": { - "duration": 20, - "matrix": [ [1.0,0.0], [0.0,0.0], [0.0,0.0], [-1.0,0.0] ], - "type": "single-qubit", - "eqasm": "rz180" - }, - "T": { - "duration": 20, - "matrix": [ [1.0,0.0], [0.0,0.0], [0.0,0.0], [-1.0,0.0] ], - "type": "single-qubit", - "eqasm": "t" - }, - "Tdag": { - "duration": 20, - "matrix": [ [1.0,0.0], [0.0,0.0], [0.0,0.0], [-1.0,0.0] ], - "type": "single-qubit", - "eqasm": "tdag" - }, - "S": { - "duration": 20, - "matrix": [ [1.0,0.0], [0.0,0.0], [0.0,0.0], [-1.0,0.0] ], - "type": "single-qubit", - "eqasm": "S" - }, - "H": { - "duration": 40, - "matrix": [[1.0,0.0], [1.0,0.0], [1.0,0.0], [-1.0,0.0]] , - "type": "single-qubit", - "eqasm": "H" - }, - "CZ": { - "duration": 40, - "matrix": [ - [1.0,0.0], [0.0,0.0], [0.0,0.0], [0.0,0.0], - [0.0,0.0], [1.0,0.0], [0.0,0.0], [0.0,0.0], - [0.0,0.0], [0.0,0.0], [1.0,0.0], [0.0,0.0], - [0.0,0.0], [0.0,0.0], [0.0,0.0], [-1.0,0.0] - ], - "type": "two-qubit", - "eqasm": "CZ" - }, - "measure": { - "duration": 600, - "type":"meas", - "eqasm":"MeasZ" - } -} diff --git a/src/quingo/lib/qiskit_tools.py b/src/quingo/lib/qiskit_tools.py new file mode 100644 index 0000000000000000000000000000000000000000..117648335f02a04fd1f41833655633f754ff95bd --- /dev/null +++ b/src/quingo/lib/qiskit_tools.py @@ -0,0 +1,33 @@ +"""Visualization functions for quantum circuits. + +Note, this module requires qiskit to be installed. +""" + +from qiskit import QuantumCircuit +from pathlib import Path +from pyqcisim.qcis_to_openqasm import qcis_file_2_qasm_file + + +def qcis_2_qiskit_qc(qcis_fn: Path): + """Convert a QCIS file to a qiskit QuantumCircuit object.""" + qasm_fn = qcis_fn.with_suffix(".qasm") + qasm_str = qcis_file_2_qasm_file(qcis_fn, qasm_fn) + return QuantumCircuit.from_qasm_file(str(qasm_fn)) + + +def draw_circ(qcis_fn: Path, output="mpl"): + """Draw the quantum circuit using qiskit. + Use the output parameter to choose the drawing format: + + **text**: ASCII art TextDrawing that can be printed in the console. + + **mpl**: images with color rendered purely in Python using matplotlib. + + **latex**: high-quality images compiled via latex. + + **latex_source**: raw uncompiled latex output. + """ + qasm_fn = qcis_fn.with_suffix(".qasm") + qasm_str = qcis_file_2_qasm_file(qcis_fn, qasm_fn) + qc = QuantumCircuit.from_qasm_file(str(qasm_fn)) + return qc.draw(output=output) diff --git a/src/quingo/lib/standard_operations.qu b/src/quingo/lib/standard_operations.qu deleted file mode 100755 index 85abfb0fb5e20259f43ece86c5b0f949071ea9fd..0000000000000000000000000000000000000000 --- a/src/quingo/lib/standard_operations.qu +++ /dev/null @@ -1,25 +0,0 @@ -opaque Rx90(q:qubit): unit; -opaque X(q:qubit): unit; -opaque Y(q:qubit): unit; -opaque Z(q:qubit): unit; -opaque T(q:qubit): unit; -opaque Tdag(q:qubit): unit; -opaque S(q:qubit): unit; -opaque H(q:qubit): unit; -opaque CZ(c:qubit, t:qubit): unit; -opaque measure(c:qubit): bool; - -operation init(q: qubit) : unit { - bool a; - a = measure(q); - if (a) { - X(q); - } -} - -operation CNOT(c: qubit, t: qubit): unit -{ - H(t); - CZ(c, t); - H(t); -} diff --git a/src/quingo/utils.py b/src/quingo/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..67cfa2c7c400f1a68e9af6126afdbd829a567c68 --- /dev/null +++ b/src/quingo/utils.py @@ -0,0 +1,57 @@ +import sympy as sp +from pathlib import Path +import numpy as np + + +def ensure_path(fn) -> Path: + assert isinstance(fn, (str, Path)) + if isinstance(fn, str): + fn = Path(fn).resolve() + return fn + + +def is_number(s): + try: + float(s) + return True + except ValueError: + return False + + +def singleton(cls): + _instance = {} + + def inner(): + if cls not in _instance: + _instance[cls] = cls() + return _instance[cls] + + return inner + + +def number_distance(a, b): + """calculates the distance between two complex numbers or two sympy numbers.""" + if isinstance(a, complex) and isinstance(b, complex): + return (a.real - b.real) ** 2 + (a.imag - b.imag) ** 2 + + if hasattr(a, "evalf") and hasattr(b, "evalf"): + return (a.evalf() - b.evalf()) ** 2 + + raise ValueError("unsupported types for dist: {} and {}".format(type(a), type(b))) + + +import numpy as np + + +def state_fidelity(state_a: np.ndarray, state_b: np.ndarray): + """ + Calculate the state fidelity between two quantum states. + + Parameters: + state_a (np.ndarray): The first quantum state. + state_b (np.ndarray): The second quantum state. + + Returns: + float: The state fidelity between the two quantum states. + """ + return np.vdot(state_a, state_b) diff --git a/tests/qiskit_tools_test.ipynb b/tests/qiskit_tools_test.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..1911415f297fa858264264f3a53460bc61e8846f --- /dev/null +++ b/tests/qiskit_tools_test.ipynb @@ -0,0 +1,93 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from quingo.lib.qiskit_tools import draw_circ, qcis_2_qiskit_qc\n", + "from pathlib import Path" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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7udwoco9baYmwaQMiPDNu4+K1FKIi18Y0Nl+HveqHXCkCTeMjAyFewZAegroeSBiAoW4+I24KJg2BL4stD8P87ATN5VrHQGZ3ex/osM9V6OIuynExa8EBNiHQlKT4NtzsD/f/jSeghIotkLN2aMRofYx76R4ew++R3udQihmUoiL32oXDUN61p122WYP+kANlYifUIhLi6LetvgbfaRFRAymEBcRMZhCXETEYApxERGD6cCmiPikyMhIrFarW9pauGQVZeUVxERFMuvxBxqc1hSOnk3QHBTiIuKTAgIC3Pbg4dCwcEIvXSY0LLy2TUfTTKThFBERgynERUQMphAXETGYQlxExGAKcRERgynERUQMphAXETGYQlxExGAKcRERgynERUQMphAXETGYQlxExGAKcRERgynERUQMphAXETGYQlxExGAKcRERgynERUQMphAXETGYQlxExGAKcRERgynERUQMphD3AQsXLiQjI4O4uDhiY2MZPHgwGzZs8HZZIte0fv16+vbtS1hYGCkpKbzyyiveLqlZbdmyhXHjxtGpUycCAgJ48cUXvVKHQtwHbN68mR/96Ed88sknfP7552RmZjJmzBi2bdvm7dJEHMrJyWHcuHGMHDmS3NxcXnjhBebMmcPrr7/u7dKajdVqpWfPnrz88sskJCR4rY5gr21Zan300Ud1Xr/88sts2LCBNWvWcNttt3mpKpGGvfLKKwwcOJD58+cD0KNHD7788kteeuklpk2b5uXqmseoUaMYNWoUALNnz/ZaHQpxH2Sz2SgrKyMqKsrbpYhhLly8xDeFp+pNr7p8ufbn0a8L6r2+0o1t42gdfe3P3rZt23jkkUfqTBsxYgSLFi2ioKCApKSkpryNJvlX4SkqL16qM83R+23o7yAiLJTk9jc0U7VNpxD3QfPmzePMmTM89thj3i5FDBMSEszWz/dxLK/Q4fyK85X87k/rG3wdG9OKmT+697rbKSoqqjeEUPO6qKjIqyFecvYcq/662eG8q9+vo2k/HD+MZI9W6F4aE/cxixcvZt68ebz33nte/Y8gZgoMCODeUXcSER7m0voTR91JeFiom6tqXn17dqXPLV1cWrd/andSb+7s5oo8SyHuQxYtWsSsWbP48MMPGTp0qLfLEUO1jo5i/DDnj6UMHtibmzq1b9SyiYmJWCyWOtNOnTpVO8/bxt81mJhWkU6tExvTiruHZnqoIs9RiPuI559/nrlz57J+/XoFuDRZWs+upPW4qdHL39g2juG3D2z08rfddhsbN26sM23Dhg106tTJJ/YgIyPCuXfUnY1ePgC4b7SZeyEKcR8wc+ZMFi5cyDvvvMPNN9+MxWLBYrFw9uxZb5cmBht312BiWl3/4HhQYCD3jckiJLjxh8h++tOf8vnnn/Pcc89x+PBhfv/73/Ob3/yGZ555piklu1X3zklk9O/VqGUHD+xDl46N2wupYbVayc3NJTc3l4sXL2KxWMjNzeX48eOulOuygOrq6upm3aLUExAQ4HD6lClTeOutt5q3GPErx74uYPlVB/KuNvz2gWRl9HO67XXr1jFnzhwOHz5MQkICM2bM4Gc/+5mrpXrExUtV/Oat9/m2pOEO0Y1t43hyygSnvsQAPv30U7KysupNv+OOO/j000+dLdVlCnHDfJ1fRFJCO0JCdGKRNM6HH2/jn7u/dDivU4cbefwHYwkM9N+d8vyi/+W37/wFm4OoCwoMZPqUCbS/oY0XKnMP//2X80PnrBUs/9N6Xl66irNlVm+XI4YYccd/0S4+tt700JBg7hud5dcBDpCceANDMvs7nDfsOwOMDnBQiBvls537qKq6TFxMNDHXuRhDpEZoSDD3j8kiMLDusN2Y72bSJi7GS1U1r6yMfiQntqszLSUpgdsH9fFSRe6jEL/C5cuXeeedd7jrrrto164dYWFhdOzYkREjRrBs2TIu//sKL284Z61gR+5BAIYOTm9wHF3EkaTEdnw3M732dY+uHRnY52YvVtS8goJqDt4GARAaGsLE0Xf6xV6I+e/ATcrKyhg2bBiTJ0/mb3/7G6GhoaSlpWGz2di0aROPPvoo586d81p9Nb3wju1vpFtKB6/VIea6M6MvyYk3EBURzj0jbm9xHYF28bGMyroVgLFDMmgT6x97ITqw+W8TJ06svUry7bffrnPU+dSpUyxfvpwZM2a4dD+T3/x+Dees512uzWazYa2wrx8ZHkawk0fRRWrYqm3YbDaCg1ruZ+jipUuEhoR4u4x6oltF8JMp9zi9nkIc2L17NwMGDCA4OJi9e/eSmprq1vbn/c8fKbOWu7VNEfEvMa2imDN9ktPrtdyv4yt88MEHAIwePdrtAQ72b1hXqRcu0jK4mhNKBODgQfsBw4yMDI+078ouUo21f9/OP3L207H9jTzxw7tb3DimiFybQhz7QU2A1q1be6R9V8fEr+yFF5ecYf7iFe4uTUR8hKtj4gpxICbGfpTaU/cqOWc93+Qx8YrKC8AF9xQkIn5DIQ706tWLNWvWsH37do+078pYl8bCRVoWV8fEdXYKsHfvXvr3709ISAi5ubn07NnT2yVpLFxEGkUX+wD9+vXjvvvu49KlS4wcOZLPPvuszvxTp04xf/58ysub5zRBXZ0pIo2lnvi/lZWVMW7cuNpbSHbo0IH27dtTVFREYWEh1dXVlJaWEhsb6/Fa1AsXkcZST/zfYmJi+Pjjj1m+fDl33nknFRUV7Nu3j8DAQIYPH87y5cuJjo5ullpaRUUQHhaqXriIXJd64j6q8sJFwkJDFOIick0KcRERg2k4RUTEYApxERGDKcRFRAymEBcRMZhCXETEYApxERGDKcRFRAymEBcRMZhCXETEYApxERGDKcRFRAymEBcRMZhCXETEYApxERGDKcRFRAymEBcRMZhCXETEYApxERGDKcRFRAymEBcRMZhCXETEYApxERGDKcRFRAymEBcRMZhCXETEYApxERGDKcRFRAymEBcRMZhCXETEYApxERGDKcRFRAymEBcRMZhCXETEYApxERGDKcRFRAymEBcRMZhCXETEYApxERGDKcRFRAz2/wHoKkgHdFVPHgAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "qcis_fn = Path('/tmp/quingo-9mp_zcgv/main_kernel_bell_state.qcis')\n", + "draw_circ(qcis_fn, output='mpl')" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "qc = qcis_2_qiskit_qc(qcis_fn)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "qc.depth()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "quingo", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.17" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/unittest/backends/test_backends.py b/unittest/backends/test_backends.py new file mode 100644 index 0000000000000000000000000000000000000000..d9f181b6207c08e1e447110ea1cacf118a858694 --- /dev/null +++ b/unittest/backends/test_backends.py @@ -0,0 +1,66 @@ +from quingo.backend.pyqcisim_tequila import PyQCISim_tequila +from quingo.backend.pyqcisim_quantumsim import PyQCISim_quantumsim +from quingo.backend.qualesim import QuaLeSim +from quingo.backend.symqc import IfSymQC +from quingo.backend.backend_hub import BackendType, Backend_hub +from quingo.backend.qisa import Qisa +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" +qcis_fn2 = unittest_dir / "test_qcis" / "bell_no_msmt.qcis" +quiet_fn = unittest_dir / "test_qcis" / "bell.qi" +quiet_fn2 = unittest_dir / "test_qcis" / "bell_no_msmt.qi" + + +# progress: 2023-10-09 +# finished test on quantumsim and Tequila. +class Test_backends: + def test_basic(self): + def single(BackendClass, type, qisa, is_sim): + sim = BackendClass() + assert sim.get_type() == type + assert sim.get_qisa() == qisa + assert sim.is_simulator() == is_sim + + # QuaLeSim_tequila and QuaLeSim_quantumsim default Qisa type is QCIS + # single(QuaLeSim_tequila, BackendType.QUALESIM_TEQUILA, Qisa.QCIS, True) + single(QuaLeSim, BackendType.QUALESIM_QUANTUMSIM, Qisa.QCIS, True) + single(PyQCISim_tequila, BackendType.TEQUILA, Qisa.QCIS, True) + single(PyQCISim_quantumsim, BackendType.QUANTUM_SIM, Qisa.QCIS, True) + single(IfSymQC, BackendType.SYMQC, Qisa.QCIS, True) + + def test_upload_program(self): + def single(BackendClass, qasm_fn): + sim = BackendClass() + try: + sim.upload_program(qasm_fn) + except Exception as e: + assert False, "upload_program failed: {}".format(e) + + # single(QuaLeSim_tequila, qcis_fn) + # single(QuaLeSim_tequila, quiet_fn) + single(QuaLeSim, qcis_fn) + single(QuaLeSim, quiet_fn) + single(PyQCISim_tequila, qcis_fn) + single(PyQCISim_quantumsim, qcis_fn) + single(IfSymQC, qcis_fn) + + def test_get_from_hub(self): + def single(backend_type, simulator_class): + hub = Backend_hub() + sim = hub.get_instance(backend_type) + assert isinstance(sim, simulator_class) + + single(BackendType.QUANTUM_SIM, PyQCISim_quantumsim) + single(BackendType.TEQUILA, PyQCISim_tequila) + single(BackendType.QUALESIM_QUANTUMSIM, QuaLeSim) + single(BackendType.SYMQC, IfSymQC) + + +if __name__ == "__main__": + pass diff --git a/unittest/backends/test_qualesim.py b/unittest/backends/test_qualesim.py new file mode 100644 index 0000000000000000000000000000000000000000..aeafbcbe3e27a94e92042ba370c06da9c1e8d5ca --- /dev/null +++ b/unittest/backends/test_qualesim.py @@ -0,0 +1,51 @@ +import pytest +from quingo.backend.backend_hub import BackendType +from quingo.backend.qualesim import QuaLeSim +from quingo.core.exe_config import ExeConfig, ExeMode +from quingo import execute +from quingo.utils import number_distance +from pathlib import Path + + +unittest_dir = Path(__file__).parent / ".." +bell_qcis_fn = unittest_dir / "test_qcis" / "bell.qcis" +bell_no_msmt_qcis_fn = unittest_dir / "test_qcis" / "bell_no_msmt.qcis" + +bell_quiet_fn = unittest_dir / "test_qcis" / "bell.qi" +bell_no_msmt_quiet_fn = unittest_dir / "test_qcis" / "bell_no_msmt.qi" + + +bell_qasm_fns = [ + bell_qcis_fn, + bell_quiet_fn, +] + + +@pytest.fixture( + scope="module", + params=[BackendType.QUALESIM_QUANTUMSIM, BackendType.QUALESIM_TEQUILA], +) +def get_backend_type(request): + return request.param + + +@pytest.fixture(scope="module") +def get_qualesim(get_backend_type): + backend_type = get_backend_type + return QuaLeSim(backend_type) + + +@pytest.fixture(params=bell_qasm_fns) +def get_bell_qasm_fn(request): + return request.param + + +def test_call_qualesim(get_qualesim, get_bell_qasm_fn): + simulator = get_qualesim + simulator.upload_program(get_bell_qasm_fn) + num_shots = 10 + exe_config = ExeConfig(ExeMode.SimShots, num_shots) + names, result = simulator.execute(exe_config) + assert names == ["Q1", "Q2"] + assert len(result) == num_shots + assert all(i == j for i, j in result) diff --git a/unittest/backends/test_result_format.py b/unittest/backends/test_result_format.py new file mode 100644 index 0000000000000000000000000000000000000000..5805597ac9c80738f02e21359ce73f0886bea4a3 --- /dev/null +++ b/unittest/backends/test_result_format.py @@ -0,0 +1,103 @@ +from quingo.backend.backend_hub import BackendType, Backend_hub +from quingo.core.exe_config import ExeConfig, ExeMode +from quingo import execute +from quingo.utils import number_distance, state_fidelity +from pathlib import Path +import pytest +import numpy as np + +cur_dir = Path(__file__).parent + +bell_qcis_fn = cur_dir / ".." / "test_qcis" / "bell.qcis" +bell_no_msmt_qcis_fn = cur_dir / ".." / "test_qcis" / "bell_no_msmt.qcis" + + +quiet_fn = cur_dir / ".." / "test_qcis" / "bell.qi" +quiet_fn2 = cur_dir / ".." / "test_qcis" / "bell_no_msmt.qi" + + +backends = [ + BackendType.QUANTUM_SIM, + BackendType.TEQUILA, + BackendType.SYMQC, + BackendType.QUALESIM_QUANTUMSIM, + BackendType.QUALESIM_TEQUILA, +] +num_shots = [5, 10] + + +@pytest.fixture(params=backends) +def get_simulator(request): + return request.param + + +@pytest.fixture(params=num_shots) +def get_num_shots(request): + return request.param + + +def test_shot_with_msmt(get_simulator, get_num_shots): + simulator = get_simulator + num_shots = get_num_shots + + exe_config = ExeConfig(ExeMode.SimShots, num_shots) + names, result = execute(bell_qcis_fn, simulator, exe_config) + print("result for {}: ".format(simulator), names, result) + assert names == ["Q1", "Q2"] + assert len(result) == num_shots + assert all(i == j for i, j in result) + + +def test_shot_without_msmt(get_simulator, get_num_shots): + simulator = get_simulator + num_shots = get_num_shots + + exe_config = ExeConfig(ExeMode.SimShots, num_shots) + names, result = execute(bell_no_msmt_qcis_fn, simulator, exe_config) + assert names == [] + assert len(result) == num_shots + assert all(len(l) == 0 for l in result) + + +def test_final_result_with_msmt(get_simulator, get_num_shots): + simulator = get_simulator + num_shots = get_num_shots + + exe_config = ExeConfig(ExeMode.SimFinalResult, num_shots=num_shots) + result = execute(bell_qcis_fn, simulator, exe_config) + print("result: ", result) + + +def test_final_result_without_msmt(get_simulator, get_num_shots): + simulator = get_simulator + num_shots = get_num_shots + + exe_config = ExeConfig(ExeMode.SimFinalResult, num_shots=num_shots) + result = execute(bell_no_msmt_qcis_fn, simulator, exe_config) + print("result: ", result) + + +def test_state_vector_without_msmt(get_simulator): + simulator = get_simulator + exe_config = ExeConfig(ExeMode.SimStateVector) + qubit_names, state_vec = execute(bell_no_msmt_qcis_fn, simulator, exe_config) + + assert qubit_names == ["Q1", "Q2"] + assert isinstance(state_vec, (list, np.ndarray)) + assert state_vec.shape == (4,) + assert state_fidelity( + state_vec, [0.7071067811865475, 0.0, 0.0, 0.7071067811865475] + ) == pytest.approx(1) + + +def test_state_vector_with_msmt(get_simulator): + simulator = get_simulator + exe_config = ExeConfig(ExeMode.SimStateVector) + qubit_names, state_vec = execute(bell_qcis_fn, simulator, exe_config) + + assert qubit_names == ["Q1", "Q2"] + assert isinstance(state_vec, (list, np.ndarray)) + assert state_vec.shape == (4,) + assert state_fidelity( + state_vec, [0.7071067811865475, 0.0, 0.0, 0.7071067811865475] + ) == pytest.approx(1) diff --git a/unittest/backends/test_result_formatter.py b/unittest/backends/test_result_formatter.py new file mode 100644 index 0000000000000000000000000000000000000000..8288e04e63d49c618844ead25336595ae92a050f --- /dev/null +++ b/unittest/backends/test_result_formatter.py @@ -0,0 +1,105 @@ +import unittest +from quingo.backend.result_formatter import get_first_non_zero_res, reorder_bits + + +class TestResultFormatter(unittest.TestCase): + def test_no_measure_results(self): + with self.assertRaises(ValueError): + get_first_non_zero_res(None) + + def test_no_measure_results_found(self): + shots_result = (["Q3", "Q4", "Q5", "Q6", "Q7"], None) + with self.assertRaises(ValueError): + get_first_non_zero_res(shots_result) + + def test_integer_format_little_endian(self): + shots_result = ( + ["Q3", "Q4", "Q5", "Q6", "Q7"], + [[1, 1, 0, 0, 0], [1, 1, 0, 0, 0], [1, 1, 0, 0, 0]], + ) + result = get_first_non_zero_res(shots_result) + self.assertEqual(result, 0b00011) + + def test_integer_format_big_endian(self): + shots_result = ( + ["Q3", "Q4", "Q5", "Q6", "Q7"], + [[1, 1, 0, 0, 0], [1, 1, 0, 0, 0], [1, 1, 0, 0, 0]], + ) + result = get_first_non_zero_res(shots_result, little_endian=False) + self.assertEqual(result, 0b11000) + + def test_list_format_little_endian(self): + shots_result = ( + ["Q3", "Q4", "Q5", "Q6", "Q7"], + [[1, 1, 0, 0, 0], [1, 1, 0, 0, 0], [1, 1, 0, 0, 0]], + ) + result = get_first_non_zero_res(shots_result, integer_format=False) + self.assertEqual(result, [0, 0, 0, 1, 1]) + + def test_list_format_big_endian(self): + shots_result = ( + ["Q3", "Q4", "Q5", "Q6", "Q7"], + [[1, 1, 0, 0, 0], [1, 1, 0, 0, 0], [1, 1, 0, 0, 0]], + ) + result = get_first_non_zero_res( + shots_result, integer_format=False, little_endian=False + ) + self.assertEqual(result, [1, 1, 0, 0, 0]) + + def test_specific_qubits(self): + shots_result = ( + ["Q3", "Q4", "Q5", "Q6", "Q7"], + [[1, 1, 0, 0, 0], [1, 1, 0, 0, 0], [1, 1, 0, 0, 0]], + ) + result = get_first_non_zero_res(shots_result, qubits=["Q4", "Q5"]) + self.assertEqual(result, 0b01) + + def test_reorder_bits_ascending(self): + qubit_list = ["Q3", "Q1", "Q4", "Q2"] + qubit_msmt_res = [1, 1, 0, 0] + expected_result = [1, 0, 1, 0] + result = reorder_bits(qubit_list, qubit_msmt_res) + self.assertEqual(result, expected_result) + + def test_reorder_bits_descending(self): + qubit_list = ["Q3", "Q1", "Q4", "Q2"] + qubit_msmt_res = [1, 1, 0, 0] + expected_result = [0, 1, 0, 1] + result = reorder_bits(qubit_list, qubit_msmt_res, Ascending=False) + self.assertEqual(result, expected_result) + + def test_reorder_bits_same_order(self): + qubit_list = ["Q1", "Q2", "Q3", "Q4"] + qubit_msmt_res = [1, 0, 1, 0] + expected_result = [1, 0, 1, 0] + self.assertEqual( + reorder_bits(qubit_list, qubit_msmt_res, Ascending=True), expected_result + ) + + def test_reorder_bits_empty_input(self): + qubit_list = [] + qubit_msmt_res = [] + expected_result = [] + self.assertEqual( + reorder_bits(qubit_list, qubit_msmt_res, Ascending=True), expected_result + ) + + def test_reorder_bits_more_qubits(self): + qubit_list = ["Q6", "Q3", "Q1", "Q4", "Q2", "Q5"] + qubit_msmt_res = [1, 1, 0, 0, 1, 0] + expected_result = [0, 1, 1, 0, 0, 1] + self.assertEqual( + reorder_bits(qubit_list, qubit_msmt_res, Ascending=True), expected_result + ) + + def test_reorder_bits_fewer_qubits(self): + qubit_list = ["Q2", "Q1"] + qubit_msmt_res = [1, 0] + expected_result = [0, 1] + self.assertEqual( + reorder_bits(qubit_list, qubit_msmt_res, Ascending=True), expected_result + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/unittest/test_backends.py b/unittest/test_backends.py deleted file mode 100644 index a088519ac0181a328219286171b3b7e7a113838b..0000000000000000000000000000000000000000 --- a/unittest/test_backends.py +++ /dev/null @@ -1,179 +0,0 @@ -from quingo.backend.pyqcisim_tequila import PyQCISim_tequila -from quingo.backend.pyqcisim_quantumsim import PyQCISim_quantumsim -from quingo.backend.symqc import IfSymQC -from quingo.backend.backend_hub import BackendType, Backend_hub -from quingo.backend.qisa import Qisa -from quingo.core.exe_config import * -from pathlib import Path -import threading -import random -from global_config import SRC_PATH - -cur_dir = SRC_PATH / "unittest" / "" -qcis_fn = cur_dir / "test_qcis" / "bell.qcis" -qcis_fn2 = cur_dir / "test_qcis" / "bell_copy.qcis" -quiet_fn = cur_dir / "test_qcis" / "bell.qi" -quiet_fn2 = cur_dir / "test_qcis" / "bell_copy.qi" - - -def dist(a, b): - if isinstance(a, complex) and isinstance(b, complex): - return (a.real - b.real) ** 2 + (a.imag - b.imag) ** 2 - else: - return (a.evalf() - b.evalf()) ** 2 - - -# progress: 2023-10-09 -# finished test on quantumsim and Tequila. -class Test_backends: - def test_basic(self): - def single(BackendClass, type, qisa, is_sim): - sim = BackendClass() - assert sim.get_type() == type - assert sim.get_qisa() == qisa - assert sim.is_simulator() == is_sim - - # QuaLeSim_tequila and QuaLeSim_quantumsim default Qisa type is QCIS - # single(QuaLeSim_tequila, BackendType.QUALESIM_TEQUILA, Qisa.QCIS, True) - # single(QuaLeSim_quantumsim, BackendType.QUALESIM_QUANTUMSIM, Qisa.QCIS, True) - single(PyQCISim_tequila, BackendType.TEQUILA, Qisa.QCIS, True) - single(PyQCISim_quantumsim, BackendType.QUANTUM_SIM, Qisa.QCIS, True) - single(IfSymQC, BackendType.SYMQC, Qisa.QCIS, True) - - def test_upload_program(self): - def single(BackendClass, qasm_fn): - sim = BackendClass() - try: - sim.upload_program(qasm_fn) - except Exception as e: - assert False, "upload_program failed: {}".format(e) - - # single(QuaLeSim_tequila, qcis_fn) - # single(QuaLeSim_tequila, quiet_fn) - # single(QuaLeSim_quantumsim, qcis_fn) - # single(QuaLeSim_quantumsim, quiet_fn) - single(PyQCISim_tequila, qcis_fn) - single(PyQCISim_quantumsim, qcis_fn) - single(IfSymQC, qcis_fn) - - def test_execute(self): - def single(BackendClass, qasm_fn): - sim = BackendClass() - sim.upload_program(qasm_fn) - exe_config = ExeConfig(ExeMode.SimFinalResult, 10) - res = sim.execute(exe_config) - print(res) - # assert len(res) == 2 - # assert res[0] == ["Q1", "Q2"] - # assert all(v in [[0, 0], [1, 1]] for v in res[1]) - - # single(QuaLeSim_tequila, qcis_fn) - # single(QuaLeSim_quantumsim, qcis_fn) - # single(QuaLeSim_tequila, quiet_fn) - # single(QuaLeSim_quantumsim, quiet_fn) - single(PyQCISim_tequila, qcis_fn) - single(PyQCISim_quantumsim, qcis_fn) - single(IfSymQC, qcis_fn) - - def test_shots(self): - def single(BackendClass, qasm_fn): - random_vals = [3, 10, 100] - for num_rep in random_vals: - sim = BackendClass() - sim.upload_program(qasm_fn) - exe_config = ExeConfig(ExeMode.SimFinalResult, num_rep) - res = sim.execute(exe_config) - assert res[0] == ["Q1", "Q2"] - assert len(res[1]) == num_rep - assert all(v in [[0, 0], [1, 1]] for v in res[1]) - - # single(QuaLeSim_tequila, qcis_fn) - # single(QuaLeSim_quantumsim, qcis_fn) - # single(QuaLeSim_tequila, quiet_fn) - # single(QuaLeSim_quantumsim, quiet_fn) - single(PyQCISim_tequila, qcis_fn) - single(PyQCISim_quantumsim, qcis_fn) - single(IfSymQC, qcis_fn) - - def test_get_from_hub(self): - def single(backend_type, qasm_fn): - hub = Backend_hub() - sim = hub.get_instance(backend_type) - sim.upload_program(qasm_fn) - exe_config = ExeConfig(ExeMode.SimFinalResult, 10) - res = sim.execute(exe_config) - assert res[0] == ["Q1", "Q2"] - assert len(res[1]) == 10 - assert all(v in [[0, 0], [1, 1]] for v in res[1]) - - # single(BackendType.QUALESIM_TEQUILA, qcis_fn) - # single(BackendType.QUALESIM_QUANTUMSIM, qcis_fn) - # single(BackendType.QUALESIM_TEQUILA, quiet_fn) - # single(BackendType.QUALESIM_QUANTUMSIM, quiet_fn) - single(BackendType.TEQUILA, qcis_fn) - single(BackendType.QUANTUM_SIM, qcis_fn) - single(BackendType.SYMQC, qcis_fn) - - def test_state_vector(self): - def single(backend_type, qasm_fn): - hub = Backend_hub() - sim = hub.get_instance(backend_type) - sim.upload_program(qasm_fn) - exe_config = ExeConfig(ExeMode.SimStateVector) - res = sim.execute(exe_config) - a = res["quantum"][1][0] - b = res["quantum"][1][3] - - assert res["quantum"][0] == ["Q1", "Q2"] - assert dist(a, b) <= 0.01 - - # single(BackendType.QUALESIM_TEQUILA, quiet_fn2) - # single(BackendType.QUALESIM_QUANTUMSIM, quiet_fn2) - # single(BackendType.QUALESIM_TEQUILA, qcis_fn) - # single(BackendType.QUALESIM_QUANTUMSIM, qcis_fn) - single(BackendType.QUANTUM_SIM, qcis_fn2) - single(BackendType.SYMQC, qcis_fn2) - - def single_sim(backend_type, qcis_fn, exp_res): - hub = Backend_hub() - sim = hub.get_instance(backend_type) - sim.upload_program(qcis_fn) - exe_config = ExeConfig(ExeMode.SimFinalResult) - sim_result = sim.execute(exe_config) - _, msmt_res = sim_result - res = msmt_res[0] - res.reverse() - int_res = int("".join(map(str, res)), 2) - assert int_res == exp_res - - def test_sim_in_paral(self): - def single(backend_type): - qcis_2_fn = cur_dir / "test_qcis" / "mod_adder_nc_res_2.qcis" - qcis_5_fn = cur_dir / "test_qcis" / "mod_adder_nc_res_5.qcis" - - t1 = threading.Thread( - target=Test_backends.single_sim, - args=(backend_type, qcis_2_fn, 2), - ) - t2 = threading.Thread( - target=Test_backends.single_sim, - args=(backend_type, qcis_5_fn, 5), - ) - t1.start() - t2.start() - - # single(BackendType.QUALESIM_TEQUILA) - # single(BackendType.QUALESIM_QUANTUMSIM) - single(BackendType.QUANTUM_SIM) - single(BackendType.TEQUILA) - - -if __name__ == "__main__": - test = Test_backends() - # test.test_basic() - # test.test_upload_program() - # test.test_execute() - # test.test_shots() - # test.test_get_from_hub() - test.test_state_vector() - # test.test_sim_in_paral() diff --git a/unittest/test_compile_cmd.py b/unittest/test_compile_cmd.py index ff8ca7d6d6bdaba7d83ef140143c90bf2d200378..e950c9b9a6deb77a1749f04c9f233e9232947d8f 100644 --- a/unittest/test_compile_cmd.py +++ b/unittest/test_compile_cmd.py @@ -3,10 +3,10 @@ from quingo.core.quingo_task import * from pathlib import Path from quingo.core.compile import * from quingo.core.compiler_config import get_mlir_path -from global_config import SRC_PATH -cur_dir = SRC_PATH / "unittest" / "" -qu_dir = cur_dir / "test_qu" / "" +unittest_dir = Path(__file__).parent +qu_dir = unittest_dir / "test_qu" +mock_qcis_fn = unittest_dir / "mock.qcis" class TestGetMlirPath: @@ -19,22 +19,12 @@ class TestCompileCmd: def test_gen_default(self): mock_fn = qu_dir / "mock.qu" task = Quingo_task(mock_fn, "foo") + + qasm_fn = compile(task, params=(1, 2), qasm_fn=mock_qcis_fn) + mlir_path = Path(get_mlir_path()) - qasm_fn = compile( - task, - ( - 1, - 2, - ), - qasm_fn=cur_dir / "mock.qcis", - ) - cmd = compose_cl_cmd( - task, - qasm_fn, - mlir_path, - ) + cmd = compose_cl_cmd(task, qasm_fn, mlir_path) cmd_eles = cmd.split() - print(cmd_eles) assert len(cmd_eles) == 10 assert mlir_path.resolve().samefile(cmd_eles[0].strip('"')) assert cmd_eles[1] == '"{}"'.format(task.cl_entry_fn.resolve()) @@ -46,7 +36,7 @@ class TestCompileCmd: def test_compile(self): bell_fn = qu_dir / "bell.qu" - task = Quingo_task(bell_fn, "bell") + task = Quingo_task(bell_fn, "bell", debug_mode=True) qasm_fn = compile(task, ()) with qasm_fn.open("r") as f: lines = f.readlines() @@ -56,8 +46,8 @@ class TestCompileCmd: def test_compile2(self): bell_fn = qu_dir / "bell.qu" task = Quingo_task(bell_fn, "bell") - qasm_fn = compile(task, (), qasm_fn=cur_dir / "out_bell.qcis") - assert qasm_fn.samefile(cur_dir / "out_bell.qcis") + qasm_fn = compile(task, (), qasm_fn=unittest_dir / "out_bell.qcis") + assert qasm_fn.samefile(unittest_dir / "out_bell.qcis") with qasm_fn.open("r") as f: lines = f.readlines() assert lines[0].strip() == "H Q0" @@ -66,6 +56,6 @@ class TestCompileCmd: if __name__ == "__main__": # TestGetMlirPath().test_get_path() - TestCompileCmd().test_gen_default() - # TestCompileCmd().test_compile() + # TestCompileCmd().test_gen_default() + TestCompileCmd().test_compile() # TestCompileCmd().test_compile2() diff --git a/unittest/test_execution.py b/unittest/test_execution.py index f450279923a61ed7d84941c418d7d158219154ee..c24dff4c031f1220e0b4e1201e386cef9d0d6cda 100644 --- a/unittest/test_execution.py +++ b/unittest/test_execution.py @@ -1,35 +1,31 @@ from pathlib import Path -from quingo.core.manager import call, compile, execute -from quingo.core.exe_config import * -from quingo.core.quingo_task import Quingo_task -from quingo.backend.backend_hub import BackendType, Backend_hub -from global_config import SRC_PATH +from quingo import BackendType, Quingo_task, ExeConfig, ExeMode +from quingo import call, compile, execute -cur_dir = SRC_PATH / "unittest" / "" -qu_file = cur_dir / "test_qu" / "bell.qu" +unittest_dir = Path(__file__).parent +qu_file = unittest_dir / "test_qu" / "bell.qu" -class Test_execution: - def test_execute(self): - task = Quingo_task(qu_file, "bell") - num_shot = 4 - cfg = ExeConfig(ExeMode.SimFinalResult, num_shot) - qasm_fn = compile(task, params=()) - res = execute(qasm_fn, BackendType.QUANTUM_SIM, cfg) +def test_compile_execute(): + task = Quingo_task(qu_file, "bell") + num_shot = 4 + cfg = ExeConfig(ExeMode.SimShots, num_shot) + qasm_fn = compile(task, params=()) + res = execute(qasm_fn, BackendType.QUANTUM_SIM, cfg) - assert len(res[0]) == 2 - assert len(res[1]) == 4 + assert len(res[0]) == 2 + assert len(res[1]) == 4 - def test_call(self): - task = Quingo_task(qu_file, "bell") - cfg = ExeConfig(ExeMode.SimFinalResult, 4) - res = call(task, (), BackendType.QUANTUM_SIM, cfg) - assert len(res[0]) == 2 - assert len(res[1]) == 4 +def test_call(): + task = Quingo_task(qu_file, "bell") + cfg = ExeConfig(ExeMode.SimShots, 4) + res = call(task, (), BackendType.QUANTUM_SIM, cfg) + + assert len(res[0]) == 2 + assert len(res[1]) == 4 if __name__ == "__main__": - test = Test_execution() - test.test_execute() - test.test_call() + test_compile_execute() + test_call() diff --git a/unittest/test_preparation.py b/unittest/test_preparation.py index d158f5d61454f0e37a3b2cfbe1de1e962e40181b..2dccdc61aac5b63cf35ebc10c7696d4d8ca212d5 100644 --- a/unittest/test_preparation.py +++ b/unittest/test_preparation.py @@ -1,10 +1,9 @@ import pytest from quingo.core.preparation import * from pathlib import Path -from global_config import SRC_PATH -cur_dir = SRC_PATH / "unittest" / "" -qu_dir = cur_dir / "test_qu" / "" +unittest_dir = Path(__file__).parent +qu_dir = unittest_dir / "test_qu" class TestPrepareMain: diff --git a/unittest/test_qcis/bell.qi b/unittest/test_qcis/bell.qi index c41e1c52519768d2fa7460acdd1258fb91356b05..8a8cbd651d62bfb7077bbef418f4ca00bd46306b 100644 --- a/unittest/test_qcis/bell.qi +++ b/unittest/test_qcis/bell.qi @@ -1,9 +1,9 @@ .body: - func main()->(int c1, int c2): + func main() -> (int c1, int c2): qubit Q1 qubit Q2 H Q1 CNOT Q1, Q2 - measure(Q1)->c1 - measure(Q2)->c2 + measure(Q1) -> c1 + measure(Q2) -> c2 end \ No newline at end of file diff --git a/unittest/test_qcis/bell_copy.qcis b/unittest/test_qcis/bell_no_msmt.qcis similarity index 100% rename from unittest/test_qcis/bell_copy.qcis rename to unittest/test_qcis/bell_no_msmt.qcis diff --git a/unittest/test_qcis/bell_copy.qi b/unittest/test_qcis/bell_no_msmt.qi similarity index 100% rename from unittest/test_qcis/bell_copy.qi rename to unittest/test_qcis/bell_no_msmt.qi diff --git a/unittest/test_quingo_task.py b/unittest/test_quingo_task.py index 1e229cc0cfecba8c97dc2a32330f99da089c7a46..6b115547234efff0504ec432fa84998d878dd5ac 100644 --- a/unittest/test_quingo_task.py +++ b/unittest/test_quingo_task.py @@ -4,11 +4,10 @@ from quingo.backend.backend_hub import BackendType from quingo.backend.qisa import Qisa from pathlib import Path import platform -from global_config import SRC_PATH -cur_dir = SRC_PATH / "unittest" / "" -qu_dir = cur_dir / "test_qu" / "" +unittest_dir = Path(__file__).parent +qu_dir = unittest_dir / "test_qu" class TestQuingoTask: diff --git a/unittest/test_result.py b/unittest/test_result.py deleted file mode 100644 index d60f4f1c21bc671aec384073fb6fd7751f3d867e..0000000000000000000000000000000000000000 --- a/unittest/test_result.py +++ /dev/null @@ -1,76 +0,0 @@ -# from quingo.backend.qualesim_tequila import QuaLeSim_tequila -# from quingo.backend.qualesim_quantumsim import QuaLeSim_quantumsim -from quingo.backend.pyqcisim_quantumsim import PyQCISim_quantumsim -from quingo.backend.pyqcisim_tequila import PyQCISim_tequila -from quingo.backend.symqc import IfSymQC -from quingo.backend.backend_hub import BackendType, Backend_hub -from quingo.backend.qisa import Qisa -from quingo.core.exe_config import * -from pathlib import Path -import sympy -import threading -import random -from global_config import SRC_PATH - -cur_dir = SRC_PATH / "unittest" / "" -qcis_fn = cur_dir / "test_qcis" / "bell.qcis" -qcis_fn2 = cur_dir / "test_qcis" / "bell_copy.qcis" -quiet_fn = cur_dir / "test_qcis" / "bell.qi" -quiet_fn2 = cur_dir / "test_qcis" / "bell_copy.qi" - - -def is_similar_statevector(m1, m2): - if isinstance(m1, sympy.matrices.dense.MutableDenseMatrix): - m1 = [complex(i.evalf()) for i in m1] - if isinstance(m2, sympy.matrices.dense.MutableDenseMatrix): - m2 = [complex(i.evalf()) for i in m2] - dist = 0 - for i in range(len(m1)): - dist = dist + (m1[i].real - m2[i].real) ** 2 + (m1[i].imag - m2[i].imag) ** 2 - return dist <= 1e-5 - - -class Test_backends: - def test_one_shot_res(self): - def single(BackendClass, qasm_fn, num_shots): - sim = BackendClass() - sim.upload_program(qasm_fn) - exe_config = ExeConfig(ExeMode.SimFinalResult, num_shots) - res = sim.execute(exe_config) - assert isinstance(res, tuple) - assert len(res) == 2 - assert res[0] == ["Q1", "Q2"] - assert len(res[1]) == num_shots - assert all(v in [[0, 0], [1, 1]] for v in res[1]) - return res - - # res1 = single(QuaLeSim_quantumsim, qcis_fn, 10) - # res2 = single(QuaLeSim_tequila, qcis_fn, 8) - res1 = single(PyQCISim_quantumsim, qcis_fn, 10) - res2 = single(PyQCISim_tequila, qcis_fn, 8) - res3 = single(IfSymQC, qcis_fn, 1) - assert res1[0] == res2[0] - assert res2[0] == res3[0] - - def test_state_vector_res(self): - def single(BackendClass, qasm_fn): - sim = BackendClass() - sim.upload_program(qasm_fn) - exe_config = ExeConfig(ExeMode.SimStateVector) - res = sim.execute(exe_config) - print(res) - assert res["quantum"][0] == ["Q1", "Q2"] - return res - - # res1 = single(QuaLeSim_tequila, qcis_fn) - # res2 = single(QuaLeSim_quantumsim, qcis_fn) - res1 = single(PyQCISim_quantumsim, qcis_fn2) - res3 = single(IfSymQC, qcis_fn2) - # assert is_similar_statevector(res1["quantum"][1], res2["quantum"][1]) - assert is_similar_statevector(res1["quantum"][1], res3["quantum"][1]) - - -if __name__ == "__main__": - test = Test_backends() - test.test_one_shot_res() - # test.test_state_vector_res() diff --git a/unittest/test_utils.py b/unittest/test_utils.py deleted file mode 100644 index a5e1c2fc3b43b333116f5b084c0cd14a91195fc7..0000000000000000000000000000000000000000 --- a/unittest/test_utils.py +++ /dev/null @@ -1,40 +0,0 @@ -import quingo.backend.result_formatter as rf - - -class Test_result_formater: - def test_reorder_bits(self): - def single_test_case(qubit_list, str_bit_list, expected): - res = rf.reorder_bits(qubit_list, str_bit_list) - print(res) - assert res == expected - - qubit_list = ["Q1", "Q2", "Q3", "Q4"] - single_test_case(qubit_list, "0001", "0001") - single_test_case(qubit_list, "0010", "0010") - single_test_case(qubit_list, "0100", "0100") - single_test_case(qubit_list, "1000", "1000") - qubit_list = ["Q2", "Q1", "Q4", "Q3"] - single_test_case(qubit_list, "0001", "0010") - single_test_case(qubit_list, "0010", "0001") - single_test_case(qubit_list, "0100", "1000") - single_test_case(qubit_list, "1000", "0100") - qubit_list = ["Q2", "Q4", "Q3", "Q1"] - single_test_case(qubit_list, "1001", "1100") - single_test_case(qubit_list, "0001", "1000") - single_test_case(qubit_list, "0110", "0011") - single_test_case(qubit_list, "0100", "0001") - - qubit_list = ["Q3", "Q4", "Q5", "Q6", "Q7"] - single_test_case(qubit_list, "00011", "00011") - single_test_case(qubit_list, "01100", "01100") - single_test_case(qubit_list, "11000", "11000") - - qubit_list = ["Q6", "Q8", "Q2", "Q4", "Q9"] - single_test_case(qubit_list, "00011", "01001") - single_test_case(qubit_list, "01100", "10010") - single_test_case(qubit_list, "11000", "00110") - - -if __name__ == "__main__": - test = Test_result_formater() - test.test_reorder_bits()