def apply_operations(
    state: np.ndarray, qubit_count: int, operations: List[Operation]
) -> np.ndarray:
    """ Applies operations to a state vector one at a time.

    Args:
        state (np.ndarray): The state vector to apply the given operations to, as a type
            (num_qubits, 0) tensor
        qubit_count (int): The number of qubits in the state
        operations (List[Operation]): The operations to apply to the state vector

    Returns:
        np.ndarray: The state vector after applying the given operations, as a type
        (qubit_count, 0) tensor
    """
    for operation in operations:
        matrix = get_matrix(operation)
        targets = operation.targets
        # `operation` is ignored if it acts trivially on its targets
        if targets:
            state = _apply_operation(state, qubit_count, matrix, targets)
        elif targets is None:
            # `operation` is an observable, and the only element in `operations`
            for qubit in range(qubit_count):
                state = _apply_operation(state, qubit_count, matrix, (qubit,))
    return state
예제 #2
0
def _contract_operations(state: np.ndarray, qubit_count: int,
                         operations: List[Operation]) -> np.ndarray:
    contraction_parameters = [state, list(range(qubit_count))]
    index_substitutions = {i: i for i in range(qubit_count)}
    next_index = qubit_count
    for operation in operations:
        matrix = get_matrix(operation)
        targets = operation.targets

        # `operation` is not added to the contraction parameters if
        # it acts trivially on its targets
        if targets:
            # Lower indices, which will be traced out
            covariant = [index_substitutions[i] for i in targets]

            # Upper indices, which will replace the contracted indices in the state vector
            contravariant = list(range(next_index,
                                       next_index + len(covariant)))

            indices = contravariant + covariant
            # `matrix` as type-(len(contravariant), len(covariant)) tensor
            matrix_as_tensor = np.reshape(matrix, [2] * len(indices))

            contraction_parameters += [matrix_as_tensor, indices]
            next_index += len(covariant)
            index_substitutions.update(
                {targets[i]: contravariant[i]
                 for i in range(len(targets))})
        elif targets is None:
            # `operation` is an observable, and the only element in `operations`
            for qubit in range(qubit_count):
                # Since observables don't overlap,
                # there's no need to track index replacements
                contraction_parameters += [matrix, [next_index, qubit]]
                index_substitutions[qubit] = next_index
                next_index += 1

    # Ensure state is in correct order
    new_indices = [index_substitutions[i] for i in range(qubit_count)]
    contraction_parameters.append(new_indices)
    return opt_einsum.contract(*contraction_parameters)
예제 #3
0
def test_get_matrix_observable(operation):
    matrix = get_matrix(operation)
    if matrix is not None:
        assert np.allclose(matrix, operation.diagonalizing_matrix)
    else:
        assert operation.diagonalizing_matrix is None
예제 #4
0
def test_get_matrix_gate_operation(operation):
    assert np.allclose(get_matrix(operation), operation.matrix)