Source code for unitaria.nodes.basic.projection

from typing import Sequence
import numpy as np

from unitaria.circuit import Circuit
from unitaria.subspace import Subspace
from unitaria.nodes.node import Node


[docs] class Projection(Node): """ Node representing a projection matrix Concretely, this is the identity matrix on the full state restricted to this subspaces ``subspace_from`` and ``subspace_to``. :param from: The domain of the identity matrix """ subspace_from: Subspace subspace_to: Subspace def __init__(self, subspace_from: Subspace, subspace_to: Subspace): """ Initialize a Projection node. :param subspace_from: The domain subspace. :param subspace_to: The codomain subspace. :raises ValueError: If the subspaces do not have the same number of qubits. """ super().__init__(subspace_from.dimension, subspace_to.dimension) self.subspace_from = subspace_from self.subspace_to = subspace_to if subspace_from.total_qubits != subspace_to.total_qubits: raise ValueError("Subspaces must have same number of qubits") def children(self) -> list[Node]: return [] def parameters(self) -> dict: params = {} params["subspace_from"] = self.subspace_from params["subspace_to"] = self.subspace_to return params def _subspace_in(self) -> Subspace: return self.subspace_from def _subspace_out(self) -> Subspace: return self.subspace_to def _normalization(self) -> float: return 1 def compute(self, input: np.ndarray) -> np.ndarray: outer_shape = list(input.shape[:-1]) input = input.reshape([-1, self.dimension_in]) expanded = np.zeros((input.shape[0], 2**self.subspace_in.total_qubits), dtype=np.complex128) expanded[:, self.subspace_in.enumerate_basis()] = input return expanded[:, self.subspace_out.enumerate_basis()].reshape(outer_shape + [-1]) def compute_adjoint(self, input: np.ndarray) -> np.ndarray: outer_shape = list(input.shape[:-1]) input = input.reshape([-1, self.dimension_out]) expanded = np.zeros((input.shape[0], 2**self.subspace_out.total_qubits), dtype=np.complex128) expanded[:, self.subspace_out.enumerate_basis()] = input return expanded[:, self.subspace_in.enumerate_basis()].reshape(outer_shape + [-1]) def _circuit( self, target: Sequence[int], clean_ancillae: Sequence[int], borrowed_ancillae: Sequence[int] ) -> Circuit: circuit = Circuit() circuit.n_qubits = self.subspace_from.total_qubits return circuit def clean_ancilla_count(self) -> int: return 0 def borrowed_ancilla_count(self) -> int: return 0