def _calculate_expectation_value_for_distribution(
        distribution: BitstringDistribution, operator: IsingOperator,
        alpha: float) -> float:

    # Calculates expectation value per bitstring
    expectation_values_per_bitstring = {}
    for bitstring in distribution.distribution_dict:
        expected_value = Measurements([bitstring]).get_expectation_values(
            operator, use_bessel_correction=False)
        expectation_values_per_bitstring[bitstring] = np.sum(
            expected_value.values)

    cumulative_value = 0.0
    # Get total expectation value (mean of expectation values of all bitstrings weighted by distribution)
    for bitstring in expectation_values_per_bitstring:
        prob = distribution.distribution_dict[bitstring]

        # For the i-th sampled bitstring, compute exp(-alpha E_i) See equation 2 in the original paper.
        expectation_value = np.exp(-alpha *
                                   expectation_values_per_bitstring[bitstring])
        cumulative_value += prob * expectation_value

    final_value = -np.log(cumulative_value)

    return final_value
示例#2
0
def convert_sampleset_to_measurements(
    sampleset: SampleSet,
    change_bitstring_convention: bool = False,
) -> Measurements:
    """
    Converts dimod SampleSet to zquantum.core Measurements.
    Works only for the sampleset with "BINARY" vartype and variables being range of integers starting from 0.

    Note:
        Since Measurements doesn't hold information about the energy of the samples, this conversion is lossy.
        For more explanation regarding change_bitstring_convention please read docs of `convert_measurements_to_sampleset`.

    Args:
        sampleset: SampleSet we want to convert
        change_bitstring_convention: whether to flip the bits in bitstrings to, depends on the convention one is using (see note).
    Returns:
        Measurements object

    """
    if sampleset.vartype != dimod.BINARY:
        raise TypeError("Sampleset needs to have vartype BINARY")
    for i in range(max(sampleset.variables)):
        if sampleset.variables[i] != i:
            raise ValueError(
                "Variables of sampleset need to be ordered list of integers")

    bitstrings = [
        tuple(
            int(change_bitstring_convention != sample[i])
            for i in range(len(sample))) for sample in sampleset.samples()
    ]
    return Measurements(bitstrings)
    def test_save_for_numpy_integers(self):
        # Given
        target_bitstrings = [(0, 0, 0)]
        input_bitstrings = [(np.int8(0), np.int8(0), np.int8(0))]

        filename = "measurementstest.json"
        measurements = Measurements(input_bitstrings)
        target_measurements = Measurements(target_bitstrings)

        # When
        measurements.save(filename)

        # Then
        recreated_measurements = Measurements.load_from_file(filename)
        assert target_measurements.bitstrings == recreated_measurements.bitstrings
        remove_file_if_exists("measurementstest.json")
def test_converted_ising_evaluates_to_the_same_energy_as_original_qubo():
    qubo = dimod.BinaryQuadraticModel(
        {
            0: 1,
            1: 2,
            2: 3
        },
        {
            (0, 1): 1,
            (0, 2): 0.5,
            (1, 2): 0.5,
        },
        -1,
        vartype=dimod.BINARY,
    )
    all_solutions = [
        [0, 0, 0],
        [0, 0, 1],
        [0, 1, 0],
        [0, 1, 1],
        [1, 0, 0],
        [1, 0, 1],
        [1, 1, 0],
        [1, 1, 1],
    ]

    ising = convert_qubo_to_openfermion_ising(qubo)
    for solution in all_solutions:
        qubo_energy = qubo.energy(solution)
        ising_energy = np.sum(
            Measurements([solution]).get_expectation_values(ising).values)
        assert qubo_energy == ising_energy
    def test_get_expectation_values_from_measurements(self):
        # Given
        measurements = Measurements([(0, 1, 0), (0, 1, 0), (0, 0, 0),
                                     (1, 0, 0), (1, 1, 1)])
        ising_operator = IsingOperator("10[] + [Z0 Z1] - 15[Z1 Z2]")
        target_expectation_values = np.array([10, -0.2, -3])
        target_correlations = np.array([[100, -2, -30], [-2, 1, -9],
                                        [-30, -9, 225]])
        denominator = len(measurements.bitstrings)
        covariance_11 = (target_correlations[1, 1] -
                         target_expectation_values[1]**2) / denominator
        covariance_12 = (target_correlations[1, 2] -
                         target_expectation_values[1] *
                         target_expectation_values[2]) / denominator
        covariance_22 = (target_correlations[2, 2] -
                         target_expectation_values[2]**2) / denominator

        target_covariances = np.array([
            [0, 0, 0],
            [0, covariance_11, covariance_12],
            [0, covariance_12, covariance_22],
        ])

        # When
        expectation_values = measurements.get_expectation_values(
            ising_operator, False)
        # Then
        np.testing.assert_allclose(expectation_values.values,
                                   target_expectation_values)
        assert len(expectation_values.correlations) == 1
        np.testing.assert_allclose(expectation_values.correlations[0],
                                   target_correlations)
        assert len(expectation_values.estimator_covariances) == 1
        np.testing.assert_allclose(expectation_values.estimator_covariances[0],
                                   target_covariances)
def test_convert_measurements_to_sampleset_with_qubo():
    bitstrings = [
        (0, 0, 0),
        (0, 0, 1),
        (0, 1, 0),
        (0, 1, 1),
        (1, 0, 0),
        (1, 1, 0),
        (1, 1, 1),
        (1, 0, 1),
        (0, 0, 1),
    ]
    qubo = dimod.BinaryQuadraticModel(
        {
            0: 1,
            1: 2,
            2: 3
        },
        {
            (1, 2): 0.5,
            (1, 0): -0.25,
            (0, 2): 2.125
        },
        0,
        vartype=dimod.BINARY,
    )
    energies = [0, 3, 2, 5.5, 1, 2.75, 8.375, 6.125, 3]
    measurements = Measurements(bitstrings)

    target_sampleset = dimod.SampleSet.from_samples(bitstrings, dimod.BINARY,
                                                    energies)
    converted_sampleset = convert_measurements_to_sampleset(measurements, qubo)
    assert target_sampleset == converted_sampleset
def test_convert_measurements_to_sampleset_without_qubo():
    bitstrings = [
        (0, 0, 0),
        (0, 0, 1),
        (0, 1, 0),
        (0, 1, 1),
        (1, 0, 0),
        (1, 1, 0),
        (1, 1, 1),
        (1, 0, 1),
        (0, 0, 1),
    ]
    measurements = Measurements(bitstrings)

    target_sampleset = dimod.SampleSet.from_samples(
        bitstrings, dimod.BINARY, [np.nan for _ in bitstrings])
    converted_sampleset = convert_measurements_to_sampleset(measurements)

    # Since energies should be np.nans, using "==" will result in error
    for (target_record, converted_record) in zip(target_sampleset.record,
                                                 converted_sampleset.record):
        for target_element, converted_element in zip(target_record,
                                                     converted_record):
            np.testing.assert_equal(target_element, converted_element)

    assert converted_sampleset.vartype == target_sampleset.vartype
def test_convert_sampleset_to_measurements_with_change_bitstring_convention():
    bitstrings = [
        (0, 0, 0),
        (0, 0, 1),
        (0, 1, 0),
        (0, 1, 1),
        (1, 0, 0),
        (1, 1, 0),
        (1, 1, 1),
        (1, 0, 1),
        (0, 0, 1),
    ]

    target_bitstrings = [
        (1, 1, 1),
        (1, 1, 0),
        (1, 0, 1),
        (1, 0, 0),
        (0, 1, 1),
        (0, 0, 1),
        (0, 0, 0),
        (0, 1, 0),
        (1, 1, 0),
    ]
    change_bitstring_convention = True
    energies = [0 for i in range(len(bitstrings))]
    sampleset = dimod.SampleSet.from_samples(bitstrings, dimod.BINARY,
                                             energies)
    target_measurements = Measurements(target_bitstrings)
    converted_measurements = convert_sampleset_to_measurements(
        sampleset, change_bitstring_convention=change_bitstring_convention)

    assert converted_measurements.bitstrings == target_measurements.bitstrings
    def test_intialize_with_bitstrings(self):
        # Given
        bitstrings = [
            (0, 0, 0),
            (0, 0, 1),
            (0, 0, 1),
            (0, 1, 0),
            (0, 1, 1),
            (1, 0, 0),
            (1, 0, 1),
            (1, 1, 0),
            (1, 1, 1),
        ]

        # When
        measurements = Measurements(bitstrings=bitstrings)

        # Then
        assert measurements.bitstrings == [
            (0, 0, 0),
            (0, 0, 1),
            (0, 0, 1),
            (0, 1, 0),
            (0, 1, 1),
            (1, 0, 0),
            (1, 0, 1),
            (1, 1, 0),
            (1, 1, 1),
        ]
示例#10
0
    def get_estimated_expectation_values(
        self,
        backend: QuantumBackend,
        circuit: Circuit,
        target_operator: IsingOperator,
        alpha: float,
        n_samples: Optional[int] = None,
    ) -> ExpectationValues:
        """Given a circuit, backend, and target operators, this method produces expectation values
        using CVaR algorithm.

        Args:
            backend (QuantumBackend): the backend that will be used to run the circuit
            circuit (Circuit): the circuit that prepares the state.
            target_operator (SymbolicOperator): Operator to be estimated.
            alpha (float): defines what part of the best measurements should be taken into account in the estimation process.
            n_samples (int): Number of measurements done on the unknown quantum state.

        Raises:
            AttributeError: If backend is not a QuantumSimulator.

        Returns:
            ExpectationValues: expectation values for each term in the target operator.
        """
        if alpha > 1 or alpha <= 0:
            raise ValueError("alpha needs to be a value between 0 and 1.")

        if not isinstance(target_operator, IsingOperator):
            raise TypeError("Operator should be of type IsingOperator.")

        distribution = backend.get_bitstring_distribution(circuit, n_samples=n_samples)
        expected_values_per_bitstring = {}

        for bitstring in distribution.distribution_dict:
            expected_value = Measurements(bitstring).get_expectation_values(
                target_operator
            )
            expected_values_per_bitstring[bitstring] = expected_value.values[0]

        sorted_expected_values_per_bitstring_list = sorted(
            expected_values_per_bitstring.items(), key=lambda item: item[1]
        )

        cumulative_prob = 0.0
        cumulative_value = 0.0

        for bitstring, energy in sorted_expected_values_per_bitstring_list:
            prob = distribution.distribution_dict[bitstring]
            if cumulative_prob + prob < alpha:
                cumulative_prob += prob
                cumulative_value += prob * energy
            else:
                cumulative_value += (alpha - cumulative_prob) * energy
                break
        final_value = cumulative_value / alpha
        return ExpectationValues(final_value)
示例#11
0
def get_exact_qubo_solution(qubo):
    """Solves qubo by iterating over all the possible solutions.
    Args:
        qubo: qubo stored as a json
    """
    qubo = load_qubo(qubo)
    sampleset = ExactSolver().sample(qubo)
    best_sample_dict = sampleset.first.sample
    solution_bitstring = tuple(best_sample_dict[i] for i in sorted(best_sample_dict))
    Measurements([solution_bitstring]).save("exact_solution.json")
示例#12
0
    def test_add_measurements(self):
        # Given
        measurements = Measurements()
        bitstrings = [
            (0, 0, 0),
            (0, 0, 1),
            (0, 0, 1),
            (0, 1, 0),
            (0, 1, 1),
            (1, 0, 0),
            (1, 0, 1),
            (1, 1, 0),
            (1, 1, 1),
        ]

        # When
        measurements.bitstrings = bitstrings

        # Then
        assert measurements.bitstrings == [
            (0, 0, 0),
            (0, 0, 1),
            (0, 0, 1),
            (0, 1, 0),
            (0, 1, 1),
            (1, 0, 0),
            (1, 0, 1),
            (1, 1, 0),
            (1, 1, 1),
        ]

        # When
        measurements.bitstrings += bitstrings

        # Then
        assert measurements.bitstrings == [
            (0, 0, 0),
            (0, 0, 1),
            (0, 0, 1),
            (0, 1, 0),
            (0, 1, 1),
            (1, 0, 0),
            (1, 0, 1),
            (1, 1, 0),
            (1, 1, 1),
            (0, 0, 0),
            (0, 0, 1),
            (0, 0, 1),
            (0, 1, 0),
            (0, 1, 1),
            (1, 0, 0),
            (1, 0, 1),
            (1, 1, 0),
            (1, 1, 1),
        ]
示例#13
0
    def run_circuit_and_measure(self, circuit, **kwargs):
        """
        Run a circuit and measure a certain number of bitstrings

        Args:
            circuit (zquantum.core.circuit.Circuit): the circuit to prepare the state
            n_samples (int): the number of bitstrings to sample
        Returns:
            a list of bitstrings (a list of tuples)
        """
        wavefunction = self.get_wavefunction(circuit)
        bitstrings = sample_from_wavefunction(wavefunction, self.n_samples)
        return Measurements(bitstrings)
def _evaluate_solution_for_hamiltonian(solution: Tuple[int],
                                       hamiltonian: QubitOperator) -> float:
    """Evaluates a solution of a hamiltonian by its calculating expectation value.

    Args:
        solution: solution to a problem as a tuple of bits
        hamiltonian: a Hamiltonian representing a problem.

    Returns:
        float: value of a solution.
    """
    hamiltonian = change_operator_type(hamiltonian, IsingOperator)
    expectation_values = expectation_values_to_real(
        Measurements([solution]).get_expectation_values(hamiltonian))
    return sum(expectation_values.values)
示例#15
0
def solve_qubo(qubo, solver_specs, solver_params=None):
    """Solves qubo using any sampler implementing either dimod.Sampler or zquantum.qubo.BQMSolver"""
    if solver_params is None:
        solver_params = {}
    solver = create_object(solver_specs)
    qubo = load_qubo(qubo)

    sampleset = solver.sample(qubo, **solver_params)
    best_sample_dict = sampleset.first.sample
    solution_bitstring = tuple(best_sample_dict[i] for i in sorted(best_sample_dict))
    lowest_energy = evaluate_bitstring_for_qubo(solution_bitstring, qubo)

    save_value_estimate(ValueEstimate(lowest_energy), "lowest-energy.json")
    Measurements([solution_bitstring]).save("solution.json")
    save_sampleset(sampleset, "sampleset.json")
示例#16
0
    def run_circuit_and_measure(self, circuit, n_samples: int):
        """Run a circuit and measure a certain number of bitstrings. Note: the number
        of bitstrings measured is derived from self.n_samples

        Args:
            circuit: the circuit to prepare the state
            n_samples: The number of samples to measure.
        Returns:
            a list of bitstrings (a list of tuples)
        """
        super().run_circuit_and_measure(circuit, n_samples=n_samples)
        cxn = get_forest_connection(self.device_name, self.seed)
        bitstrings = cxn.run_and_measure(export_to_pyquil(circuit), trials=n_samples)
        if isinstance(bitstrings, dict):
            bitstrings = np.vstack([bitstrings[q] for q in sorted(cxn.qubits())]).T

        bitstrings = [tuple(b) for b in bitstrings.tolist()]
        return Measurements(bitstrings)
示例#17
0
    def run_circuit_and_measure(self,
                                circuit: Circuit,
                                n_samples: Optional[int] = None,
                                **kwargs):
        """
        Run a circuit and measure a certain number of bitstrings

        Args:
            circuit: the circuit to prepare the state
            n_samples: the number of bitstrings to sample
        Returns:
            The measured bitstrings.
        """
        if n_samples is None:
            n_samples = self.n_samples
        wavefunction = self.get_wavefunction(circuit)
        bitstrings = sample_from_wavefunction(wavefunction, n_samples)
        return Measurements(bitstrings)
def test_convert_sampleset_to_measurements():
    bitstrings = [
        (0, 0, 0),
        (0, 0, 1),
        (0, 1, 0),
        (0, 1, 1),
        (1, 0, 0),
        (1, 1, 0),
        (1, 1, 1),
        (1, 0, 1),
        (0, 0, 1),
    ]
    energies = [0 for i in range(len(bitstrings))]
    sampleset = dimod.SampleSet.from_samples(bitstrings, dimod.BINARY,
                                             energies)
    target_measurements = Measurements(bitstrings)
    converted_measurements = convert_sampleset_to_measurements(sampleset)

    assert converted_measurements.bitstrings == target_measurements.bitstrings
def test_converted_qubo_evaluates_to_the_same_energy_as_original_ising():
    ising = IsingOperator(
        "2.5 [] + [Z0] + 2[Z0 Z1] +0.5[Z0 Z2] +[Z1] + 0.75[Z1 Z2] -[Z2]")

    all_solutions = [
        [0, 0, 0],
        [0, 0, 1],
        [0, 1, 0],
        [0, 1, 1],
        [1, 0, 0],
        [1, 0, 1],
        [1, 1, 0],
        [1, 1, 1],
    ]

    qubo = convert_openfermion_ising_to_qubo(ising)
    for solution in all_solutions:
        qubo_energy = qubo.energy(solution)
        ising_energy = np.sum(
            Measurements([solution]).get_expectation_values(ising).values)
        assert qubo_energy == ising_energy
示例#20
0
    def run_circuit_and_measure(
        self,
        circuit: Circuit,
        n_samples: int,
        symbol_map: Optional[Dict[Symbol, Any]] = {},
    ) -> Measurements:
        """Run a circuit and measure a certain number of bitstrings

        Args:
            circuit: the circuit to prepare the state
            n_samples: the number of bitstrings to sample
        """
        wavefunction = self.get_wavefunction(circuit).bind(
            symbol_map=symbol_map)

        if circuit.free_symbols:
            raise ValueError(
                "Cannot sample from circuit with symbolic parameters.")

        bitstrings = sample_from_wavefunction(wavefunction, n_samples,
                                              self._seed)
        return Measurements(bitstrings)
示例#21
0
    def test_add_counts(self):
        # Given
        measurements = Measurements()
        measurements_counts = {
            "000": 1,
            "001": 2,
            "010": 1,
            "011": 1,
            "100": 1,
            "101": 1,
            "110": 1,
            "111": 1,
        }

        # When
        measurements.add_counts(measurements_counts)

        # Then
        assert measurements.bitstrings == [
            (0, 0, 0),
            (0, 0, 1),
            (0, 0, 1),
            (0, 1, 0),
            (0, 1, 1),
            (1, 0, 0),
            (1, 0, 1),
            (1, 1, 0),
            (1, 1, 1),
        ]
        assert measurements.get_counts() == {
            "000": 1,
            "001": 2,
            "010": 1,
            "011": 1,
            "100": 1,
            "101": 1,
            "110": 1,
            "111": 1,
        }
示例#22
0
    def run_circuit_and_measure(self,
                                circuit: Circuit,
                                n_samples: Optional[int] = None,
                                **kwargs):
        """
        Run a circuit and measure a certain number of bitstrings

        Args:
            circuit: the circuit to prepare the state
            n_samples: the number of bitstrings to sample
        Returns:
            The measured bitstrings.
        """
        if n_samples is None:
            if self.n_samples is None:
                raise ValueError(
                    "n_samples needs to be specified either as backend attribute or as an function argument."
                )
            else:
                n_samples = self.n_samples
        wavefunction = self.get_wavefunction(circuit)
        bitstrings = sample_from_wavefunction(wavefunction, n_samples)
        return Measurements(bitstrings)
示例#23
0
def _calculate_expectation_value_of_bitstring(
        bitstring: str, operator: IsingOperator) -> float:
    """Calculate expectation value for a bitstring based on an operator."""
    expected_value = Measurements([bitstring]).get_expectation_values(
        operator, use_bessel_correction=False)
    return np.sum(expected_value.values)
示例#24
0
 def run_circuit_and_measure(self, circuit, **kwargs):
     wavefunction = self.get_wavefunction(circuit)
     return Measurements(
         sample_from_wavefunction(wavefunction, self.n_samples))