Coverage for /home/runner/work/tket/tket/pytket/pytket/circuit/__init__.py: 96%

76 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-11 07:40 +0000

1# Copyright Quantinuum 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14 

15"""The circuit module provides an API to interact with the 

16tket :py:class:`~.Circuit` data structure. 

17This module is provided in binary form during the PyPI installation.""" 

18 

19from collections.abc import Callable, Sequence 

20from typing import ( 

21 Any, 

22 Optional, 

23 Union, 

24) 

25 

26from pytket import wasm 

27from pytket._tket.circuit import * 

28from pytket._tket.circuit import Circuit 

29from pytket._tket.pauli import Pauli 

30from pytket._tket.unit_id import * 

31 

32# prefixes for assertion bits 

33from pytket._tket.unit_id import ( 

34 _DEBUG_ONE_REG_PREFIX, 

35 _DEBUG_ZERO_REG_PREFIX, 

36 Bit, 

37 BitRegister, 

38) 

39 

40from .clexpr import wired_clexpr_from_logic_exp 

41from .logic_exp import ( 

42 BinaryOp, 

43 LogicExp, 

44 Ops, 

45 if_bit, 

46 if_not_bit, 

47 reg_eq, 

48 reg_geq, 

49 reg_gt, 

50 reg_leq, 

51 reg_lt, 

52 reg_neq, 

53) 

54 

55 

56def add_wasm( # noqa: PLR0913 

57 self: Circuit, 

58 funcname: str, 

59 filehandler: wasm.WasmModuleHandler, 

60 list_i: Sequence[int], 

61 list_o: Sequence[int], 

62 args: Union[Sequence[int], Sequence[Bit]], # noqa: UP007 

63 args_wasm: Sequence[int] | None = None, 

64 **kwargs: Any, 

65) -> Circuit: 

66 """Add a classical function call from a wasm file to the circuit. 

67 \n\n:param funcname: name of the function that is called 

68 \n:param filehandler: wasm file or module handler to identify the wasm module 

69 \n:param list_i: list of the number of bits in the input variables 

70 \n:param list_o: list of the number of bits in the output variables 

71 \n:param args: vector of circuit bits the wasm op should be added to 

72 \n:param args_wasm: vector of wasmstates the wasm op should be added to 

73 \n:param kwargs: additional arguments passed to `add_gate_method` . 

74 Allowed parameters are `opgroup`, `condition` , `condition_bits`, 

75 `condition_value` 

76 \n:return: the new :py:class:`Circuit`""" 

77 

78 if args_wasm is None: 

79 args_wasm = [0] 

80 

81 for x in list_i: 

82 if x > filehandler._int_size: # noqa: SLF001 

83 raise ValueError( 

84 f"only functions with i{filehandler._int_size} type are allowed" # noqa: SLF001 

85 ) 

86 

87 for x in list_o: 

88 if x > filehandler._int_size: # noqa: SLF001 

89 raise ValueError( 

90 f"only functions with i{filehandler._int_size} type are allowed" # noqa: SLF001 

91 ) 

92 

93 if filehandler.check_function(funcname, len(list_i), len(list_o)): 

94 if (len(args_wasm)) > 0: 94 ↛ 96line 94 didn't jump to line 96 because the condition on line 94 was always true

95 self._add_w_register(max(args_wasm) + 1) 

96 return self._add_wasm( 

97 funcname, str(filehandler), list_i, list_o, args, args_wasm, **kwargs 

98 ) 

99 

100 raise ValueError(f"{funcname} not found, check {filehandler!r}") 

101 

102 

103setattr(Circuit, "add_wasm", add_wasm) # noqa: B010 

104 

105 

106def add_wasm_to_reg( # noqa: PLR0913 

107 self: Circuit, 

108 funcname: str, 

109 filehandler: wasm.WasmModuleHandler, 

110 list_i: Sequence[BitRegister], 

111 list_o: Sequence[BitRegister], 

112 args_wasm: Sequence[int] | None = None, 

113 **kwargs: Any, 

114) -> Circuit: 

115 """Add a classical function call from a wasm file to the circuit. 

116 \n\n:param funcname: name of the function that is called 

117 \n:param filehandler: wasm file or module handler to identify the wasm module 

118 \n:param list_i: list of the classical registers assigned to 

119 the input variables of the function call 

120 \n:param list_o: list of the classical registers assigned to 

121 the output variables of the function call 

122 \n:param args_wasm: vector of wasmstates the wasm op should be added to 

123 \n:param kwargs: additional arguments passed to `add_gate_method` . 

124 Allowed parameters are `opgroup`, `condition` , `condition_bits`, 

125 `condition_value` 

126 \n:return: the new :py:class:`Circuit`""" 

127 

128 if args_wasm is None: 128 ↛ 131line 128 didn't jump to line 131 because the condition on line 128 was always true

129 args_wasm = [0] 

130 

131 if filehandler.checked: 

132 for reg in list_i: 

133 if reg.size > 32: # noqa: PLR2004 

134 raise ValueError( 

135 """wasm is only supporting 32 bit size registers, 

136please use only registers of at most 32 bits""" 

137 ) 

138 

139 for reg in list_o: 

140 if reg.size > 32: # noqa: PLR2004 140 ↛ 141line 140 didn't jump to line 141 because the condition on line 140 was never true

141 raise ValueError( 

142 """wasm is only supporting 32 bit size registers, 

143please use only registers of at most 32 bits""" 

144 ) 

145 

146 # If the filehandler has not been checked we allow it to 

147 # be added without checking the function arity. 

148 if not filehandler.checked or filehandler.check_function( 

149 funcname, len(list_i), len(list_o) 

150 ): 

151 if (len(args_wasm)) > 0: 151 ↛ 153line 151 didn't jump to line 153 because the condition on line 151 was always true

152 self._add_w_register(max(args_wasm) + 1) 

153 return self._add_wasm( 

154 funcname, str(filehandler), list_i, list_o, args_wasm, **kwargs 

155 ) 

156 

157 raise ValueError(f"{funcname} not found, check {filehandler!r}") 

158 

159 

160setattr(Circuit, "add_wasm_to_reg", add_wasm_to_reg) # noqa: B010 

161 

162 

163def set_rng_seed(self: Circuit, creg: BitRegister, **kwargs: Any) -> Circuit: 

164 """Seed an RNG from the contents of a classical register. 

165 

166 The classical register must be exactly 64 bits. 

167 

168 :param creg: register of classical bits 

169 :param kwargs: additional arguments passed to `add_gate_method` (allowed parameters 

170 are `opgroup`, `condition` , `condition_bits` and `condition_value`) 

171 :return: the new :py:class:`Circuit` 

172 """ 

173 self._add_r_register(1) 

174 if creg.size != 64: # noqa: PLR2004 

175 raise ValueError( 

176 f"Register passed to `set_rng_seed()` has size {creg.size} (should be 64)" 

177 ) 

178 return self._set_rng_seed(creg, 0, **kwargs) 

179 

180 

181setattr(Circuit, "set_rng_seed", set_rng_seed) # noqa: B010 

182 

183 

184def set_rng_bound(self: Circuit, creg: BitRegister, **kwargs: Any) -> Circuit: 

185 """Set an RNG upper bound from the contents of a classical register. 

186 

187 The classical register must be exactly 32 bits. It encodes the upper bound in 

188 little-endian binary (least significant bit first). The bound is inclusive. 

189 

190 :param creg: register of classical bits 

191 :param kwargs: additional arguments passed to `add_gate_method` (allowed parameters 

192 are `opgroup`, `condition` , `condition_bits` and `condition_value`) 

193 :return: the new :py:class:`Circuit` 

194 """ 

195 self._add_r_register(1) 

196 if creg.size != 32: # noqa: PLR2004 

197 raise ValueError( 

198 f"Register passed to `set_rng_bound()` has size {creg.size} (should be 32)" 

199 ) 

200 return self._set_rng_bound(creg, 0, **kwargs) 

201 

202 

203setattr(Circuit, "set_rng_bound", set_rng_bound) # noqa: B010 

204 

205 

206def set_rng_index(self: Circuit, creg: BitRegister, **kwargs: Any) -> Circuit: 

207 """Set an RNG stream index from the contents of a classical register. 

208 

209 The classical register must be exactly 32 bits. It encodes the index in little- 

210 endian binary (least significant bit first). 

211 

212 :param creg: register of classical bits 

213 :param kwargs: additional arguments passed to `add_gate_method` (allowed parameters 

214 are `opgroup`, `condition` , `condition_bits` and `condition_value`) 

215 :return: the new :py:class:`Circuit` 

216 """ 

217 self._add_r_register(1) 

218 if creg.size != 32: # noqa: PLR2004 

219 raise ValueError( 

220 f"Register passed to `set_rng_bound()` has size {creg.size} (should be 32)" 

221 ) 

222 return self._set_rng_index(creg, 0, **kwargs) 

223 

224 

225setattr(Circuit, "set_rng_index", set_rng_index) # noqa: B010 

226 

227 

228def get_rng_num(self: Circuit, creg: BitRegister, **kwargs: Any) -> Circuit: 

229 """Get RNG output into a classical register. 

230 

231 The classical register must be exactly 32 bits. After the operation it encodes the 

232 output number in little-endian binary (least significant bit first). 

233 

234 :param creg: register of classical bits 

235 :param kwargs: additional arguments passed to `add_gate_method` (allowed parameters 

236 are `opgroup`, `condition` , `condition_bits` and `condition_value`) 

237 :return: the new :py:class:`Circuit` 

238 """ 

239 self._add_r_register(1) 

240 if creg.size != 32: # noqa: PLR2004 

241 raise ValueError( 

242 f"Register passed to `get_rng_num()` has size {creg.size} (should be 32)" 

243 ) 

244 return self._get_rng_num(creg, 0, **kwargs) 

245 

246 

247setattr(Circuit, "get_rng_num", get_rng_num) # noqa: B010 

248 

249 

250def get_job_shot_num(self: Circuit, creg: BitRegister, **kwargs: Any) -> Circuit: 

251 """Get shot number into a classical register. 

252 

253 The classical register must be exactly 32 bits. After the operation it encodes the 

254 shot number in little-endian binary (least significant bit first). 

255 

256 :param creg: register of classical bits 

257 :param kwargs: additional arguments passed to `add_gate_method` (allowed parameters 

258 are `opgroup`, `condition` , `condition_bits` and `condition_value`) 

259 :return: the new :py:class:`Circuit` 

260 """ 

261 self._add_r_register(1) 

262 if creg.size != 32: # noqa: PLR2004 

263 raise ValueError( 

264 f"Register passed to `get_job_shot_num()` has size {creg.size} (should be 32)" 

265 ) 

266 return self._get_job_shot_num(creg, **kwargs) 

267 

268 

269setattr(Circuit, "get_job_shot_num", get_job_shot_num) # noqa: B010 

270 

271 

272def add_clexpr_from_logicexp( 

273 circ: Circuit, exp: LogicExp, output_bits: list[Bit], **kwargs: Any 

274) -> Circuit: 

275 """Append a :py:class:`~.ClExprOp` defined in terms of a logical expression. 

276 \n\nExample: 

277 \n>>> c = Circuit()\n>>> x_reg = c.add_c_register('x', 3)\n>>> y_reg = c.add_c_register('y', 3)\n>>> z_reg = c.add_c_register('z', 3)\n>>> c.add_clexpr_from_logicexp(x_reg | y_reg, z_reg.to_list())\n[ClExpr x[0], x[1], x[2], y[0], y[1], y[2], z[0], z[1], z[2]; ] 

278 \n:param exp: logical expression 

279 \n:param output_bits: list of bits in output 

280 \n:return: the updated circuit""" 

281 wexpr, args = wired_clexpr_from_logic_exp(exp, output_bits) 

282 circ.add_clexpr(wexpr, args, **kwargs) 

283 return circ 

284 

285 

286setattr(Circuit, "add_clexpr_from_logicexp", add_clexpr_from_logicexp) # noqa: B010