microsoft/qdk
Publicmirrored fromhttps://github.com/microsoft/qdkAvailable
source/pip/tests-integration/utils.py
171lines · modecode
| 1 | # Copyright (c) Microsoft Corporation. |
| 2 | # Licensed under the MIT License. |
| 3 | |
| 4 | """ |
| 5 | This file is used to configure pytest for the test suite. |
| 6 | |
| 7 | - It attempts to import necessary modules from test_circuits. |
| 8 | |
| 9 | Fixtures and other configurations for pytest can be added to this file to |
| 10 | be shared across multiple test files. |
| 11 | """ |
| 12 | |
| 13 | import os |
| 14 | |
| 15 | from qsharp._native import ( |
| 16 | Interpreter, |
| 17 | TargetProfile, |
| 18 | QSharpError, |
| 19 | ) |
| 20 | |
| 21 | from typing import Optional, List |
| 22 | |
| 23 | from interop_qiskit.test_circuits import * |
| 24 | |
| 25 | try: |
| 26 | from qirrunner import run, OutputHandler |
| 27 | |
| 28 | QIR_RUNNER_AVAILABLE = True |
| 29 | except ImportError: |
| 30 | QIR_RUNNER_AVAILABLE = False |
| 31 | |
| 32 | SKIP_REASON = "QIR runner is not available" |
| 33 | |
| 34 | |
| 35 | def get_resource_dir(target_profile: TargetProfile) -> str: |
| 36 | return os.path.join( |
| 37 | os.path.dirname(__file__), "resources", str(target_profile).lower() |
| 38 | ) |
| 39 | |
| 40 | |
| 41 | def get_input_dir(target_profile: TargetProfile) -> str: |
| 42 | return os.path.join(get_resource_dir(target_profile), "input") |
| 43 | |
| 44 | |
| 45 | def get_output_dir(target_profile: TargetProfile) -> str: |
| 46 | return os.path.join(get_resource_dir(target_profile), "output") |
| 47 | |
| 48 | |
| 49 | def generate_test_outputs(target_profile: TargetProfile) -> None: |
| 50 | input_files = get_input_files(target_profile) |
| 51 | output_dir = get_output_dir(target_profile) |
| 52 | os.makedirs(output_dir, exist_ok=True) |
| 53 | |
| 54 | for file_path in input_files: |
| 55 | ll_file_path = get_output_ll_file(file_path, target_profile) |
| 56 | out_file_path = get_output_out_file(file_path, target_profile) |
| 57 | with open(file_path, "rt", encoding="utf-8") as f: |
| 58 | source = f.read() |
| 59 | qir = compile_qsharp(source, target_profile) |
| 60 | with open(ll_file_path, "wt", encoding="utf-8") as f: |
| 61 | f.write(qir) |
| 62 | output = execute_qir(ll_file_path) |
| 63 | with open(out_file_path, "wt", encoding="utf-8") as f: |
| 64 | f.write(output) |
| 65 | |
| 66 | |
| 67 | def read_file(file_name: str, target_profile: TargetProfile) -> str: |
| 68 | file_path = os.path.join(get_input_dir(target_profile), file_name) |
| 69 | with open(file_path, "rt", encoding="utf-8") as file: |
| 70 | source = file.read() |
| 71 | return source |
| 72 | |
| 73 | |
| 74 | def save_qir_to_temp_file_and_execute(qir: str) -> str: |
| 75 | |
| 76 | import tempfile |
| 77 | |
| 78 | # create a temporary file to store the qir |
| 79 | with tempfile.TemporaryDirectory() as tempdir: |
| 80 | # Create a temporary file in the temporary directory |
| 81 | with tempfile.NamedTemporaryFile( |
| 82 | dir=tempdir, delete=True, suffix=".ll" |
| 83 | ) as temp_file: |
| 84 | # You can write to the file or read from it |
| 85 | # encode the uf8 string to bytes |
| 86 | temp_file.write(qir.encode()) |
| 87 | temp_file.flush() |
| 88 | |
| 89 | actual_output = execute_qir(temp_file.name) |
| 90 | return actual_output |
| 91 | |
| 92 | |
| 93 | def assert_strings_equal_ignore_line_endings(lhs, rhs): |
| 94 | normalized_lhs = lhs.replace("\r\n", "\n") |
| 95 | normalized_rhs = rhs.replace("\r\n", "\n") |
| 96 | assert normalized_lhs == normalized_rhs |
| 97 | |
| 98 | |
| 99 | def execute_qir(file_path: str) -> str: |
| 100 | RNG_SEED = 42 |
| 101 | SHOTS = 1 |
| 102 | handler = OutputHandler() |
| 103 | run(file_path, None, SHOTS, RNG_SEED, output_fn=handler.handle) |
| 104 | return handler.get_output() |
| 105 | |
| 106 | |
| 107 | def get_interpreter( |
| 108 | target_profile: TargetProfile = TargetProfile.Unrestricted, |
| 109 | target_name: Optional[str] = None, |
| 110 | ) -> Interpreter: |
| 111 | if isinstance(target_name, str): |
| 112 | target = target_name.split(".")[0].lower() |
| 113 | if target == "ionq" or target == "rigetti": |
| 114 | target_profile = TargetProfile.Base |
| 115 | elif target == "quantinuum": |
| 116 | target_profile = TargetProfile.Adaptive_RI |
| 117 | else: |
| 118 | raise QSharpError( |
| 119 | f'target_name "{target_name}" not recognized. Please set target_profile directly.' |
| 120 | ) |
| 121 | |
| 122 | manifest_descriptor = None |
| 123 | language_features = None |
| 124 | from qsharp._fs import read_file, list_directory |
| 125 | |
| 126 | interpreter = Interpreter( |
| 127 | target_profile, |
| 128 | language_features, |
| 129 | manifest_descriptor, |
| 130 | read_file, |
| 131 | list_directory, |
| 132 | ) |
| 133 | return interpreter |
| 134 | |
| 135 | |
| 136 | def compile_qsharp( |
| 137 | source: str, |
| 138 | target_profile: TargetProfile = TargetProfile.Adaptive_RI, |
| 139 | target_name: Optional[str] = None, |
| 140 | ) -> str: |
| 141 | interpreter = get_interpreter(target_profile, target_name) |
| 142 | interpreter.interpret(source) |
| 143 | qir = interpreter.qir("Test.Main()") |
| 144 | return qir |
| 145 | |
| 146 | |
| 147 | def get_input_files(target_profile: TargetProfile) -> List[str]: |
| 148 | resources_dir = get_input_dir(target_profile) |
| 149 | input_files = [ |
| 150 | os.path.join(resources_dir, file_name) |
| 151 | for file_name in os.listdir(resources_dir) |
| 152 | if os.path.isfile(os.path.join(resources_dir, file_name)) |
| 153 | ] |
| 154 | return input_files |
| 155 | |
| 156 | |
| 157 | def get_ouput_file_basename(file_path: str, target_profile: TargetProfile) -> str: |
| 158 | file_name, _ext = os.path.splitext(file_path) |
| 159 | output_dir = get_output_dir(target_profile) |
| 160 | output_file = os.path.join(output_dir, os.path.basename(file_name)) |
| 161 | return output_file |
| 162 | |
| 163 | |
| 164 | def get_output_ll_file(file_path: str, target_profile: TargetProfile) -> str: |
| 165 | output_file = get_ouput_file_basename(file_path, target_profile) |
| 166 | return output_file + ".ll" |
| 167 | |
| 168 | |
| 169 | def get_output_out_file(file_path: str, target_profile: TargetProfile) -> str: |
| 170 | output_file = get_ouput_file_basename(file_path, target_profile) |
| 171 | return output_file + ".out" |