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

76 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-10 11:51 +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 """ 

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

68 

69 :param funcname: name of the function that is called 

70 :param filehandler: wasm file or module handler to identify the wasm module 

71 :param list_i: list of the number of bits in the input variables 

72 :param list_o: list of the number of bits in the output variables 

73 :param args: vector of circuit bits the wasm op should be added to 

74 :param args_wasm: vector of wasmstates the wasm op should be added to 

75 :param kwargs: additional arguments passed to :py:meth:`~.Circuit.add_gate`. 

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

77 `condition_value` 

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

79 """ 

80 

81 if args_wasm is None: 

82 args_wasm = [0] 

83 

84 for x in list_i: 

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

86 raise ValueError( 

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

88 ) 

89 

90 for x in list_o: 

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

92 raise ValueError( 

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

94 ) 

95 

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

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

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

99 return self._add_wasm( 

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

101 ) 

102 

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

104 

105 

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

107 

108 

109def add_wasm_to_reg( # noqa: PLR0913 

110 self: Circuit, 

111 funcname: str, 

112 filehandler: wasm.WasmModuleHandler, 

113 list_i: Sequence[BitRegister], 

114 list_o: Sequence[BitRegister], 

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

116 **kwargs: Any, 

117) -> Circuit: 

118 """ 

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

120 

121 :param funcname: name of the function that is called 

122 :param filehandler: wasm file or module handler to identify the wasm module 

123 :param list_i: list of the classical registers assigned to 

124 the input variables of the function call 

125 :param list_o: list of the classical registers assigned to 

126 the output variables of the function call 

127 :param args_wasm: vector of wasmstates the wasm op should be added to 

128 :param kwargs: additional arguments passed to :py:meth:`~.Circuit.add_gate`. 

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

130 `condition_value` 

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

132 """ 

133 

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

135 args_wasm = [0] 

136 

137 if filehandler.checked: 

138 for reg in list_i: 

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

140 raise ValueError( 

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

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

143 ) 

144 

145 for reg in list_o: 

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

147 raise ValueError( 

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

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

150 ) 

151 

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

153 # be added without checking the function arity. 

154 if not filehandler.checked or filehandler.check_function( 

155 funcname, len(list_i), len(list_o) 

156 ): 

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

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

159 return self._add_wasm( 

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

161 ) 

162 

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

164 

165 

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

167 

168 

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

170 """ 

171 Seed an RNG from the contents of a classical register. 

172 

173 The classical register must be exactly 64 bits. 

174 

175 :param creg: register of classical bits 

176 :param kwargs: additional arguments passed to :py:meth:`~.Circuit.add_gate` (allowed parameters 

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

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

179 """ 

180 self._add_r_register(1) 

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

182 raise ValueError( 

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

184 ) 

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

186 

187 

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

189 

190 

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

192 """ 

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

194 

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

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

197 

198 :param creg: register of classical bits 

199 :param kwargs: additional arguments passed to :py:meth:`~.Circuit.add_gate` (allowed parameters 

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

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

202 """ 

203 self._add_r_register(1) 

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

205 raise ValueError( 

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

207 ) 

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

209 

210 

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

212 

213 

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

215 """ 

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

217 

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

219 endian binary (least significant bit first). 

220 

221 :param creg: register of classical bits 

222 :param kwargs: additional arguments passed to :py:meth:`~.Circuit.add_gate` (allowed parameters 

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

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

225 """ 

226 self._add_r_register(1) 

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

228 raise ValueError( 

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

230 ) 

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

232 

233 

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

235 

236 

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

238 """ 

239 Get RNG output into a classical register. 

240 

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

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

243 

244 :param creg: register of classical bits 

245 :param kwargs: additional arguments passed to :py:meth:`~.Circuit.add_gate` (allowed parameters 

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

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

248 """ 

249 self._add_r_register(1) 

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

251 raise ValueError( 

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

253 ) 

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

255 

256 

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

258 

259 

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

261 """ 

262 Get shot number into a classical register. 

263 

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

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

266 

267 :param creg: register of classical bits 

268 :param kwargs: additional arguments passed to :py:meth:`~.Circuit.add_gate` (allowed parameters 

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

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

271 """ 

272 self._add_r_register(1) 

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

274 raise ValueError( 

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

276 ) 

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

278 

279 

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

281 

282 

283def add_clexpr_from_logicexp( 

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

285) -> Circuit: 

286 """ 

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

288 

289 Example: 

290 

291 >>> c = Circuit() 

292 >>> x_reg = c.add_c_register('x', 3) 

293 >>> y_reg = c.add_c_register('y', 3) 

294 >>> z_reg = c.add_c_register('z', 3) 

295 >>> c.add_clexpr_from_logicexp(x_reg | y_reg, z_reg.to_list()) 

296 [ClExpr x[0], x[1], x[2], y[0], y[1], y[2], z[0], z[1], z[2]; ] 

297 

298 :param exp: logical expression 

299 :param output_bits: list of bits in output 

300 :return: the updated circuit 

301 """ 

302 wexpr, args = wired_clexpr_from_logic_exp(exp, output_bits) 

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

304 return circ 

305 

306 

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