예제 #1
0
    def test_dot_product_qnodes_tensor(self, qnodes, interface, tf_support,
                                       torch_support):
        """Test that the dot product of qnodes.tensor can be applied using all interfaces"""
        if interface == "torch" and not torch_support:
            pytest.skip("Skipped, no torch support")

        if interface == "tf" and not tf_support:
            pytest.skip("Skipped, no tf support")

        qnode1, _ = qnodes
        qc = qml.QNodeCollection([qnode1])
        coeffs = [0.5, -0.1]

        if interface == "torch":
            coeffs = torch.tensor(coeffs, dtype=torch.float64)

        if interface == "tf":
            coeffs = tf.cast(coeffs, dtype=tf.float64)

        # test the dot product of qnodes, tensor
        cost = qml.dot(qc, coeffs)

        params = [0.5643, -0.45]
        res = cost(params)
        qcval = qc(params)

        if interface in ("tf", "torch"):
            res = res.numpy()
            qcval = qcval.numpy()
            coeffs = coeffs.numpy()

        expected = np.dot(qcval, coeffs)
        assert np.all(res == expected)
예제 #2
0
    def test_dot_product_qnodes_qnodes(self, qnodes, interface, tf_support,
                                       torch_support):
        """Test that the dot product of qnodes.qnodes can be applied using all interfaces"""
        if interface == "torch" and not torch_support:
            pytest.skip("Skipped, no torch support")

        if interface == "tf" and not tf_support:
            pytest.skip("Skipped, no tf support")

        qnode1, qnode2 = qnodes
        qc1 = qml.QNodeCollection([qnode1, qnode2])
        qc2 = qml.QNodeCollection([qnode1, qnode2])

        # test the dot product of qnodes, qnodes
        cost = qml.dot(qc1, qc2)

        params = [0.5643, -0.45]
        res = cost(params)

        qc1val = qc1(params)
        qc2val = qc2(params)

        if interface in ("tf", "torch"):
            res = res.numpy()
            qc1val = qc1val.numpy()
            qc2val = qc2val.numpy()

        expected = np.dot(qc1val, qc2val)
        assert np.all(res == expected)
예제 #3
0
    def test_mismatching_interface(self, monkeypatch):
        """Test exception raised if the interfaces don't match"""
        dev = qml.device("default.qubit", wires=1)

        @qml.qnode(dev, interface=None)
        def circuit1(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0))

        @qml.qnode(dev, interface="autograd")
        def circuit2(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0))

        qc1 = qml.QNodeCollection([circuit1])
        qc2 = qml.QNodeCollection([circuit2])
        with pytest.raises(ValueError, match="have non-matching interfaces"):
            qml.dot(qc1, qc2)
예제 #4
0
    def test_unknown_interface(self, monkeypatch):
        """Test exception raised if the interface is unknown"""
        monkeypatch.setattr(qml.QNodeCollection, "interface", "invalid")
        dev = qml.device("default.qubit", wires=1)

        @qml.qnode(dev)
        def circuit1(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0))

        @qml.qnode(dev)
        def circuit2(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0))

        qc = qml.QNodeCollection([circuit1, circuit2])
        with pytest.raises(ValueError, match="Unknown interface invalid"):
            qml.dot([1, 2], qc)
예제 #5
0
파일: vqe.py 프로젝트: yuyuexi/pennylane
    def __init__(
        self,
        ansatz,
        hamiltonian,
        device,
        interface="autograd",
        diff_method="best",
        optimize=False,
        **kwargs,
    ):
        coeffs, observables = hamiltonian.terms

        self.hamiltonian = hamiltonian
        """Hamiltonian: the hamiltonian defining the VQE problem."""

        self.qnodes = None
        """QNodeCollection: The QNodes to be evaluated. Each QNode corresponds to the expectation
        value of each observable term after applying the circuit ansatz."""

        self._optimize = optimize

        if self._optimize:
            if not qml.tape_mode_active():
                raise ValueError(
                    "Observable optimization is only supported in tape mode. Tape "
                    "mode can be enabled with the command:\n"
                    "qml.enable_tape()"
                )

            obs_groupings, coeffs_groupings = qml.grouping.group_observables(observables, coeffs)

            wires = device.wires.tolist()

            @qml.qnode(device, interface=interface, diff_method=diff_method, **kwargs)
            def circuit(*qnode_args, obs, **qnode_kwargs):
                """Converting ansatz into a full circuit including measurements"""
                ansatz(*qnode_args, wires=wires, **qnode_kwargs)
                return [qml.expval(o) for o in obs]

            def cost_fn(*qnode_args, **qnode_kwargs):
                """Combine results from grouped QNode executions with grouped coefficients"""
                total = 0
                for o, c in zip(obs_groupings, coeffs_groupings):
                    res = circuit(*qnode_args, obs=o, **qnode_kwargs)
                    total += sum([r * c_ for r, c_ in zip(res, c)])
                return total

            self.cost_fn = cost_fn

        else:
            self.qnodes = qml.map(
                ansatz, observables, device, interface=interface, diff_method=diff_method, **kwargs
            )

            self.cost_fn = qml.dot(coeffs, self.qnodes)
예제 #6
0
    def __init__(self, ansatz, hamiltonian, device, interface="autograd", diff_method="best"):
        coeffs, observables = hamiltonian.terms
        self.hamiltonian = hamiltonian
        """Hamiltonian: the hamiltonian defining the VQE problem."""

        self.qnodes = qml.map(ansatz, observables, device, interface=interface, diff_method=diff_method)
        """QNodeCollection: The QNodes to be evaluated. Each QNode corresponds to the
        the expectation value of each observable term after applying the circuit ansatz.
        """

        self.cost_fn = qml.dot(coeffs, self.qnodes)
예제 #7
0
    def test_single_qubit_vqe(self, tol):
        """Test single-qubit VQE has the correct QNG value
        every step, the correct parameter updates,
        and correct cost after 200 steps"""
        dev = qml.device("default.qubit", wires=1)

        def circuit(params, wires=0):
            qml.RX(params[0], wires=wires)
            qml.RY(params[1], wires=wires)

        coeffs = [1, 1]
        obs_list = [
            qml.PauliX(0),
            qml.PauliZ(0)
        ]

        qnodes = qml.map(circuit, obs_list, dev, measure='expval')
        cost_fn = qml.dot(coeffs, qnodes)

        def gradient(params):
            """Returns the gradient"""
            da = -np.sin(params[0]) * (np.cos(params[1]) + np.sin(params[1]))
            db = np.cos(params[0]) * (np.cos(params[1]) - np.sin(params[1]))
            return np.array([da, db])

        eta = 0.01
        init_params = np.array([0.011, 0.012])
        num_steps = 200

        opt = qml.QNGOptimizer(eta)
        theta = init_params

        # optimization for 200 steps total
        for t in range(num_steps):
            theta_new = opt.step(cost_fn, theta,
                                 metric_tensor_fn=qnodes.qnodes[0].metric_tensor)

            # check metric tensor
            res = opt.metric_tensor
            exp = np.diag([0.25, (np.cos(theta[0]) ** 2)/4])
            assert np.allclose(res, exp, atol=tol, rtol=0)

            # check parameter update
            dtheta = eta * sp.linalg.pinvh(exp) @ gradient(theta)
            assert np.allclose(dtheta, theta - theta_new, atol=tol, rtol=0)

            theta = theta_new

        # check final cost
        assert np.allclose(cost_fn(theta), -1.41421356, atol=tol, rtol=0)
    def term(params, sign_term, sign_i, i, sign_j, j):
        qml.BasisState(np.array([0, 0, 0, 0, 0, 0]), wires=range(6))

        variational_circuit_wire_list(params)

        shift = np.zeros_like(params)
        shift[i] = sign_i * one
        shift[j] = sign_j * one
        variational_circuit_wire_list(params + shift, wire_list=[3, 4, 5])

        # return qml.DiagonalQubitUnitary([1] * 6, wires=[0, 1, 2]), qml.DiagonalQubitUnitary([1] * 6, wires=[3, 4, 5])
        # return [
        #     [qml.expval(qml.PauliX(wire)) for wire in [0, 1, 2]],
        #     [qml.expval(qml.PauliX(wire)) for wire in [3, 4, 5]],
        # ]
        return sign_term * np.abs(
            qml.dot(
                [qml.expval(qml.PauliX(wire)) for wire in [0, 1, 2]],
                [qml.expval(qml.PauliX(wire)) for wire in [3, 4, 5]],
            ))**2
예제 #9
0
 def test_no_qnodes(self):
     """Test exception raised if no qnodes are provided as arguments"""
     with pytest.raises(ValueError, match="At least one argument must be a QNodeCollection"):
         qml.dot([1, 2], [3, 4])
예제 #10
0
 def test_aggregate_expval(self, coeffs, observables, expected):
     """Tests that the aggregate function returns correct expectation values"""
     dev = qml.device("default.qubit", wires=2)
     qnodes = qml.map(lambda params, **kwargs: None, observables, dev)
     expval = qml.dot(coeffs, qnodes)
     assert expval([]) == sum(expected)
예제 #11
0
파일: vqe.py 프로젝트: rryoung98/pennylane
    def __init__(
        self,
        ansatz,
        hamiltonian,
        device,
        interface="autograd",
        diff_method="best",
        optimize=False,
        **kwargs,
    ):
        if kwargs.get("measure", "expval") != "expval":
            raise ValueError("ExpvalCost can only be used to construct sums of expectation values.")

        coeffs, observables = hamiltonian.terms

        self.hamiltonian = hamiltonian
        """Hamiltonian: the input Hamiltonian."""

        self.qnodes = None
        """QNodeCollection: The QNodes to be evaluated. Each QNode corresponds to the expectation
        value of each observable term after applying the circuit ansatz."""

        self._multiple_devices = isinstance(device, Sequence)
        """Bool: Records if multiple devices are input"""

        if all(c == 0 for c in coeffs) or not coeffs:
            self.cost_fn = lambda *args, **kwargs: np.array(0)
            return

        self._optimize = optimize

        self.qnodes = qml.map(
            ansatz, observables, device, interface=interface, diff_method=diff_method, **kwargs
        )

        if self._optimize:

            if self._multiple_devices:
                raise ValueError("Using multiple devices is not supported when optimize=True")

            obs_groupings, coeffs_groupings = qml.grouping.group_observables(observables, coeffs)
            d = device[0] if self._multiple_devices else device
            w = d.wires.tolist()

            @qml.qnode(device, interface=interface, diff_method=diff_method, **kwargs)
            def circuit(*qnode_args, obs, **qnode_kwargs):
                """Converting ansatz into a full circuit including measurements"""
                ansatz(*qnode_args, wires=w, **qnode_kwargs)
                return [qml.expval(o) for o in obs]

            def cost_fn(*qnode_args, **qnode_kwargs):
                """Combine results from grouped QNode executions with grouped coefficients"""
                total = 0
                for o, c in zip(obs_groupings, coeffs_groupings):
                    res = circuit(*qnode_args, obs=o, **qnode_kwargs)
                    total += sum([r * c_ for r, c_ in zip(res, c)])
                return total

            self.cost_fn = cost_fn

        else:
            self.cost_fn = qml.dot(coeffs, self.qnodes)
예제 #12
0
for i in range(100):
    params = opt.step(cost, params)
    cost_wrs.append(cost(params))
    shots_wrs.append(total_shots * i)
    print("Step {}: cost = {} shots used = {}".format(i, cost_wrs[-1],
                                                      shots_wrs[-1]))

##############################################################################
# Let's compare this against an optimization not using weighted random sampling.
# Here, we will split the 8000 total shots evenly across all Hamiltonian terms,
# also known as *uniform deterministic sampling*.

non_analytic_dev.shots = total_shots / len(coeffs)

qnodes = qml.map(StronglyEntanglingLayers, obs, device=non_analytic_dev)
cost = qml.dot(coeffs, qnodes)

opt = qml.AdamOptimizer(0.05)
params = init_params

cost_adam = []
shots_adam = []

for i in range(100):
    params = opt.step(cost, params)
    cost_adam.append(cost(params))
    shots_adam.append(total_shots * i)
    print("Step {}: cost = {} shots used = {}".format(i, cost_adam[-1],
                                                      shots_adam[-1]))

##############################################################################
예제 #13
0
    def __init__(
        self,
        ansatz,
        hamiltonian,
        device,
        interface="autograd",
        diff_method="best",
        optimize=False,
        **kwargs,
    ):
        coeffs, observables = hamiltonian.terms

        self.hamiltonian = hamiltonian
        """Hamiltonian: the input Hamiltonian."""

        self.qnodes = None
        """QNodeCollection: The QNodes to be evaluated. Each QNode corresponds to the expectation
        value of each observable term after applying the circuit ansatz."""

        self._multiple_devices = isinstance(device, Sequence)
        """Bool: Records if multiple devices are input"""

        tape_mode = qml.tape_mode_active()
        if tape_mode:

            d = device[0] if self._multiple_devices else device
            w = d.wires.tolist()

            try:
                qml.disable_tape()

                @qml.qnode(d,
                           interface=interface,
                           diff_method=diff_method,
                           **kwargs)
                def qnode_for_metric_tensor_in_tape_mode(
                        *qnode_args, **qnode_kwargs):
                    """The metric tensor cannot currently be calculated in tape-mode QNodes. As a
                    short-term fix for ExpvalCost, we create a non-tape mode QNode just for
                    calculation of the metric tensor. In doing so, we reintroduce the same
                    restrictions of the old QNode but allow users to access new functionality
                    such as measurement grouping and batch execution of the gradient."""
                    ansatz(*qnode_args, wires=w, **qnode_kwargs)
                    return qml.expval(qml.PauliZ(0))

                self._qnode_for_metric_tensor_in_tape_mode = qnode_for_metric_tensor_in_tape_mode
            finally:
                qml.enable_tape()

        self._optimize = optimize

        if self._optimize:
            if not tape_mode:
                raise ValueError(
                    "Observable optimization is only supported in tape mode. Tape "
                    "mode can be enabled with the command:\n"
                    "qml.enable_tape()")

            if self._multiple_devices:
                raise ValueError(
                    "Using multiple devices is not supported when optimize=True"
                )

            obs_groupings, coeffs_groupings = qml.grouping.group_observables(
                observables, coeffs)

            @qml.qnode(device,
                       interface=interface,
                       diff_method=diff_method,
                       **kwargs)
            def circuit(*qnode_args, obs, **qnode_kwargs):
                """Converting ansatz into a full circuit including measurements"""
                ansatz(*qnode_args, wires=w, **qnode_kwargs)
                return [qml.expval(o) for o in obs]

            def cost_fn(*qnode_args, **qnode_kwargs):
                """Combine results from grouped QNode executions with grouped coefficients"""
                total = 0
                for o, c in zip(obs_groupings, coeffs_groupings):
                    res = circuit(*qnode_args, obs=o, **qnode_kwargs)
                    total += sum([r * c_ for r, c_ in zip(res, c)])
                return total

            self.cost_fn = cost_fn

        else:
            self.qnodes = qml.map(ansatz,
                                  observables,
                                  device,
                                  interface=interface,
                                  diff_method=diff_method,
                                  **kwargs)

            self.cost_fn = qml.dot(coeffs, self.qnodes)
예제 #14
0
for i in range(100):
    params, _cost = opt.step_and_cost(cost, params)
    cost_wrs.append(_cost)
    shots_wrs.append(total_shots*i)
    print("Step {}: cost = {} shots used = {}".format(i, cost_wrs[-1], shots_wrs[-1]))

##############################################################################
# Let's compare this against an optimization not using weighted random sampling.
# Here, we will split the 8000 total shots evenly across all Hamiltonian terms,
# also known as *uniform deterministic sampling*.

non_analytic_dev.shots = int(total_shots / len(coeffs))

qnodes = qml.map(StronglyEntanglingLayers, obs, device=non_analytic_dev)
cost = qml.dot(coeffs, qnodes)

opt = qml.AdamOptimizer(0.05)
params = init_params

cost_adam = []
shots_adam = []

for i in range(100):
    params, _cost = opt.step_and_cost(cost, params)
    cost_adam.append(_cost)
    shots_adam.append(total_shots*i)
    print("Step {}: cost = {} shots used = {}".format(i, cost_adam[-1], shots_adam[-1]))

##############################################################################
# Comparing these two techniques:
예제 #15
0
def ExpvalH(H: qml.Hamiltonian, device: qml.device):
    coeffs, observables = H.terms
    qnodes = qml.map(variational_ansatz, observables, device)
    cost = qml.dot(coeffs, qnodes)
    return cost