tensorcircuit-nightly 1.3.0.dev20250903__py3-none-any.whl → 1.3.0.dev20250904__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.

Potentially problematic release.


This version of tensorcircuit-nightly might be problematic. Click here for more details.

tensorcircuit/circuit.py CHANGED
@@ -1,5 +1,7 @@
1
1
  """
2
- Quantum circuit: the state simulator
2
+ Quantum circuit: the state simulator.
3
+ Supports qubit (dim=2) and qudit (3 <= dim <= 36) systems.
4
+ For string-encoded samples/counts, digits use 0–9A–Z where A=10, …, Z=35.
3
5
  """
4
6
 
5
7
  # pylint: disable=invalid-name
@@ -13,8 +15,8 @@ import tensornetwork as tn
13
15
 
14
16
  from . import gates
15
17
  from . import channels
16
- from .cons import backend, contractor, dtypestr, npdtype
17
- from .quantum import QuOperator, identity
18
+ from .cons import backend, contractor, dtypestr, npdtype, _ALPHABET
19
+ from .quantum import QuOperator, identity, _infer_num_sites, onehot_d_tensor
18
20
  from .simplify import _full_light_cone_cancel
19
21
  from .basecircuit import BaseCircuit
20
22
 
@@ -23,7 +25,7 @@ Tensor = Any
23
25
 
24
26
 
25
27
  class Circuit(BaseCircuit):
26
- """
28
+ r"""
27
29
  ``Circuit`` class.
28
30
  Simple usage demo below.
29
31
 
@@ -45,14 +47,18 @@ class Circuit(BaseCircuit):
45
47
  inputs: Optional[Tensor] = None,
46
48
  mps_inputs: Optional[QuOperator] = None,
47
49
  split: Optional[Dict[str, Any]] = None,
50
+ dim: Optional[int] = None,
48
51
  ) -> None:
49
- """
52
+ r"""
50
53
  Circuit object based on state simulator.
54
+ Do not use this class with d!=2 directly, use tc.QuditCircuit instead for qudit systems.
51
55
 
52
56
  :param nqubits: The number of qubits in the circuit.
53
57
  :type nqubits: int
58
+ :param dim: The local Hilbert space dimension per site. Qudit is supported for 2 <= d <= 36.
59
+ :type dim: If None, the dimension of the circuit will be `2`, which is a qubit system.
54
60
  :param inputs: If not None, the initial state of the circuit is taken as ``inputs``
55
- instead of :math:`\\vert 0\\rangle^n` qubits, defaults to None.
61
+ instead of :math:`\vert 0 \rangle^n` qubits, defaults to None.
56
62
  :type inputs: Optional[Tensor], optional
57
63
  :param mps_inputs: QuVector for a MPS like initial wavefunction.
58
64
  :type mps_inputs: Optional[QuOperator]
@@ -60,6 +66,7 @@ class Circuit(BaseCircuit):
60
66
  ``max_singular_values`` and ``max_truncation_err``.
61
67
  :type split: Optional[Dict[str, Any]]
62
68
  """
69
+ self._d = 2 if dim is None else dim
63
70
  self.inputs = inputs
64
71
  self.mps_inputs = mps_inputs
65
72
  self.split = split
@@ -70,18 +77,19 @@ class Circuit(BaseCircuit):
70
77
  "inputs": inputs,
71
78
  "mps_inputs": mps_inputs,
72
79
  "split": split,
80
+ "dim": dim,
73
81
  }
74
82
  if (inputs is None) and (mps_inputs is None):
75
- nodes = self.all_zero_nodes(nqubits)
83
+ nodes = self.all_zero_nodes(nqubits, dim=self._d)
76
84
  self._front = [n.get_edge(0) for n in nodes]
77
85
  elif inputs is not None: # provide input function
78
86
  inputs = backend.convert_to_tensor(inputs)
79
87
  inputs = backend.cast(inputs, dtype=dtypestr)
80
88
  inputs = backend.reshape(inputs, [-1])
81
89
  N = inputs.shape[0]
82
- n = int(np.log(N) / np.log(2))
90
+ n = _infer_num_sites(N, dim=self._d)
83
91
  assert n == nqubits or n == 2 * nqubits
84
- inputs = backend.reshape(inputs, [2 for _ in range(n)])
92
+ inputs = backend.reshape(inputs, [self._d for _ in range(n)])
85
93
  inputs = Gate(inputs)
86
94
  nodes = [inputs]
87
95
  self._front = [inputs.get_edge(i) for i in range(n)]
@@ -178,27 +186,14 @@ class Circuit(BaseCircuit):
178
186
 
179
187
  :param index: The index of qubit that the Z direction postselection applied on.
180
188
  :type index: int
181
- :param keep: 0 for spin up, 1 for spin down, defaults to be 0.
189
+ :param keep: the post-selected digit in {0, ..., d-1}, defaults to be 0.
182
190
  :type keep: int, optional
183
191
  """
184
192
  # normalization not guaranteed
185
- # assert keep in [0, 1]
186
- if keep < 0.5:
187
- gate = np.array(
188
- [
189
- [1.0],
190
- [0.0],
191
- ],
192
- dtype=npdtype,
193
- )
194
- else:
195
- gate = np.array(
196
- [
197
- [0.0],
198
- [1.0],
199
- ],
200
- dtype=npdtype,
201
- )
193
+ gate = np.array(
194
+ [[0.0] if _idx != keep else [1.0] for _idx in range(self._d)],
195
+ dtype=npdtype,
196
+ )
202
197
 
203
198
  mg1 = tn.Node(gate)
204
199
  mg2 = tn.Node(gate)
@@ -479,7 +474,7 @@ class Circuit(BaseCircuit):
479
474
  if get_gate_from_index is None:
480
475
  raise ValueError("no `get_gate_from_index` implementation is provided")
481
476
  g = get_gate_from_index(r, kraus)
482
- g = backend.reshape(g, [2 for _ in range(sites * 2)])
477
+ g = backend.reshape(g, [self._d for _ in range(sites * 2)])
483
478
  self.any(*index, unitary=g, name=name) # type: ignore
484
479
  return r
485
480
 
@@ -680,7 +675,7 @@ class Circuit(BaseCircuit):
680
675
  Apply %s quantum channel on the circuit.
681
676
  See :py:meth:`tensorcircuit.channels.%schannel`
682
677
 
683
- :param index: Qubit number that the gate applies on.
678
+ :param index: Site index that the gate applies on.
684
679
  :type index: int.
685
680
  :param status: uniform external random number between 0 and 1
686
681
  :type status: Tensor
@@ -737,8 +732,8 @@ class Circuit(BaseCircuit):
737
732
  :return: ``QuOperator`` object for the circuit unitary (open indices for the input state)
738
733
  :rtype: QuOperator
739
734
  """
740
- mps = identity([2 for _ in range(self._nqubits)])
741
- c = Circuit(self._nqubits)
735
+ mps = identity([self._d for _ in range(self._nqubits)])
736
+ c = Circuit(self._nqubits, dim=self._d)
742
737
  ns, es = self._copy()
743
738
  c._nodes = ns
744
739
  c._front = es
@@ -758,8 +753,8 @@ class Circuit(BaseCircuit):
758
753
  :return: The circuit unitary matrix
759
754
  :rtype: Tensor
760
755
  """
761
- mps = identity([2 for _ in range(self._nqubits)])
762
- c = Circuit(self._nqubits)
756
+ mps = identity([self._d for _ in range(self._nqubits)])
757
+ c = Circuit(self._nqubits, dim=self._d)
763
758
  ns, es = self._copy()
764
759
  c._nodes = ns
765
760
  c._front = es
@@ -772,6 +767,9 @@ class Circuit(BaseCircuit):
772
767
  """
773
768
  Take measurement on the given quantum lines by ``index``.
774
769
 
770
+ Return format:
771
+ - For d <= 36, the sample is a base-d string using 0–9A–Z (A=10,…).
772
+
775
773
  :Example:
776
774
 
777
775
  >>> c = tc.Circuit(3)
@@ -800,10 +798,7 @@ class Circuit(BaseCircuit):
800
798
  if i != j:
801
799
  e ^ edge2[i]
802
800
  for i in range(len(sample)):
803
- if sample[i] == "0":
804
- m = np.array([1, 0], dtype=npdtype)
805
- else:
806
- m = np.array([0, 1], dtype=npdtype)
801
+ m = onehot_d_tensor(sample[i], d=self._d)
807
802
  nodes1.append(tn.Node(m))
808
803
  nodes1[-1].get_edge(0) ^ edge1[index[i]]
809
804
  nodes2.append(tn.Node(m))
@@ -814,15 +809,13 @@ class Circuit(BaseCircuit):
814
809
  / p
815
810
  * contractor(nodes1, output_edge_order=[edge1[j], edge2[j]]).tensor
816
811
  )
817
- pu = rho[0, 0]
818
- r = backend.random_uniform([])
819
- r = backend.real(backend.cast(r, dtypestr))
820
- if r < backend.real(pu):
821
- sample += "0"
822
- p = p * pu
823
- else:
824
- sample += "1"
825
- p = p * (1 - pu)
812
+ probs = backend.real(backend.diagonal(rho))
813
+ probs /= backend.sum(probs)
814
+ outcome = backend.implicit_randc(self._d, shape=1, p=probs)
815
+
816
+ sample += _ALPHABET[outcome]
817
+ p *= float(probs[outcome])
818
+
826
819
  if with_prob:
827
820
  return sample, p
828
821
  else:
@@ -842,6 +835,10 @@ class Circuit(BaseCircuit):
842
835
  ) -> Tensor:
843
836
  """
844
837
  Compute the expectation of corresponding operators.
838
+ For qudit (d > 2),
839
+ ensure that operator tensor shapes are consistent with d (each site contributes two axes of size d).
840
+
841
+ Noise shorthand (via noise_conf) is qubit-only; for d>2, use explicit operators.
845
842
 
846
843
  :Example:
847
844
 
@@ -883,8 +880,6 @@ class Circuit(BaseCircuit):
883
880
  :return: Tensor with one element
884
881
  :rtype: Tensor
885
882
  """
886
- from .noisemodel import expectation_noisfy
887
-
888
883
  if noise_conf is None:
889
884
  # if not reuse:
890
885
  # nodes1, edge1 = self._copy()
@@ -899,6 +894,8 @@ class Circuit(BaseCircuit):
899
894
  nodes1 = _full_light_cone_cancel(nodes1)
900
895
  return contractor(nodes1).tensor
901
896
  else:
897
+ from .noisemodel import expectation_noisfy
898
+
902
899
  return expectation_noisfy(
903
900
  self,
904
901
  *ops,
@@ -919,9 +916,11 @@ def expectation(
919
916
  bra: Optional[Tensor] = None,
920
917
  conj: bool = True,
921
918
  normalization: bool = False,
919
+ dim: Optional[int] = None,
922
920
  ) -> Tensor:
923
921
  """
924
922
  Compute :math:`\\langle bra\\vert ops \\vert ket\\rangle`.
923
+ For qudit systems (d>2), ops must be reshaped with per-site axes of length d.
925
924
 
926
925
  Example 1 (:math:`bra` is same as :math:`ket`)
927
926
 
@@ -966,6 +965,8 @@ def expectation(
966
965
  :type ket: Tensor
967
966
  :param bra: :math:`bra`, defaults to None, which is the same as ``ket``.
968
967
  :type bra: Optional[Tensor], optional
968
+ :param dim: dimension of the circuit (defaults to 2)
969
+ :type dim: int, optional
969
970
  :param conj: :math:`bra` changes to the adjoint matrix of :math:`bra`, defaults to True.
970
971
  :type conj: bool, optional
971
972
  :param normalization: Normalize the :math:`ket` and :math:`bra`, defaults to False.
@@ -974,6 +975,7 @@ def expectation(
974
975
  :return: The result of :math:`\\langle bra\\vert ops \\vert ket\\rangle`.
975
976
  :rtype: Tensor
976
977
  """
978
+ dim = 2 if dim is None else dim
977
979
  if bra is None:
978
980
  bra = ket
979
981
  if isinstance(ket, QuOperator):
@@ -987,7 +989,7 @@ def expectation(
987
989
  for op, index in ops:
988
990
  if not isinstance(op, tn.Node):
989
991
  # op is only a matrix
990
- op = backend.reshape2(op)
992
+ op = backend.reshaped(op, dim)
991
993
  op = gates.Gate(op)
992
994
  if isinstance(index, int):
993
995
  index = [index]
@@ -1011,8 +1013,8 @@ def expectation(
1011
1013
  if conj is True:
1012
1014
  bra = backend.conj(bra)
1013
1015
  ket = backend.reshape(ket, [-1])
1014
- ket = backend.reshape2(ket)
1015
- bra = backend.reshape2(bra)
1016
+ ket = backend.reshaped(ket, dim)
1017
+ bra = backend.reshaped(bra, dim)
1016
1018
  n = len(backend.shape_tuple(ket))
1017
1019
  ket = Gate(ket)
1018
1020
  bra = Gate(bra)
@@ -1024,7 +1026,7 @@ def expectation(
1024
1026
  for op, index in ops:
1025
1027
  if not isinstance(op, tn.Node):
1026
1028
  # op is only a matrix
1027
- op = backend.reshape2(op)
1029
+ op = backend.reshaped(op, dim)
1028
1030
  op = gates.Gate(op)
1029
1031
  if isinstance(index, int):
1030
1032
  index = [index]
tensorcircuit/cons.py CHANGED
@@ -63,6 +63,7 @@ rdtypestr = "float32"
63
63
  npdtype = np.complex64
64
64
  backend: NumpyBackend = get_backend("numpy")
65
65
  contractor = tn.contractors.auto
66
+ _ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
66
67
  # these above lines are just for mypy, it is not very good at evaluating runtime object
67
68
 
68
69
 
@@ -17,7 +17,7 @@ from .channels import kraus_to_super_gate
17
17
  from .circuit import Circuit
18
18
  from .cons import backend, contractor, dtypestr
19
19
  from .basecircuit import BaseCircuit
20
- from .quantum import QuOperator
20
+ from .quantum import QuOperator, _infer_num_sites
21
21
 
22
22
  Gate = gates.Gate
23
23
  Tensor = Any
@@ -35,9 +35,11 @@ class DMCircuit(BaseCircuit):
35
35
  dminputs: Optional[Tensor] = None,
36
36
  mpo_dminputs: Optional[QuOperator] = None,
37
37
  split: Optional[Dict[str, Any]] = None,
38
+ dim: Optional[int] = None,
38
39
  ) -> None:
39
40
  """
40
41
  The density matrix simulator based on tensornetwork engine.
42
+ Do not use this class with d!=2 directly
41
43
 
42
44
  :param nqubits: Number of qubits
43
45
  :type nqubits: int
@@ -55,6 +57,7 @@ class DMCircuit(BaseCircuit):
55
57
  ``max_singular_values`` and ``max_truncation_err``.
56
58
  :type split: Optional[Dict[str, Any]]
57
59
  """
60
+ self._d = 2 if dim is None else dim
58
61
  if not empty:
59
62
  if (
60
63
  (inputs is None)
@@ -73,9 +76,9 @@ class DMCircuit(BaseCircuit):
73
76
  inputs = backend.cast(inputs, dtype=dtypestr)
74
77
  inputs = backend.reshape(inputs, [-1])
75
78
  N = inputs.shape[0]
76
- n = int(np.log(N) / np.log(2))
79
+ n = _infer_num_sites(N, self._d)
77
80
  assert n == nqubits
78
- inputs = backend.reshape(inputs, [2 for _ in range(n)])
81
+ inputs = backend.reshape(inputs, [self._d for _ in range(n)])
79
82
  inputs_gate = Gate(inputs)
80
83
  self._nodes = [inputs_gate]
81
84
  self.coloring_nodes(self._nodes)
@@ -94,7 +97,9 @@ class DMCircuit(BaseCircuit):
94
97
  elif dminputs is not None:
95
98
  dminputs = backend.convert_to_tensor(dminputs)
96
99
  dminputs = backend.cast(dminputs, dtype=dtypestr)
97
- dminputs = backend.reshape(dminputs, [2 for _ in range(2 * nqubits)])
100
+ dminputs = backend.reshape(
101
+ dminputs, [self._d for _ in range(2 * nqubits)]
102
+ )
98
103
  dminputs_gate = Gate(dminputs)
99
104
  nodes = [dminputs_gate]
100
105
  self._front = [dminputs_gate.get_edge(i) for i in range(2 * nqubits)]
@@ -217,7 +222,7 @@ class DMCircuit(BaseCircuit):
217
222
  dd = dmc.densitymatrix()
218
223
  circuits.append(dd)
219
224
  tensor = reduce(add, circuits)
220
- tensor = backend.reshape(tensor, [2 for _ in range(2 * self._nqubits)])
225
+ tensor = backend.reshaped(tensor, d=self._d)
221
226
  self._nodes = [Gate(tensor)]
222
227
  dangling = [e for e in self._nodes[0]]
223
228
  self._front = dangling
@@ -255,7 +260,7 @@ class DMCircuit(BaseCircuit):
255
260
  t = contractor(nodes, output_edge_order=d_edges)
256
261
  else:
257
262
  t = nodes[0]
258
- dm = backend.reshape(t.tensor, shape=[2**self._nqubits, 2**self._nqubits])
263
+ dm = backend.reshapem(t.tensor)
259
264
  if check:
260
265
  self.check_density_matrix(dm)
261
266
  return dm
@@ -274,7 +279,7 @@ class DMCircuit(BaseCircuit):
274
279
  dm = self.densitymatrix()
275
280
  e, v = backend.eigh(dm)
276
281
  np.testing.assert_allclose(
277
- e[:-1], backend.zeros([2**self._nqubits - 1]), atol=1e-5
282
+ e[:-1], backend.zeros([self._d**self._nqubits - 1]), atol=1e-5
278
283
  )
279
284
  return v[:, -1]
280
285
 
@@ -375,7 +380,7 @@ class DMCircuit2(DMCircuit):
375
380
  # index = [index[0] for _ in range(len(kraus))]
376
381
  super_op = kraus_to_super_gate(kraus)
377
382
  nlegs = 4 * len(index)
378
- super_op = backend.reshape(super_op, [2 for _ in range(nlegs)])
383
+ super_op = backend.reshape(super_op, [self._d for _ in range(nlegs)])
379
384
  super_op = Gate(super_op)
380
385
  o2i = int(nlegs / 2)
381
386
  r2l = int(nlegs / 4)
tensorcircuit/gates.py CHANGED
@@ -34,6 +34,12 @@ one_state = np.array([0.0, 1.0], dtype=npdtype)
34
34
  plus_state = 1.0 / np.sqrt(2) * (zero_state + one_state)
35
35
  minus_state = 1.0 / np.sqrt(2) * (zero_state - one_state)
36
36
 
37
+ # Common elements as np.ndarray objects
38
+ _i00 = np.array([[1.0, 0.0], [0.0, 0.0]])
39
+ _i01 = np.array([[0.0, 1.0], [0.0, 0.0]])
40
+ _i10 = np.array([[0.0, 0.0], [1.0, 0.0]])
41
+ _i11 = np.array([[0.0, 0.0], [0.0, 1.0]])
42
+
37
43
  # Common single qubit gates as np.ndarray objects
38
44
  _h_matrix = 1 / np.sqrt(2) * np.array([[1.0, 1.0], [1.0, -1.0]])
39
45
  _i_matrix = np.array([[1.0, 0.0], [0.0, 1.0]])
@@ -229,7 +235,7 @@ def num_to_tensor(*num: Union[float, Tensor], dtype: Optional[str] = None) -> An
229
235
  # TODO(@YHPeter): fix __doc__ for same function with different names
230
236
 
231
237
  l = []
232
- if not dtype:
238
+ if dtype is None:
233
239
  dtype = dtypestr
234
240
  for n in num:
235
241
  if not backend.is_tensor(n):
@@ -245,7 +251,7 @@ array_to_tensor = num_to_tensor
245
251
 
246
252
 
247
253
  def gate_wrapper(m: Tensor, n: Optional[str] = None) -> Gate:
248
- if not n:
254
+ if n is None:
249
255
  n = "unknowngate"
250
256
  m = m.astype(npdtype)
251
257
  return Gate(deepcopy(m), name=n)
@@ -255,7 +261,7 @@ class GateF:
255
261
  def __init__(
256
262
  self, m: Tensor, n: Optional[str] = None, ctrl: Optional[List[int]] = None
257
263
  ):
258
- if not n:
264
+ if n is None:
259
265
  n = "unknowngate"
260
266
  self.m = m
261
267
  self.n = n
@@ -310,7 +316,7 @@ class GateF:
310
316
 
311
317
  return Gate(cu, name="c" + self.n)
312
318
 
313
- if not self.ctrl:
319
+ if self.ctrl is None:
314
320
  ctrl = [1]
315
321
  else:
316
322
  ctrl = [1] + self.ctrl
@@ -330,7 +336,7 @@ class GateF:
330
336
  # TODO(@refraction-ray): ctrl convention to be finally determined
331
337
  return Gate(ocu, name="o" + self.n)
332
338
 
333
- if not self.ctrl:
339
+ if self.ctrl is None:
334
340
  ctrl = [0]
335
341
  else:
336
342
  ctrl = [0] + self.ctrl
@@ -349,7 +355,7 @@ class GateVF(GateF):
349
355
  n: Optional[str] = None,
350
356
  ctrl: Optional[List[int]] = None,
351
357
  ):
352
- if not n:
358
+ if n is None:
353
359
  n = "unknowngate"
354
360
  self.f = f
355
361
  self.n = n
@@ -483,7 +489,7 @@ def phase_gate(theta: float = 0) -> Gate:
483
489
  :rtype: Gate
484
490
  """
485
491
  theta = array_to_tensor(theta)
486
- i00, i11 = array_to_tensor(np.array([[1, 0], [0, 0]]), np.array([[0, 0], [0, 1]]))
492
+ i00, i11 = array_to_tensor(_i00, _i11)
487
493
  unitary = i00 + backend.exp(1.0j * theta) * i11
488
494
  return Gate(unitary)
489
495
 
@@ -512,7 +518,7 @@ def get_u_parameter(m: Tensor) -> Tuple[float, float, float]:
512
518
  return theta, phi, lbd
513
519
 
514
520
 
515
- def u_gate(theta: float = 0, phi: float = 0, lbd: float = 0) -> Gate:
521
+ def u_gate(theta: float = 0.0, phi: float = 0.0, lbd: float = 0.0) -> Gate:
516
522
  r"""
517
523
  IBMQ U gate following the converntion of OpenQASM3.0.
518
524
  See `OpenQASM doc <https://openqasm.com/language/gates.html#built-in-gates>`_
@@ -533,12 +539,7 @@ def u_gate(theta: float = 0, phi: float = 0, lbd: float = 0) -> Gate:
533
539
  :rtype: Gate
534
540
  """
535
541
  theta, phi, lbd = array_to_tensor(theta, phi, lbd)
536
- i00, i01, i10, i11 = array_to_tensor(
537
- np.array([[1, 0], [0, 0]]),
538
- np.array([[0, 1], [0, 0]]),
539
- np.array([[0, 0], [1, 0]]),
540
- np.array([[0, 0], [0, 1]]),
541
- )
542
+ i00, i01, i10, i11 = array_to_tensor(_i00, _i01, _i10, _i11)
542
543
  unitary = (
543
544
  backend.cos(theta / 2) * i00
544
545
  - backend.exp(1.0j * lbd) * backend.sin(theta / 2) * i01
@@ -548,7 +549,7 @@ def u_gate(theta: float = 0, phi: float = 0, lbd: float = 0) -> Gate:
548
549
  return Gate(unitary)
549
550
 
550
551
 
551
- def r_gate(theta: float = 0, alpha: float = 0, phi: float = 0) -> Gate:
552
+ def r_gate(theta: float = 0.0, alpha: float = 0.0, phi: float = 0.0) -> Gate:
552
553
  r"""
553
554
  General single qubit rotation gate
554
555
 
@@ -582,7 +583,7 @@ def r_gate(theta: float = 0, alpha: float = 0, phi: float = 0) -> Gate:
582
583
  # r = r_gate
583
584
 
584
585
 
585
- def rx_gate(theta: float = 0) -> Gate:
586
+ def rx_gate(theta: float = 0.0) -> Gate:
586
587
  r"""
587
588
  Rotation gate along :math:`x` axis.
588
589
 
@@ -603,7 +604,7 @@ def rx_gate(theta: float = 0) -> Gate:
603
604
  # rx = rx_gate
604
605
 
605
606
 
606
- def ry_gate(theta: float = 0) -> Gate:
607
+ def ry_gate(theta: float = 0.0) -> Gate:
607
608
  r"""
608
609
  Rotation gate along :math:`y` axis.
609
610
 
@@ -624,7 +625,7 @@ def ry_gate(theta: float = 0) -> Gate:
624
625
  # ry = ry_gate
625
626
 
626
627
 
627
- def rz_gate(theta: float = 0) -> Gate:
628
+ def rz_gate(theta: float = 0.0) -> Gate:
628
629
  r"""
629
630
  Rotation gate along :math:`z` axis.
630
631
 
@@ -645,7 +646,7 @@ def rz_gate(theta: float = 0) -> Gate:
645
646
  # rz = rz_gate
646
647
 
647
648
 
648
- def rgate_theoretical(theta: float = 0, alpha: float = 0, phi: float = 0) -> Gate:
649
+ def rgate_theoretical(theta: float = 0.0, alpha: float = 0.0, phi: float = 0.0) -> Gate:
649
650
  r"""
650
651
  Rotation gate implemented by matrix exponential. The output is the same as `rgate`.
651
652
 
@@ -723,7 +724,7 @@ def iswap_gate(theta: float = 1.0) -> Gate:
723
724
  # iswap = iswap_gate
724
725
 
725
726
 
726
- def cr_gate(theta: float = 0, alpha: float = 0, phi: float = 0) -> Gate:
727
+ def cr_gate(theta: float = 0.0, alpha: float = 0.0, phi: float = 0.0) -> Gate:
727
728
  r"""
728
729
  Controlled rotation gate. When the control qubit is 1, `rgate` is applied to the target qubit.
729
730
 
@@ -775,7 +776,7 @@ def random_two_qubit_gate() -> Gate:
775
776
  return Gate(deepcopy(unitary), name="R2Q")
776
777
 
777
778
 
778
- def any_gate(unitary: Tensor, name: str = "any") -> Gate:
779
+ def any_gate(unitary: Tensor, name: str = "any", dim: Optional[int] = None) -> Gate:
779
780
  """
780
781
  Note one should provide the gate with properly reshaped.
781
782
 
@@ -783,6 +784,8 @@ def any_gate(unitary: Tensor, name: str = "any") -> Gate:
783
784
  :type unitary: Tensor
784
785
  :param name: The name of the gate.
785
786
  :type name: str
787
+ :param dim: The dimension of the gate.
788
+ :type dim: int
786
789
  :return: the resulted gate
787
790
  :rtype: Gate
788
791
  """
@@ -791,7 +794,10 @@ def any_gate(unitary: Tensor, name: str = "any") -> Gate:
791
794
  unitary.tensor = backend.cast(unitary.tensor, dtypestr)
792
795
  return unitary
793
796
  unitary = backend.cast(unitary, dtypestr)
794
- unitary = backend.reshape2(unitary)
797
+ if dim is None or dim == 2:
798
+ unitary = backend.reshape2(unitary)
799
+ else:
800
+ unitary = backend.reshaped(unitary, dim)
795
801
  # nleg = int(np.log2(backend.sizen(unitary)))
796
802
  # unitary = backend.reshape(unitary, [2 for _ in range(nleg)])
797
803
  return Gate(unitary, name=name)