(
num_qubits: int,
compute_step_matrix: Callable[[Mapping[str, NumericType], float],
NDArray[numpy.complexfloating]],
tlist: Sequence[float],
schedule: Iterable[Mapping[str, NumericType]],
split_into_steps=False,
register_kraus_channel: Optional[Callable[
[str, Mapping[str, NumericType], float], None]] = None
)
| 200 | |
| 201 | # FIXME: move to C++ |
| 202 | def _evolution_kernel( |
| 203 | num_qubits: int, |
| 204 | compute_step_matrix: Callable[[Mapping[str, NumericType], float], |
| 205 | NDArray[numpy.complexfloating]], |
| 206 | tlist: Sequence[float], |
| 207 | schedule: Iterable[Mapping[str, NumericType]], |
| 208 | split_into_steps=False, |
| 209 | register_kraus_channel: Optional[Callable[ |
| 210 | [str, Mapping[str, NumericType], float], None]] = None |
| 211 | ) -> Generator[PyKernel]: |
| 212 | kernel_base_name = "".join(filter(str.isalnum, str(uuid.uuid4()))) |
| 213 | |
| 214 | def register_operations(): |
| 215 | for step_idx, parameters in enumerate(schedule): |
| 216 | # We could make operators `hashable` and try to use that to do some kernel caching, |
| 217 | # but there is no guarantee that if the hash is equal, the operator is equal. |
| 218 | # Overall it feels like a better choice to just take a `uuid` here. |
| 219 | operation_name = f"evolve_{kernel_base_name}_{step_idx}" |
| 220 | # Note: the first step is expected to be the identity matrix, i.e., initial state. |
| 221 | if step_idx == 0: |
| 222 | evolution_matrix = numpy.eye(2**num_qubits, |
| 223 | dtype=numpy.complex128) |
| 224 | register_operation(operation_name, evolution_matrix) |
| 225 | else: |
| 226 | dt = tlist[step_idx] - tlist[step_idx - 1] |
| 227 | register_operation(operation_name, |
| 228 | compute_step_matrix(parameters, dt)) |
| 229 | register_kraus_channel(operation_name, parameters, dt) |
| 230 | yield operation_name |
| 231 | |
| 232 | operation_names = register_operations() |
| 233 | |
| 234 | evolution, initial_state = make_kernel(cudaq_runtime.State) |
| 235 | qs = evolution.qalloc(initial_state) |
| 236 | for operation_name in operation_names: |
| 237 | # FIXME: `#(*qs)` causes infinite loop |
| 238 | # FIXME: It would be nice if a registered operation could take a vector of qubits? |
| 239 | targets = [qs[i] for i in range(num_qubits)] |
| 240 | evolution.__getattr__(f"{operation_name}")(*targets) |
| 241 | if split_into_steps: |
| 242 | yield evolution |
| 243 | evolution, initial_state = make_kernel(cudaq_runtime.State) |
| 244 | qs = evolution.qalloc(initial_state) |
| 245 | if not split_into_steps: |
| 246 | yield evolution |
| 247 | |
| 248 | |
| 249 | def evolve_single( |
no test coverage detected