|
61 | 61 | SympySymbolAllocator, |
62 | 62 | ) |
63 | 63 | from qualtran.simulation.classical_sim import ClassicalValRetT, ClassicalValT |
| 64 | + from qualtran.simulation.tensor import DiscardInd |
64 | 65 |
|
65 | 66 |
|
66 | 67 | def _decompose_from_build_composite_bloq(bloq: 'Bloq') -> 'CompositeBloq': |
67 | 68 | from qualtran import BloqBuilder |
68 | 69 |
|
69 | 70 | bb, initial_soqs = BloqBuilder.from_signature(bloq.signature, add_registers_allowed=False) |
70 | 71 | out_soqs = bloq.build_composite_bloq(bb=bb, **initial_soqs) |
| 72 | + if not isinstance(out_soqs, dict): |
| 73 | + raise ValueError( |
| 74 | + f'{bloq}.build_composite_bloq must return a dictionary mapping right register names to output soquets.' |
| 75 | + ) |
71 | 76 | return bb.finalize(**out_soqs) |
72 | 77 |
|
73 | 78 |
|
@@ -258,21 +263,45 @@ def call_classically( |
258 | 263 | res = self.as_composite_bloq().on_classical_vals(**vals) |
259 | 264 | return tuple(res[reg.name] for reg in self.signature.rights()) |
260 | 265 |
|
261 | | - def tensor_contract(self) -> 'NDArray': |
262 | | - """Return a contracted, dense ndarray representing this bloq. |
| 266 | + def tensor_contract(self, superoperator: bool = False) -> 'NDArray': |
| 267 | + """Return a contracted, dense ndarray encoding of this bloq. |
| 268 | +
|
| 269 | + This method decomposes and flattens this bloq into a factorized CompositeBloq, |
| 270 | + turns that composite bloq into a Quimb tensor network, and contracts it into a dense |
| 271 | + ndarray. |
| 272 | +
|
| 273 | + The returned array will be 0-, 1-, 2-, or 4-dimensional with indices arranged according to the |
| 274 | + bloq's signature and the type of simulation requested via the `superoperator` flag. |
| 275 | +
|
| 276 | + If `superoperator` is set to False (the default), a pure-state tensor network will be |
| 277 | + constructed. |
| 278 | + - If `bloq` has all thru-registers, the dense tensor will be 2-dimensional with shape `(n, n)` |
| 279 | + where `n` is the number of bits in the signature. We follow the linear algebra convention |
| 280 | + and order the indices as (right, left) so the matrix-vector product can be used to evolve |
| 281 | + a state vector. |
| 282 | + - If `bloq` has all left- or all right-registers, the tensor will be 1-dimensional with |
| 283 | + shape `(n,)`. Note that we do not distinguish between 'row' and 'column' vectors in this |
| 284 | + function. |
| 285 | + - If `bloq` has no external registers, the contracted form is a 0-dimensional complex number. |
| 286 | +
|
| 287 | + If `superoperator` is set to True, an open-system tensor network will be constructed. |
| 288 | + - States result in a 2-dimensional density matrix with indices (right_forward, right_backward) |
| 289 | + or (left_forward, left_backward) depending on whether they're input or output states. |
| 290 | + - Operations result in a 4-dimensional tensor with indices (right_forward, right_backward, |
| 291 | + left_forward, left_backward). |
263 | 292 |
|
264 | | - This constructs a tensor network and then contracts it according to our registers, |
265 | | - i.e. the dangling indices. The returned array will be 0-, 1- or 2-dimensional. If it is |
266 | | - a 2-dimensional matrix, we follow the quantum computing / matrix multiplication convention |
267 | | - of (right, left) indices. |
| 293 | + Args: |
| 294 | + superoperator: If toggled to True, do an open-system simulation. This supports |
| 295 | + non-unitary operations like measurement, but is more costly and results in |
| 296 | + higher-dimension resultant tensors. |
268 | 297 | """ |
269 | 298 | from qualtran.simulation.tensor import bloq_to_dense |
270 | 299 |
|
271 | | - return bloq_to_dense(self) |
| 300 | + return bloq_to_dense(self, superoperator=superoperator) |
272 | 301 |
|
273 | 302 | def my_tensors( |
274 | 303 | self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] |
275 | | - ) -> List['qtn.Tensor']: |
| 304 | + ) -> List[Union['qtn.Tensor', 'DiscardInd']]: |
276 | 305 | """Override this method to support native quimb simulation of this Bloq. |
277 | 306 |
|
278 | 307 | This method is responsible for returning tensors corresponding to the unitary, state, or |
|
0 commit comments