common.title

Docs
Quantum Circuit
TYTAN CLOUD

QUANTUM GAMING


Overview
Contact
Event
Project
Research

Terms of service (Web service)

Terms of service (Quantum and ML Cloud service)

Privacy policy


Sign in
Sign up
common.title

BlueqatでVQEモジュール作ってみたい(手始め)

Yuichiro Minato

2021/01/01 14:27

VQE

Openfermionblueqatに、

https://github.com/Blueqat/OpenFermion-Blueqat/blob/master/openfermionblueqat/ucc.py

class UCCAnsatz(AnsatzBase):
"""Ansatz of Unitary Coupled Cluster."""
def __init__(self, hamiltonian, n_step, initial_circuit):
self.initial_circuit = initial_circuit
hamiltonian = to_pauli_expr_with_bk(hamiltonian)
super().__init__(hamiltonian, n_step)

def get\_circuit(self, params):
    c = self.initial\_circuit.copy()
    for t in params:
        for term in self.hamiltonian.terms:
            term.get\_time\_evolution()(c, t \* np.pi)
    return c

とあり、Blueqatに、

https://github.com/Blueqat/Blueqat/blob/master/blueqat/vqe.py

class QaoaAnsatz(AnsatzBase):
def __init__(self, hamiltonian, step=1, init_circuit=None):
super().__init__(hamiltonian, step * 2)
self.hamiltonian = hamiltonian.to_expr().simplify()
if not self.check_hamiltonian():
raise ValueError("Hamiltonian terms are not commutable")

    self.step = step
    self.n\_qubits = self.hamiltonian.max\_n() + 1
    if init\_circuit:
        self.init\_circuit = init\_circuit
        if init\_circuit.n\_qubits > self.n\_qubits:
            self.n\_qubits = init\_circuit.n\_qubits
    else:
        self.init\_circuit = Circuit(self.n\_qubits).h\[:\]
    self.init\_circuit.make\_cache()
    self.time\_evolutions = \[term.get\_time\_evolution() for term in self.hamiltonian\]

def check\_hamiltonian(self):
    """Check hamiltonian is commutable. This condition is required for QaoaAnsatz"""
    return self.hamiltonian.is\_all\_terms\_commutable()

def get\_circuit(self, params):
    c = self.init\_circuit.copy()
    betas = params\[:self.step\]
    gammas = params\[self.step:\]
    for beta, gamma in zip(betas, gammas):
        beta \*= np.pi
        gamma \*= 2 \* np.pi
        for evo in self.time\_evolutions:
            evo(c, gamma)
        c.rx(beta)\[:\]
    return c

を見つけました。VQEを実行するには、例えば、

runner = vqe.Vqe(UCCAnsatz(h,6,Circuit().x[0]))
result = runner.run()

だったり、

from blueqat import vqe
from blueqat.pauli import qubo_bit as q

hamiltonian = -3*q(0)-3*q(1)-3*q(2)-3*q(3)-3*q(4)+2*q(0)*q(1)+2*q(0)*q(2)+2*q(0)*q(3)+2*q(0)*q(4)+2*q(1)*q(2)+2*q(1)*q(3)+2*q(1)*q(4)+2*q(2)*q(3)+2*q(2)*q(4)+2*q(3)*q(4)
step = 2

result = vqe.Vqe(vqe.QaoaAnsatz(hamiltonian, step)).run()
print(result.most_common(12))

のようにしたりすれば良いとのことで、QAOAはpauliZのゲートでなんかよくわからなさそうだったので、UCCAnsatzの方を改造してみてみたいと思います。

AnsatzBase

class AnsatzBase:
def __init__(self, hamiltonian, n_params):
self.hamiltonian = hamiltonian
self.n_params = n_params
self.n_qubits = self.hamiltonian.max_n() + 1

def get\_circuit(self, params):
    """Make a circuit from parameters."""
    raise NotImplementedError

def get\_energy(self, circuit, sampler):
    """Calculate energy from circuit and sampler."""
    val = 0.0
    for meas in self.hamiltonian:
        c = circuit.copy()
        for op in meas.ops:
            if op.op == "X":
                c.h\[op.n\]
            elif op.op == "Y":
                c.rx(-np.pi / 2)\[op.n\]
        measured = sampler(c, meas.n\_iter())
        for bits, prob in measured.items():
            if sum(bits) % 2:
                val -= prob \* meas.coeff
            else:
                val += prob \* meas.coeff
    return val.real

def get\_objective(self, sampler):
    """Get an objective function to be optimized."""
    def objective(params):
        circuit = self.get\_circuit(params)
        circuit.make\_cache()
        return self.get\_energy(circuit, sampler)
    return objective

やってみました

from blueqat import vqe
from blueqat.pauli import *
from blueqat import Circuit

class AnsatzBase:
def __init__(self, hamiltonian, n_params):
self.hamiltonian = hamiltonian
self.n_params = n_params
self.n_qubits = self.hamiltonian.max_n() + 1

def get\_circuit(self, params):
    """Make a circuit from parameters."""
    raise NotImplementedError

def get\_energy(self, circuit, sampler):
    """Calculate energy from circuit and sampler."""
    val = 0.0
    for meas in self.hamiltonian:
        c = circuit.copy()
        for op in meas.ops:
            if op.op == "X":
                c.h\[op.n\]
            elif op.op == "Y":
                c.rx(-np.pi / 2)\[op.n\]
        measured = sampler(c, meas.n\_iter())
        for bits, prob in measured.items():
            if sum(bits) % 2:
                val -= prob \* meas.coeff
            else:
                val += prob \* meas.coeff
    return val.real

def get\_objective(self, sampler):
    """Get an objective function to be optimized."""
    def objective(params):
        circuit = self.get\_circuit(params)
        circuit.make\_cache()
        return self.get\_energy(circuit, sampler)
    return objective

class BasicAnsatz(AnsatzBase):
"""Ansatz"""
def __init__(self, hamiltonian, n_step, initial_circuit=None):
self.initial_circuit = initial_circuit
super().__init__(hamiltonian, n_step)

def get\_circuit(self, params):
    c = self.initial\_circuit.copy()
    for t in params:
        for term in self.hamiltonian.terms:
            term.get\_time\_evolution()(c, t \* np.pi)
    return c

runner = vqe.Vqe(BasicAnsatz(X[0]+Z[0]+Z[0],6,Circuit().x[0]))
result = runner.run()
print(runner.ansatz.get_energy(result.circuit,runner.sampler))

#=> -2.2360425983671095

なんかできた気がします。試しにnumpyで確かめてみます。

import numpy as np
import numpy.linalg as LA

LA.eig(np.array([[2,1],[1,-2]]))

#=>(array([ 2.23606798, -2.23606798]), array([[ 0.97324899, -0.22975292],
[ 0.22975292, 0.97324899]]))

固有値に-2.236...

が出てきて大体あってます。最初の量子状態をどうとるか結構大事な気がします。

開発者に確認したら大体合ってるようです

from blueqat import vqe
from blueqat.pauli import *
from blueqat import Circuit
from blueqat.vqe import AnsatzBase

class BasicAnsatz(AnsatzBase):
"""Ansatz"""
def __init__(self, hamiltonian, n_step, initial_circuit=Circuit()):
self.initial_circuit = initial_circuit
super().__init__(hamiltonian, n_step)

def get\_circuit(self, params):
    c = self.initial\_circuit.copy()
    for t in params:
        for term in self.hamiltonian.terms:
            term.get\_time\_evolution()(c, t \* np.pi)
    return c

runner = vqe.Vqe(BasicAnsatz(X[0]+Z[0]+Z[0],6,Circuit().x[0]))
result = runner.run()
print(runner.ansatz.get_energy(result.circuit,runner.sampler))

#=> -2.2360425983671095

© 2025, blueqat Inc. All rights reserved