def test_amplitudes_and_probs_output_type(self, wf: Wavefunction):
     if len(wf.free_symbols) > 0:
         assert wf.amplitudes.dtype == object
         assert wf.probabilities().dtype == object
     else:
         assert wf.amplitudes.dtype == np.complex128
         assert wf.probabilities().dtype == np.float64
    def test_eq_returns_true_for_objects_with_equal_wavefunctions(
            self, symbolic_wf: Wavefunction, numeric_wf: Wavefunction):
        test_wf = Wavefunction(symbolic_wf._amplitude_vector)
        assert symbolic_wf == test_wf

        test_wf = Wavefunction(numeric_wf._amplitude_vector)
        np.testing.assert_array_equal(numeric_wf, test_wf)
    def test_string_output_of_numeric_wavefunction(self):
        wf = Wavefunction([1j, 0])

        wf_str = wf.__str__()

        assert "j" in wf_str
        assert wf_str.endswith("])")
        assert wf_str.startswith("Wavefunction([")
    def test_string_output_of_symbolic_wavefunction(self):
        wf = Wavefunction([Symbol("alpha"), 0])

        wf_str = wf.__str__()

        assert "alpha" in wf_str
        assert wf_str.endswith("])")
        assert wf_str.startswith("Wavefunction([")
    def test_get_outcome_probs(self, wf_vec):
        wf = Wavefunction(wf_vec)
        probs_dict = wf.get_outcome_probs()

        assert all([len(key) == wf.n_qubits for key in probs_dict.keys()])

        for key in probs_dict.keys():
            assert len(key) == wf.n_qubits

            assert wf.probabilities()[int(key, 2)] == probs_dict[key]
class TestRepresentations:
    def test_string_output_of_symbolic_wavefunction(self):
        wf = Wavefunction([Symbol("alpha"), 0])

        wf_str = wf.__str__()

        assert "alpha" in wf_str
        assert wf_str.endswith("])")
        assert wf_str.startswith("Wavefunction([")

    def test_string_output_of_numeric_wavefunction(self):
        wf = Wavefunction([1j, 0])

        wf_str = wf.__str__()

        assert "j" in wf_str
        assert wf_str.endswith("])")
        assert wf_str.startswith("Wavefunction([")

    @pytest.mark.parametrize(
        "wf",
        [Wavefunction.init_system(2),
         Wavefunction([Symbol("alpha"), 0.0])])
    def test_amplitudes_and_probs_output_type(self, wf: Wavefunction):
        if len(wf.free_symbols) > 0:
            assert wf.amplitudes.dtype == object
            assert wf.probabilities().dtype == object
        else:
            assert wf.amplitudes.dtype == np.complex128
            assert wf.probabilities().dtype == np.float64

    @pytest.mark.parametrize(
        "wf_vec",
        [
            [1.0, 0.0],
            [0.5, 0.5, 0.5, 0.5],
            [1 / sqrt(2), 0, 0, 0, 0, 0, 0, 1 / sqrt(2)],
        ],
    )
    def test_get_outcome_probs(self, wf_vec):
        wf = Wavefunction(wf_vec)
        probs_dict = wf.get_outcome_probs()

        assert all([len(key) == wf.n_qubits for key in probs_dict.keys()])

        for key in probs_dict.keys():
            assert len(key) == wf.n_qubits

            assert wf.probabilities()[int(key, 2)] == probs_dict[key]
 def test_binding_all_symbols_returns_numpy_array(
         self, symbolic_wf: Wavefunction):
     assert isinstance(
         symbolic_wf.bind({
             "alpha": 0.5,
             "beta": 0.5
         })._amplitude_vector, np.ndarray)
Example #8
0
def sample_from_wavefunction(
    wavefunction: Wavefunction,
    n_samples: int,
    seed: Optional[int] = None,
) -> List[Tuple[int, ...]]:
    """Sample bitstrings from a wavefunction.

    Args:
        wavefunction: the wavefunction to sample from.
        n_samples: the number of samples taken. Needs to be greater than 0.
        seed: the seed of the sampler

    Returns:
        List[Tuple[int]]: A list of tuples where the each tuple is a sampled bitstring.
    """
    assert isinstance(n_samples, int) and n_samples > 0
    rng = np.random.default_rng(seed)
    outcomes_str, probabilities_np = zip(
        *wavefunction.get_outcome_probs().items())
    probabilities = [
        x[0] if isinstance(x, (list, np.ndarray)) else x
        for x in list(probabilities_np)
    ]
    samples_ndarray = rng.choice(a=outcomes_str,
                                 size=n_samples,
                                 p=probabilities)
    samples = [
        tuple(int(y) for y in list(x)[::-1]) for x in list(samples_ndarray)
    ]
    return samples
def test_sample_from_wavefunction_fails_for_invalid_n_samples(n_samples):
    n_qubits = 4
    amplitudes = [0] * (2**n_qubits)
    amplitudes[1] = 1
    wavefunction = Wavefunction(amplitudes)
    with pytest.raises(AssertionError):
        sample_from_wavefunction(wavefunction, n_samples)
Example #10
0
    def get_wavefunction(
            self,
            circuit: Circuit,
            initial_state: Optional[StateVector] = None) -> Wavefunction:
        """Returns a wavefunction representing quantum state produced by a circuit

        Args:
            circuit: quantum circuit to be executed.
            initial_state: a state from which the simulation starts.
              If not provided, the default |0...0> is used.
        """
        if initial_state is None:
            state = np.zeros(2**circuit.n_qubits)
            state[0] = 1
        else:
            state = initial_state

        for is_supported, subcircuit in split_circuit(
                circuit, self.is_natively_supported):
            # Native subcircuits are passed through to the underlying simulator.
            # They also count towards number of circuits and number of jobs run.
            if is_supported:
                self.number_of_circuits_run += 1
                self.number_of_jobs_run += 1
                state = self._get_wavefunction_from_native_circuit(
                    subcircuit, state)
            else:
                for operation in subcircuit.operations:
                    state = operation.apply(state)

        return Wavefunction(state)
class TestGates:
    @pytest.fixture
    def simulator(self) -> SymbolicSimulator:
        return SymbolicSimulator()

    @pytest.mark.parametrize(
        "circuit, expected_wavefunction",
        [
            (
                Circuit([RX(Symbol("theta"))(0)]),
                Wavefunction([
                    1.0 * cos(Symbol("theta") / 2),
                    -1j * sin(Symbol("theta") / 2)
                ]),
            ),
            (
                Circuit([X(0), RY(Symbol("theta"))(0)]),
                Wavefunction([
                    -1.0 * sin(Symbol("theta") / 2),
                    1.0 * cos(Symbol("theta") / 2),
                ]),
            ),
            (
                Circuit([
                    H(0),
                    U3(Symbol("theta"), Symbol("phi"), Symbol("lambda"))(0)
                ]),
                Wavefunction([
                    cos(Symbol("theta") / 2) / sqrt(2) +
                    -exp(I * Symbol("lambda")) * sin(Symbol("theta") / 2) /
                    sqrt(2),
                    exp(I * Symbol("phi")) * sin(Symbol("theta") / 2) / sqrt(2)
                    + exp(I * (Symbol("lambda") + Symbol("phi"))) *
                    cos(Symbol("theta") / 2) / sqrt(2),
                ]),
            ),
        ],
    )
    def test_wavefunction_works_as_expected_with_symbolic_circuits(
        self,
        simulator: SymbolicSimulator,
        circuit: Circuit,
        expected_wavefunction: Wavefunction,
    ):
        returned_wavefunction = simulator.get_wavefunction(circuit)

        assert returned_wavefunction == expected_wavefunction
Example #12
0
    def _get_wavefunction_from_native_circuit(self, circuit: Circuit,
                                              initial_state) -> Wavefunction:
        state = initial_state

        for operation in circuit.operations:
            state = operation.apply(state)

        return Wavefunction(state)
def test_sample_from_wavefunction_column_vector():
    n_qubits = 4
    expected_bitstring = (0, 0, 0, 1)
    amplitudes = np.array([0] * (2**n_qubits)).reshape(2**n_qubits, 1)
    amplitudes[1] = 1  # |0001> will be measured in all cases.
    wavefunction = Wavefunction(amplitudes)
    sample = set(sample_from_wavefunction(wavefunction, 500))
    assert len(sample) == 1
    assert sample.pop() == expected_bitstring
def test_sample_from_wavefunction_list():
    n_qubits = 4
    expected_bitstring = (0, 0, 0, 1)
    amplitudes = [0] * (2**n_qubits)
    amplitudes[1] = 1  # |0001> will be measured in all cases.
    wavefunction = Wavefunction(amplitudes)
    sample = set(sample_from_wavefunction(wavefunction, 500))
    assert len(sample) == 1
    assert sample.pop() == expected_bitstring
Example #15
0
def create_random_wavefunction(n_qubits, seed=None):
    if seed:
        np.random.seed(seed)

    random_vector = [
        complex(a, b) for a, b in zip(np.random.rand(2**n_qubits),
                                      np.random.rand(2**n_qubits))
    ]
    normalization_factor = np.sqrt(np.sum(np.abs(random_vector)**2))
    random_vector /= normalization_factor

    return Wavefunction(random_vector)
Example #16
0
    def test_get_expectation_value(self):
        """Check <Z0> and <Z1> for the state |100>"""
        # Given
        wf = Wavefunction([0, 1, 0, 0, 0, 0, 0, 0])
        op1 = QubitOperator("Z0")
        op2 = QubitOperator("Z1")
        # When
        exp_op1 = get_expectation_value(op1, wf, True)
        exp_op2 = get_expectation_value(op2, wf, True)

        # Then
        self.assertAlmostEqual(-1, exp_op1)
        self.assertAlmostEqual(1, exp_op2)
    def test_init_system_returns_expected_wavefunction_size(self, n_qubits):
        wavefunction = Wavefunction.init_system(n_qubits=n_qubits)

        # Check length
        assert len(wavefunction) == 2**n_qubits

        # Check internal property
        assert wavefunction.n_qubits == n_qubits

        # Check amplitude of zero state
        assert wavefunction[0] == 1.0

        # Check amplitude of the rest of the states
        assert not np.any(wavefunction[1:])
Example #18
0
def load_wavefunction(file: LoadSource) -> Wavefunction:
    """Load a qubit wavefunction from a file.

    Args:
        file (str or file-like object): the name of the file, or a file-like object.

    Returns:
        wavefunction (zquantum.core.Wavefunction): the wavefunction object
    """

    if isinstance(file, str):
        with open(file, "r") as f:
            data = json.load(f)
    else:
        data = json.load(file)

    wavefunction = Wavefunction(convert_dict_to_array(data["amplitudes"]))
    return wavefunction
def jw_get_ground_state_at_particle_number(
        particle_number: int, qubit_operator: Union[str, SymbolicOperator]):
    """Get the ground state wavefunction of the operator for the input particle number.

    Outputs are serialized to JSON within the files: "ground-state.json" and
    "value-estimate.json".

    Args:
        particle_number: The given number of particles in the system
        qubit_operator: The operator for which to find the ground state
    """
    if isinstance(qubit_operator, str):
        qubit_operator = load_qubit_operator(qubit_operator)
    sparse_matrix = qubit_operator_sparse(qubit_operator)

    ground_energy, ground_state_amplitudes = _jw_get_ground_state_at_particle_number(
        sparse_matrix, particle_number)
    ground_state = Wavefunction(ground_state_amplitudes)
    value_estimate = ValueEstimate(ground_energy)

    save_wavefunction(ground_state, "ground-state.json")
    save_value_estimate(value_estimate, "value-estimate.json")
def test_imag_wavefunction_io():
    wf = Wavefunction([0, 1j, 0, 0, 0, 0, 0, 0])
    save_wavefunction(wf, "wavefunction.json")
    loaded_wf = load_wavefunction("wavefunction.json")
    assert np.allclose(wf.amplitudes, loaded_wf.amplitudes)
    remove_file_if_exists("wavefunction.json")
 def test_init_system_returns_numpy_array(self):
     wf = Wavefunction.init_system(2)
     assert isinstance(wf._amplitude_vector, np.ndarray)
 def test_constructor_returns_sympy_matrix_for_free_symbols(self):
     wf = Wavefunction([0.25, 0, Symbol("alpha"), 0])
     assert isinstance(wf._amplitude_vector, Matrix)
 def symbolic_wf(self) -> Wavefunction:
     return Wavefunction([Symbol("alpha"), 0.5, Symbol("beta"), 0.5])
 def test_init_system_fails_on_invalid_params(self, n_qubits):
     with pytest.raises(ValueError):
         Wavefunction.init_system(n_qubits=n_qubits)
 def test_init_system_raises_warning_for_non_ints(self):
     with pytest.warns(UserWarning):
         Wavefunction.init_system(1.234)
 def test_init_fails_when_passed_list_has_free_symbols_and_exceeds_unity(
         self, input_list):
     with pytest.raises(ValueError):
         Wavefunction(input_list)
Example #27
0
def test_flipped_wavefunction_comprises_expected_amplitudes(
        input_amplitudes, expected_output_amplitudes):
    np.testing.assert_array_equal(
        flip_wavefunction(Wavefunction(input_amplitudes)).amplitudes,
        expected_output_amplitudes,
    )
 def numeric_wf(self) -> Wavefunction:
     return Wavefunction([0.5, 0.5, 0.5, 0.5])
 def test_init_fails_when_len_of_passed_list_is_not_power_of_two(
         self, input_list):
     with pytest.raises(ValueError):
         Wavefunction(input_list)
 def test_constructor_returns_numpy_array_for_no_symbols(self):
     wf = Wavefunction([1.0, 0, 0, 0])
     assert isinstance(wf._amplitude_vector, np.ndarray)