Skip to content

Commit b002796

Browse files
add circuit cop
1 parent aea9dab commit b002796

File tree

7 files changed

+31
-7
lines changed

7 files changed

+31
-7
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212

1313
- Add keras3 example showcasing integration with tc
1414

15+
- Add circuit copy method that avoid shallow copy issue `Circuit.copy()`
16+
17+
### Changed
18+
19+
- The static method `BaseCircuit.copy` is renamed as `BaseCircuit.copy_nodes`
20+
1521
## 0.10.0
1622

1723
### Added

docs/source/quickstart.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ The IR is given as a list, each element is a dict containing information on one
148148
>>> c.to_qir()
149149
[{'gate': cnot, 'index': (0, 1), 'name': 'cnot', 'split': None}, {'gate': crx, 'index': (1, 0), 'name': 'crx', 'split': None, 'parameters': {'theta': 0.2}}]
150150
151+
We can also create new copied circuit via ``c.copy()`` which internally utilize the ``qir``.
152+
151153

152154
Programming Paradigm
153155
-------------------------

tensorcircuit/abstractcircuit.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,11 @@ def append(
11721172
self.__dict__.update(newc.__dict__)
11731173
return self
11741174

1175+
def copy(self) -> "AbstractCircuit":
1176+
qir = self.to_qir()
1177+
c = type(self).from_qir(qir, self.circuit_param)
1178+
return c
1179+
11751180
def expectation(
11761181
self,
11771182
*ops: Tuple[tn.Node, List[int]],

tensorcircuit/basecircuit.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def coloring_copied_nodes(
8181
node.id = getattr(n0, "id", id(n0))
8282

8383
@staticmethod
84-
def copy(
84+
def copy_nodes(
8585
nodes: Sequence[tn.Node],
8686
dangling: Optional[Sequence[tn.Edge]] = None,
8787
conj: Optional[bool] = False,
@@ -111,7 +111,7 @@ def copy(
111111
def _copy(
112112
self, conj: Optional[bool] = False
113113
) -> Tuple[List[tn.Node], List[tn.Edge]]:
114-
return self.copy(self._nodes, self._front, conj)
114+
return self.copy_nodes(self._nodes, self._front, conj)
115115

116116
def apply_general_gate(
117117
self,
@@ -171,7 +171,7 @@ def apply_general_gate(
171171
self._front[index[0]] = n1[0]
172172
self._front[index[1]] = n2[1]
173173
if self.is_dm:
174-
[n1l, n2l], _ = self.copy([n1, n2], conj=True)
174+
[n1l, n2l], _ = self.copy_nodes([n1, n2], conj=True)
175175
n1l[1] ^ self._front[index[0] + nq]
176176
n2l[2] ^ self._front[index[1] + nq]
177177
self._nodes.append(n1l)
@@ -186,7 +186,7 @@ def apply_general_gate(
186186
self._front[index[0]] = n1[0]
187187
self._front[index[1]] = n2[1]
188188
if self.is_dm:
189-
[n1l, n2l], _ = self.copy([n1, n2], conj=True)
189+
[n1l, n2l], _ = self.copy_nodes([n1, n2], conj=True)
190190
n2l[1] ^ self._front[index[0] + nq]
191191
n1l[2] ^ self._front[index[1] + nq]
192192
self._nodes.append(n1l)
@@ -203,7 +203,7 @@ def apply_general_gate(
203203
# gate.id = id(gate)
204204
self._nodes.append(gate)
205205
if self.is_dm:
206-
lgates, _ = self.copy([gate], conj=True)
206+
lgates, _ = self.copy_nodes([gate], conj=True)
207207
lgate = lgates[0]
208208
self._nodes.append(lgate)
209209
for i, ind in enumerate(index):

tensorcircuit/densitymatrix.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def __init__(
8686
for i, n in enumerate(mps_nodes):
8787
mps_nodes[i].tensor = backend.cast(n.tensor, dtypestr) # type: ignore
8888
mps_edges = mps_inputs.out_edges + mps_inputs.in_edges
89-
self._nodes, self._front = self.copy(mps_nodes, mps_edges)
89+
self._nodes, self._front = self.copy_nodes(mps_nodes, mps_edges)
9090
self.coloring_nodes(self._nodes)
9191
self._double_nodes_front()
9292

@@ -131,7 +131,7 @@ def __init__(
131131
self._extra_qir: List[Dict[str, Any]] = []
132132

133133
def _double_nodes_front(self) -> None:
134-
lnodes, lfront = self.copy(self._nodes, self._front, conj=True)
134+
lnodes, lfront = self.copy_nodes(self._nodes, self._front, conj=True)
135135
self._front.extend(lfront)
136136
self._nodes.extend(lnodes)
137137

tensorcircuit/results/counts.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
Tensor = Any
1010
ct = Dict[str, int]
1111

12+
# TODO(@refraction-ray): merge_count
13+
1214

1315
def reverse_count(count: ct) -> ct:
1416
ncount = {}

tests/test_circuit.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,3 +1627,12 @@ def test_general_kraus_with_prob(backend):
16271627
np.testing.assert_allclose(rs[0][1], [0.25, 0.25, 0.5], atol=1e-5)
16281628
np.testing.assert_allclose(rs[1][1], [0.25, 0.25, 0.5], atol=1e-5)
16291629
np.testing.assert_allclose(tc.backend.norm(c.state()), 1, atol=1e-5)
1630+
1631+
1632+
@pytest.mark.parametrize("backend", [lf("tfb"), lf("jaxb"), lf("npb")])
1633+
def test_circuit_copy(backend):
1634+
c = tc.Circuit(2)
1635+
c.h(0)
1636+
c1 = c.copy()
1637+
c.rz(0, theta=0.1)
1638+
assert c1.gate_count() == 1

0 commit comments

Comments
 (0)