classiq 0.100.0__py3-none-any.whl → 0.102.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. classiq/__init__.py +3 -0
  2. classiq/_internals/api_wrapper.py +29 -4
  3. classiq/applications/chemistry/op_utils.py +31 -1
  4. classiq/applications/chemistry/problems.py +18 -6
  5. classiq/applications/chemistry/ucc.py +2 -2
  6. classiq/evaluators/parameter_types.py +1 -4
  7. classiq/evaluators/qmod_node_evaluators/utils.py +6 -3
  8. classiq/execution/__init__.py +11 -1
  9. classiq/execution/jobs.py +122 -5
  10. classiq/interface/_version.py +1 -1
  11. classiq/interface/exceptions.py +0 -42
  12. classiq/interface/executor/execution_request.py +1 -0
  13. classiq/interface/executor/quantum_code.py +0 -6
  14. classiq/interface/generator/generation_request.py +9 -4
  15. classiq/interface/generator/quantum_program.py +8 -36
  16. classiq/interface/helpers/model_normalizer.py +24 -0
  17. classiq/interface/helpers/text_utils.py +17 -6
  18. classiq/interface/model/invert.py +7 -0
  19. classiq/interface/model/model.py +42 -3
  20. classiq/interface/model/quantum_function_call.py +17 -5
  21. classiq/model_expansions/interpreters/base_interpreter.py +3 -2
  22. classiq/model_expansions/visitors/uncomputation_signature_inference.py +15 -38
  23. classiq/open_library/functions/__init__.py +42 -27
  24. classiq/open_library/functions/bit_operations.py +30 -0
  25. classiq/open_library/functions/modular_arithmetics.py +597 -0
  26. classiq/open_library/functions/qft_space_arithmetics.py +81 -0
  27. classiq/open_library/functions/state_preparation.py +6 -3
  28. classiq/open_library/functions/utility_functions.py +22 -3
  29. classiq/qmod/builtins/functions/exponentiation.py +2 -2
  30. classiq/qmod/builtins/operations.py +29 -4
  31. classiq/qmod/native/pretty_printer.py +15 -4
  32. classiq/qmod/pretty_print/pretty_printer.py +14 -2
  33. classiq/qmod/quantum_callable.py +8 -2
  34. classiq/qmod/quantum_expandable.py +3 -1
  35. classiq/qmod/quantum_function.py +2 -1
  36. classiq/qmod/utilities.py +7 -4
  37. classiq/synthesis_action/__init__.py +20 -0
  38. classiq/synthesis_action/actions.py +106 -0
  39. {classiq-0.100.0.dist-info → classiq-0.102.0.dist-info}/METADATA +1 -1
  40. {classiq-0.100.0.dist-info → classiq-0.102.0.dist-info}/RECORD +42 -40
  41. classiq/interface/executor/register_initialization.py +0 -36
  42. classiq/open_library/functions/modular_exponentiation.py +0 -272
  43. classiq/open_library/functions/qsvt_temp.py +0 -536
  44. {classiq-0.100.0.dist-info → classiq-0.102.0.dist-info}/WHEEL +0 -0
  45. {classiq-0.100.0.dist-info → classiq-0.102.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,597 @@
1
+ import warnings
2
+
3
+ from classiq.interface.exceptions import ClassiqDeprecationWarning
4
+
5
+ from classiq.open_library.functions.bit_operations import (
6
+ bitwise_negate,
7
+ cyclic_shift_left,
8
+ )
9
+ from classiq.open_library.functions.qft_functions import qft
10
+ from classiq.open_library.functions.qft_space_arithmetics import modular_add_qft_space
11
+ from classiq.open_library.functions.utility_functions import multiswap
12
+ from classiq.qmod.builtins.constants import SIGNED
13
+ from classiq.qmod.builtins.functions.allocation import free
14
+ from classiq.qmod.builtins.functions.standard_gates import X
15
+ from classiq.qmod.builtins.operations import (
16
+ allocate,
17
+ bind,
18
+ control,
19
+ if_,
20
+ inplace_add,
21
+ inplace_xor,
22
+ invert,
23
+ repeat,
24
+ within_apply,
25
+ )
26
+ from classiq.qmod.cparam import CInt
27
+ from classiq.qmod.qfunc import qperm
28
+ from classiq.qmod.qmod_variable import Const, Output, QArray, QBit, QNum
29
+ from classiq.qmod.symbolic import mod_inverse
30
+
31
+ # Modular Adding and Subtraction
32
+
33
+
34
+ @qperm
35
+ def modular_add_inplace(modulus: CInt, x: Const[QNum], y: QNum) -> None:
36
+ """
37
+ [Qmod Classiq-library function]
38
+
39
+ Performs the transformation |x>|y> -> |x>|(x + y mod modulus)>.
40
+ Note:
41
+ |x> and |y> should have values smaller than `modulus`.
42
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |x> and |y>.
43
+
44
+ Implementation based on: https://arxiv.org/pdf/1706.06752 Chapter 3.2 Fig 3
45
+
46
+ Args:
47
+ modulus: Classical number modulus (CInt)
48
+ x: 1st quantum number input (unsigned).
49
+ y: 2nd quantum number input (unsigned). Will hold the result after the operation.
50
+ """
51
+ # Use a carry qubit to detect a negative result after subtracting modulus (underflow)
52
+ carry = QBit()
53
+ allocate(carry)
54
+ temp: QNum = QNum("temp", y.size + 1, SIGNED, 0)
55
+ within_apply(
56
+ lambda: bind([y, carry], temp),
57
+ lambda: (
58
+ inplace_add(x, temp),
59
+ inplace_add(-modulus, temp),
60
+ ),
61
+ )
62
+ # If carry is set (negative result), add modulus back to y
63
+ control(carry, lambda: inplace_add(modulus, y))
64
+ # Update carry qubit based on comparison (y >= x after operation)
65
+ carry ^= y >= x
66
+ free(carry)
67
+
68
+
69
+ @qperm
70
+ def modular_negate_inplace(modulus: CInt, x: QNum) -> None:
71
+ """
72
+ [Qmod Classiq-library function]
73
+
74
+ Performs the transformation |x> -> |(-x mod modulus)>.
75
+ Note:
76
+ |x> should have values smaller than `modulus`.
77
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |x>.
78
+
79
+ Args:
80
+ modulus: Classical number modulus
81
+ x: Quantum number input (unsigned). Will hold the result after the operation.
82
+ """
83
+ n = x.size
84
+ neg_modulus = 2**n - modulus - 1
85
+ is_all_zeros = QBit()
86
+ allocate(is_all_zeros)
87
+ is_all_zeros ^= x == 0
88
+ control(is_all_zeros, lambda: inplace_add(modulus, x))
89
+ inplace_add(neg_modulus, x)
90
+ # If x=0, then we have neg_modulus + modulus = all ones
91
+ is_all_zeros ^= x == (2**n - 1)
92
+ bitwise_negate(x)
93
+ free(is_all_zeros)
94
+
95
+
96
+ @qperm
97
+ def modular_subtract_inplace(modulus: CInt, x: Const[QNum], y: QNum) -> None:
98
+ """
99
+ [Qmod Classiq-library function]
100
+
101
+ Performs the transformation |x>|y> -> |x>|(x - y mod modulus)>.
102
+ Note:
103
+ |x> and |y> should have values smaller than `modulus`.
104
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |x> and |y>.
105
+
106
+ Args:
107
+ modulus: Classical number modulus
108
+ x: 1st quantum number input (unsigned). Const.
109
+ y: 2nd quantum number input (unsigned). In-place target, will hold the result after the operation.
110
+ """
111
+ modular_negate_inplace(modulus, y)
112
+ modular_add_inplace(modulus, x, y)
113
+
114
+
115
+ @qperm
116
+ def modular_double_inplace(modulus: CInt, x: QNum) -> None:
117
+ """
118
+ [Qmod Classiq-library function]
119
+
120
+ Performs the transformation |x> -> |(2x mod modulus)>.
121
+ Note:
122
+ |x> should have a value smaller than `modulus`.
123
+ The modulus must be a constant odd integer.
124
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |x>.
125
+
126
+ Implementation based on: https://arxiv.org/pdf/1706.06752 Chapter 3.2 Fig 4
127
+
128
+ Args:
129
+ modulus: Classical number modulus
130
+ x: Quantum number input (unsigned). Will hold the result after the operation.
131
+ """
132
+ carry = QBit()
133
+ allocate(carry)
134
+ res_and_carry: QNum = QNum("res_and_carry", x.size + 1, SIGNED, 0)
135
+ within_apply(
136
+ lambda: bind([x, carry], res_and_carry),
137
+ lambda: (
138
+ cyclic_shift_left(res_and_carry), # holds 2*x
139
+ inplace_add(-modulus, res_and_carry),
140
+ ),
141
+ )
142
+ control(carry, lambda: inplace_add(modulus, x))
143
+ # Post-fix carry
144
+ carry ^= (x % 2) == 0
145
+ free(carry)
146
+
147
+
148
+ @qperm
149
+ def modular_add_constant_inplace(modulus: CInt, a: CInt, x: QNum) -> None:
150
+ """
151
+ [Qmod Classiq-library function]
152
+
153
+ Performs the transformation |x> -> |(x + a mod modulus)>.
154
+ Note:
155
+ |x> and `a` should have values smaller than `modulus`.
156
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |x>.
157
+
158
+ Implementation is based on the logic in: https://arxiv.org/pdf/1706.06752 Chapter 3.2 Fig 3
159
+
160
+ Args:
161
+ modulus: Classical number modulus
162
+ a: constant unsigned number input for the addition.
163
+ x: Quantum number input (unsigned). Will hold the result after the operation.
164
+ """
165
+ carry = QBit()
166
+ allocate(carry)
167
+ temp: QNum = QNum("temp", x.size + 1, SIGNED, 0)
168
+ within_apply(
169
+ lambda: bind([x, carry], temp),
170
+ lambda: (
171
+ inplace_add(a, temp),
172
+ inplace_add(-modulus, temp),
173
+ ),
174
+ )
175
+ # If carry is set, we need to add modulus back
176
+ control(carry, lambda: inplace_add(modulus, x))
177
+ carry ^= x >= a
178
+ free(carry)
179
+
180
+
181
+ # Modular Multiplication
182
+
183
+
184
+ @qperm
185
+ def modular_multiply(
186
+ modulus: CInt,
187
+ x: Const[QArray[QBit]],
188
+ y: Const[QArray[QBit]],
189
+ z: QArray[QBit],
190
+ ) -> None:
191
+ """
192
+ [Qmod Classiq-library function]
193
+ Performs the transformation |x>|y>|0> -> |x>|y>|(x*y mod modulus)>
194
+ Note:
195
+ |x>, |y> should have the same size and have values smaller than `modulus`.
196
+ The modulus must be a constant odd integer.
197
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |x> and |y>.
198
+ The output register z must be pre-allocated with the same size as x and y.
199
+ Implementation is based on the logic in: https://arxiv.org/pdf/1706.06752 Chapter 3.2 Fig 5
200
+ Args:
201
+ modulus: Classical number modulus
202
+ x: Quantum number input (unsigned), multiplicand.
203
+ y: Quantum number input (unsigned), multiplier.
204
+ z: Quantum number (unsigned), pre-allocated output variable that will hold the result.
205
+ """
206
+ n = x.len
207
+ repeat(
208
+ n,
209
+ lambda idx: [
210
+ control(x[n - idx - 1], lambda: modular_add_inplace(modulus, y, z)),
211
+ if_(idx != (n - 1), lambda: modular_double_inplace(modulus, z)),
212
+ ],
213
+ )
214
+
215
+
216
+ @qperm
217
+ def modular_square(modulus: CInt, x: Const[QArray[QBit]], z: QArray[QBit]) -> None:
218
+ """
219
+ [Qmod Classiq-library function]
220
+ Performs the transformation |x>|0> -> |x>|(x^2 mod modulus)>.
221
+ Note:
222
+ |x> should have the same size and have values smaller than `modulus`.
223
+ The modulus must be a constant odd integer.
224
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |x>.
225
+ The output register z must be pre-allocated with the same size as x.
226
+ Implementation is based on: https://arxiv.org/pdf/1706.06752 Chapter 3.2 Fig 6
227
+ Args:
228
+ modulus: Classical number modulus
229
+ x: Quantum number input (unsigned), the input to square.
230
+ z: Quantum number (unsigned), pre-allocated output variable to hold the result.
231
+ """
232
+ n = x.len
233
+ repeat(
234
+ n - 1,
235
+ lambda i: [
236
+ control(x[n - i - 1], lambda: modular_add_inplace(modulus, x, z)),
237
+ modular_double_inplace(modulus, z),
238
+ ],
239
+ )
240
+ control(x[0], lambda: modular_add_inplace(modulus, x, z))
241
+
242
+
243
+ @qperm(disable_perm_check=True)
244
+ def modular_multiply_constant(modulus: CInt, x: Const[QNum], a: CInt, y: QNum) -> None:
245
+ """
246
+ [Qmod Classiq-library function]
247
+ Performs the transformation |x>|y> -> |x>|(x * a mod modulus)>.
248
+ Note:
249
+ |x> and |y> should have values smaller than `modulus`.
250
+ The modulus must be a constant odd integer.
251
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |x> and |y>.
252
+
253
+ Args:
254
+ modulus: Classical number modulus
255
+ x: Quantum number (unsigned), input variable.
256
+ a: Classical number constant
257
+ y: Quantum number (unsigned), output variable that will hold the result.
258
+ """
259
+ x_arr: QArray[QBit] = QArray()
260
+ within_apply(
261
+ lambda: [bind(x, x_arr), qft(y)],
262
+ lambda: repeat(
263
+ count=x_arr.len,
264
+ iteration=lambda index: control(
265
+ x_arr[index],
266
+ lambda: modular_add_qft_space(modulus, (a * (2**index)) % modulus, y),
267
+ ),
268
+ ),
269
+ )
270
+
271
+
272
+ @qperm
273
+ def modular_multiply_constant_inplace(modulus: CInt, a: CInt, x: QNum) -> None:
274
+ """
275
+ [Qmod Classiq-library function]
276
+ In-place modular multiplication of x by a classical constant modulo a symbolic modulus.
277
+ Performs |x> -> |(x * a mod modulus)>.
278
+ Note:
279
+ |x> should have values smaller than `modulus`.
280
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |x>.
281
+ The constant `a` should have an inverse modulo `modulus`, i.e. gcd(a, modulus) = 1.
282
+ The constant `a` should satisfy 0 <= a < modulus.
283
+
284
+ Args:
285
+ modulus: Classical number modulus
286
+ a: Classical number constant
287
+ x: Quantum number (unsigned), in-place input/output.
288
+ """
289
+ y: QNum = QNum("y", x.size + 1)
290
+ allocate(y)
291
+ modular_multiply_constant(modulus, x, a, y)
292
+ multiswap(x, y)
293
+ invert(lambda: modular_multiply_constant(modulus, x, mod_inverse(a, modulus), y))
294
+ free(y)
295
+
296
+
297
+ @qperm
298
+ def inplace_modular_multiply(n: CInt, a: CInt, x: QArray[QBit]) -> None:
299
+ """
300
+ [Qmod Classiq-library function]
301
+
302
+ Performs multiplication of a quantum number `x` by a classical number `a` modulo classical number `n`
303
+ (Applies $x=xa \\mod n$).
304
+
305
+ Args:
306
+ n: The modulo number. Should be non-negative.
307
+ a: The classical factor. Should be non-negative.
308
+ x: The quantum factor.
309
+
310
+ Comment: It is assumed that `a` has an inverse modulo `n`
311
+ """
312
+ warnings.warn(
313
+ "Function 'inplace_modular_multiply' is deprecated. Use 'modular_multiply_constant_inplace' instead.",
314
+ ClassiqDeprecationWarning,
315
+ stacklevel=1,
316
+ )
317
+ modular_multiply_constant_inplace(n, a, x)
318
+
319
+
320
+ @qperm
321
+ def modular_exp(n: CInt, a: CInt, x: QArray[QBit], power: QArray[QBit]) -> None:
322
+ """
323
+ [Qmod Classiq-library function]
324
+ Raises a classical integer `a` to the power of a quantum number `power` modulo classical integer `n`
325
+ times a quantum number `x`. Performs $x=(a^{power} \\mod n)*x$ in-place.
326
+ (and specifically if at the input $x=1$, at the output $x=a^{power} \\mod n$).
327
+ Args:
328
+ n: The modulus number. Should be non-negative.
329
+ a: The base of the exponentiation. Should be non-negative.
330
+ x: A quantum number that multiplies the modular exponentiation and holds the output. It should be at least the size of $\\lceil \\log(n) \rceil$.
331
+ power: The power of the exponentiation.
332
+ """
333
+ warnings.warn(
334
+ "Function 'modular_exp' is deprecated. Use 'modular_exponentiate_inplace' instead.",
335
+ ClassiqDeprecationWarning,
336
+ stacklevel=1,
337
+ )
338
+ repeat(
339
+ count=power.len,
340
+ iteration=lambda index: control(
341
+ power[index],
342
+ lambda: modular_multiply_constant_inplace(n, (a ** (2**index)) % n, x),
343
+ ),
344
+ )
345
+
346
+
347
+ @qperm
348
+ def modular_exponentiate(modulus: CInt, a: CInt, x: QNum, p: QNum) -> None:
349
+ """
350
+ [Qmod Classiq-library function]
351
+
352
+ Raises a classical integer `a` to the power of a quantum number `p` modulo classical integer `modulus`
353
+ times a quantum number `x`. Performs $x=(a^{p} \\mod modulus)*x$ in-place.
354
+ (and specifically if at the input $x=1$, at the output $x=a^{p} \\mod modulus$).
355
+
356
+ Args:
357
+ modulus: The modulus number. Should be non-negative.
358
+ a: The base of the exponentiation. Should be non-negative.
359
+ x: A quantum number that multiplies the modular exponentiation and holds the output. It should be at least the size of $\\lceil \\log(modulus) \rceil$.
360
+ p: The power of the exponentiation.
361
+ """
362
+ p_arr: QArray[QBit] = QArray(length=p.size)
363
+ within_apply(
364
+ lambda: bind(p, p_arr),
365
+ lambda: repeat(
366
+ count=p_arr.len,
367
+ iteration=lambda index: control(
368
+ p_arr[index],
369
+ lambda: modular_multiply_constant_inplace(
370
+ modulus, (a ** (2**index)) % modulus, x
371
+ ),
372
+ ),
373
+ ),
374
+ )
375
+
376
+
377
+ # Helper Functions
378
+
379
+
380
+ def get_bit(number: int, index: int) -> int:
381
+ """
382
+ Returns the value (0 or 1) of the bit at the specified index in a non-negative integer number.
383
+ Index 0 is the least significant bit (LSB).
384
+ """
385
+ return (number >> index) & 1
386
+
387
+
388
+ # Montgomery representation
389
+
390
+
391
+ @qperm
392
+ def modular_to_montgomery_inplace(modulus: CInt, x: QNum) -> None:
393
+ """
394
+ [Qmod Classiq-library function]
395
+ Converts a quantum integer |x> into its Montgomery representation modulo modulus in place.
396
+ The Montgomery factor is R = 2**n, where n = x.size (the number of qubits in |x>).
397
+ This function performs the transformation |x> -> |(x * R mod modulus)>.
398
+ Note:
399
+ |x> should have values smaller than `modulus`.
400
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |x>.
401
+ The modulus must be odd so that R = 2**n is invertible modulo modulus (gcd(R, modulus) = 1).
402
+
403
+ Args:
404
+ modulus: Classical number modulus
405
+ x: Quantum number, in-place operand to convert to Montgomery form.
406
+ """
407
+ n = x.size
408
+ mont_factor = 2**n % modulus
409
+ modular_multiply_constant_inplace(modulus, mont_factor, x)
410
+
411
+
412
+ @qperm
413
+ def modular_montgomery_to_standard_inplace(modulus: CInt, x: QNum) -> None:
414
+ """
415
+ [Qmod Classiq-library function]
416
+ Converts quantum integer |x> from Montgomery representation to standard form in place modulo modulus.
417
+ The Montgomery factor is R = 2**n, where n = x.size (the number of qubits in |x>).
418
+ This function performs the transformation |x> -> |(x * R^-1 mod modulus)>.
419
+ Note:
420
+ |x> should have values smaller than `modulus`.
421
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |x>.
422
+ The modulus must be odd so that R = 2**n is invertible modulo modulus (gcd(R, modulus) = 1).
423
+
424
+ Args:
425
+ modulus: Classical number modulus
426
+ x: Quantum number, in-place operand to convert from Montgomery form.
427
+ """
428
+ n = x.size
429
+ modular_multiply_constant_inplace(modulus, mod_inverse(2**n % modulus, modulus), x)
430
+
431
+
432
+ # Modular Inverse
433
+
434
+
435
+ @qperm
436
+ def modular_inverse_inplace(modulus: CInt, v: QNum, m: Output[QArray[QBit]]) -> None:
437
+ """
438
+ [Qmod Classiq-library function]
439
+ Computes the modular inverse of a quantum number |v> modulo modulus in place, using the Kaliski algorithm.
440
+ Performs the transformation |v> -> |(v^-1 mod modulus)>.
441
+
442
+ Based on: https://arxiv.org/pdf/2302.06639 Chapter 5
443
+
444
+ Note:
445
+ |v> should have values smaller than `modulus`.
446
+ If |v> = 0, the output will be 0 (although 0 does not have an inverse modulo `modulus`).
447
+ The modulus should be prime OR at least gcd(v, modulus) = 1.
448
+ The modulus must be a constant odd integer.
449
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |v>.
450
+ The ancilla qubits m are provided as Output, will be allocated to length 2*n.
451
+
452
+ Args:
453
+ modulus: Classical number modulus
454
+ v: Quantum number, in-place operand to compute the modular inverse.
455
+ m: Output quantum array (QArray[QBit]) allocated to length 2*n (n = v.size) and used as ancilla during the algorithm.
456
+ """
457
+ n = v.size
458
+ allocate(2 * n, m)
459
+ # Convert v to Montgomery form
460
+ modular_to_montgomery_inplace(modulus, v)
461
+ u: QNum = QNum("u", n)
462
+ r: QNum = QNum("r", n + 1)
463
+ s: QNum = QNum("s", n + 1)
464
+ a: QBit = QBit()
465
+ b: QBit = QBit()
466
+ f: QBit = QBit()
467
+ allocate(u)
468
+ allocate(r)
469
+ allocate(s)
470
+ allocate(a)
471
+ allocate(b)
472
+ allocate(f)
473
+ # Initialize
474
+ u ^= modulus
475
+ r ^= 0
476
+ s ^= 1
477
+ f ^= 1
478
+ # Main loop (2*n iterations)
479
+ repeat(2 * n, lambda i: kaliski_iteration(modulus, i, v, m, u, r, s, a, b, f))
480
+ # Finalization steps
481
+ modular_rsub_inplace(2 * modulus, modulus, r)
482
+ multiswap(v, r)
483
+ m_num: QNum = QNum("m_num", 2 * n)
484
+ bind(m, m_num)
485
+ control(
486
+ m_num == 1,
487
+ stmt_block=lambda: [inplace_xor(1, s), inplace_xor(modulus, u)], # type: ignore[arg-type]
488
+ else_block=lambda: [inplace_xor(1, u), inplace_xor(modulus, s)], # type: ignore[arg-type]
489
+ )
490
+ bind(m_num, m)
491
+ modular_montgomery_to_standard_inplace(modulus, v)
492
+ # Free variables
493
+ free(u)
494
+ free(r)
495
+ free(s)
496
+ free(a)
497
+ free(b)
498
+ free(f)
499
+
500
+
501
+ @qperm
502
+ def kaliski_iteration(
503
+ modulus: CInt,
504
+ i: CInt,
505
+ v: QNum,
506
+ m: QArray[QBit],
507
+ u: QNum,
508
+ r: QNum,
509
+ s: QNum,
510
+ a: QBit,
511
+ b: QBit,
512
+ f: QBit,
513
+ ) -> None:
514
+ """
515
+ Single iteration of the Kaliski modular inverse algorithm main loop.
516
+ Based on: https://arxiv.org/pdf/2302.06639 Figure 15
517
+
518
+ Note:
519
+ Assumes the global inversion constraints (odd modulus, 1 < modulus < 2**n).
520
+ Called with 0 <= v < modulus; per-iteration ancilla bit is m[i].
521
+
522
+ Args:
523
+ modulus: Classical number modulus (CInt)
524
+ i: Loop iteration index.
525
+ v: The QNum to invert (quantum number, will be mutated).
526
+ m: Quantum array of ancilla qubits (QArray[QBit]).
527
+ u: QNum (quantum number, auxiliary for algorithm).
528
+ r: QNum (quantum number, auxiliary).
529
+ s: QNum (quantum number, auxiliary).
530
+ a: QBit (ancilla qubit)
531
+ b: QBit (ancilla qubit)
532
+ f: QBit (ancilla qubit)
533
+ """
534
+ # Step 1: Update f, m[i]
535
+ control((v == 0) & f, lambda: X(m[i]))
536
+ f ^= m[i]
537
+ # Step 2: Update a, b, m[i]
538
+ control(f & ((u % 2) == 0), lambda: X(a))
539
+ control(f & ~a & ((v % 2) == 0), lambda: X(m[i]))
540
+ b ^= a
541
+ b ^= m[i]
542
+ # Step 3: Update a, m[i]
543
+ control(
544
+ (u > v) & f & ~b,
545
+ lambda: (
546
+ X(a),
547
+ X(m[i]),
548
+ ),
549
+ )
550
+ # Step 4: Update u, v, r, s
551
+ control(
552
+ a,
553
+ lambda: (
554
+ multiswap(u, v),
555
+ multiswap(r, s),
556
+ ),
557
+ )
558
+ # Step 5: Update u, v, r, s
559
+ control(f & ~b, lambda: (inplace_add(-u, v), inplace_add(r, s)))
560
+ # Step 6: Update a, b, v, r
561
+ b ^= m[i]
562
+ b ^= a
563
+ control(f, lambda: invert(lambda: cyclic_shift_left(v)))
564
+ modular_double_inplace(2 * modulus, r)
565
+ larger_than_modulus = QBit()
566
+ allocate(larger_than_modulus)
567
+ larger_than_modulus ^= r > modulus
568
+ control(larger_than_modulus, lambda: inplace_add(-modulus, r))
569
+ control(((r % 2) == 1), lambda: X(larger_than_modulus))
570
+ free(larger_than_modulus)
571
+ control(
572
+ a,
573
+ lambda: (
574
+ multiswap(u, v),
575
+ multiswap(r, s),
576
+ ),
577
+ )
578
+ control(((s % 2) == 0), lambda: X(a))
579
+
580
+
581
+ @qperm
582
+ def modular_rsub_inplace(modulus: CInt, a: CInt, x: QNum) -> None:
583
+ """
584
+ [Qmod Classiq-library function]
585
+ Performs the in-place modular right-subtraction |x> -> |(a - x mod modulus)>.
586
+ Note:
587
+ |x> should have values smaller than `modulus`.
588
+ The modulus should satisfy 1 < modulus < 2**n, where n is the size of |x>.
589
+ The classical constant `a` should be in the range 0 <= a < modulus.
590
+
591
+ Args:
592
+ modulus: Classical number modulus
593
+ a: Classical constant to subtract from
594
+ x: Quantum number, in-place operand to perform the modular right-subtraction.
595
+ """
596
+ modular_negate_inplace(modulus, x)
597
+ modular_add_constant_inplace(modulus, a, x)
@@ -0,0 +1,81 @@
1
+ from classiq.open_library.functions.qft_functions import qft_no_swap
2
+ from classiq.qmod.builtins.classical_functions import qft_const_adder_phase
3
+ from classiq.qmod.builtins.functions.allocation import free
4
+ from classiq.qmod.builtins.functions.standard_gates import PHASE, X
5
+ from classiq.qmod.builtins.operations import (
6
+ allocate,
7
+ control,
8
+ invert,
9
+ repeat,
10
+ skip_control,
11
+ within_apply,
12
+ )
13
+ from classiq.qmod.cparam import CInt
14
+ from classiq.qmod.qfunc import qfunc, qperm
15
+ from classiq.qmod.qmod_variable import QArray, QBit
16
+
17
+
18
+ @qfunc
19
+ def _check_msb(ref: CInt, x: QArray[QBit], aux: QBit) -> None:
20
+ within_apply(
21
+ lambda: invert(lambda: qft_no_swap(x)),
22
+ lambda: control(x[0] == ref, lambda: X(aux)),
23
+ )
24
+
25
+
26
+ @qfunc
27
+ def qft_space_add_const(value: CInt, phi_b: QArray[QBit]) -> None:
28
+ """
29
+ [Qmod Classiq-library function]
30
+
31
+ Adds a constant to a quantum number (in the Fourier space) using the Quantum Fourier Transform (QFT) Adder algorithm.
32
+ Assuming that the input `phi_b` has `n` qubits, the result will be $\\phi_b+=value \\mod 2^n$.
33
+
34
+ To perform the full algorithm, use:
35
+ within_apply(lambda: QFT(phi_b), qft_space_add_const(value, phi_b))
36
+
37
+ Args:
38
+ value: The constant to add to the quantum number.
39
+ phi_b: The quantum number (at the aft space) to which the constant is added.
40
+
41
+ """
42
+ repeat(
43
+ count=phi_b.len,
44
+ iteration=lambda index: PHASE(
45
+ theta=qft_const_adder_phase(
46
+ index, value, phi_b.len # type:ignore[arg-type]
47
+ ),
48
+ target=phi_b[index],
49
+ ),
50
+ )
51
+
52
+
53
+ @qperm(disable_perm_check=True)
54
+ def modular_add_qft_space(n: CInt, a: CInt, phi_b: QArray[QBit]) -> None:
55
+ """
56
+ [Qmod Classiq-library function]
57
+
58
+ Adds a constant `a` to a quantum number `phi_b` modulo the constant `n`.
59
+ The quantum number `phi_b` is assumed to be in the QFT space.
60
+
61
+ Args:
62
+ n: The modulo number.
63
+ a: The constant to add to the quantum number.
64
+ phi_b: The quantum number to which the constant is added.
65
+
66
+ """
67
+ aux = QBit()
68
+
69
+ allocate(aux)
70
+ qft_space_add_const(a, phi_b),
71
+ skip_control(
72
+ lambda: (
73
+ invert(lambda: qft_space_add_const(n, phi_b)),
74
+ _check_msb(1, phi_b, aux),
75
+ control(aux, lambda: qft_space_add_const(n, phi_b)),
76
+ )
77
+ )
78
+ invert(lambda: qft_space_add_const(a, phi_b))
79
+ skip_control(lambda: _check_msb(0, phi_b, aux))
80
+ qft_space_add_const(a, phi_b)
81
+ free(aux)
@@ -13,8 +13,8 @@ from classiq.open_library.functions.utility_functions import (
13
13
  from classiq.qmod.builtins.functions import (
14
14
  CX,
15
15
  IDENTITY,
16
- PHASE,
17
16
  RY,
17
+ RZ,
18
18
  H,
19
19
  X,
20
20
  free,
@@ -28,6 +28,7 @@ from classiq.qmod.builtins.operations import (
28
28
  inplace_add,
29
29
  inplace_xor,
30
30
  invert,
31
+ phase,
31
32
  repeat,
32
33
  within_apply,
33
34
  )
@@ -337,10 +338,12 @@ def apply_phase_table(
337
338
  for i in range(1, len(alphas) - 1):
338
339
  gray = _graycode(i)
339
340
  next_gray = _graycode(i + 1)
340
- PHASE(alphas[gray], target[_msb(gray)])
341
+ RZ(alphas[gray], target[_msb(gray)])
341
342
  CX(target[_control_qubit(i)], target[_msb(next_gray)])
342
343
 
343
- PHASE(alphas[_graycode(len(phases) - 1)], target[target.len - 1])
344
+ RZ(alphas[_graycode(len(phases) - 1)], target[target.len - 1])
345
+ # fix the global phase:
346
+ phase(-0.5 * alphas[0])
344
347
 
345
348
 
346
349
  @qfunc