ljvmiranda921 / pyswarms

A research toolkit for particle swarm optimization in Python
https://pyswarms.readthedocs.io/en/latest/
MIT License
1.29k stars 332 forks source link

TypeError: Cannot add invalid type to <class 'openfermion.ops._qubit_operator.QubitOperator'>. #416

Closed zohimchandani closed 4 years ago

zohimchandani commented 4 years ago

I am trying to minimise a cost function which is itself a function of a quantum computing package that invokes the QubitOperator command from the package. When I run the pyswarms optimisation

%%time
# Set-up hyperparameters
options = {'c1': 0.5, 'c2': 0.3, 'w':0.9}

# Call instance of PSO
optimizer = ps.single.GlobalBestPSO(n_particles=10, dimensions=8, options=options)

# Perform optimization
cost, pos = optimizer.optimize(disc_loss, iters=1000)

I get the following error : TypeError: Cannot add invalid type to <class 'openfermion.ops._qubit_operator.QubitOperator'>.

Any ideas why this may be occurring?

whzup commented 4 years ago

Hello @zohimchandani! Welcome to pyswarms 😄!

Could you provide more information? This is not an error that is yielded by pyswarms and after a quick look in the openfermion project, it also doesn't seem to stem from there. And it does not seem to be a standard CPython error either (according to a quick Google search). But just from the error message, I would guess that you are adding some other type to a QubitOperator.

But as I said, it'd be useful to have the entire code in order to make a more meaningful analysis.

zohimchandani commented 4 years ago

Please see below the main chunk of the code below. I appreciate you looking into this for me.


%load_ext jupyternotify
from pytket import Circuit, Qubit, Bit, OpType
from pytket.utils.operators import QubitPauliOperator
from sympy import symbols
from openfermion import QubitOperator
from random import sample
import numpy as np
from pytket.backends.projectq import ProjectQBackend
from pytket.backends.ibm import AerStateBackend, AerBackend, AerUnitaryBackend, IBMQBackend
from scipy.linalg import expm, sinm, cosm
from sympy.physics.quantum.dagger import Dagger
import functools
import operator
import itertools    
from openfermion import get_sparse_operator
from scipy.optimize import minimize, LinearConstraint
import matplotlib.pyplot as plt

backend = AerStateBackend()

def fidelity(rsv, gsv):

    rsv_conj = np.conj(rsv)
    fid = sum(rsv_conj*gsv) * np.conj(sum(rsv_conj*gsv))

    return fid

def real(n, weights):

    real_circ = Circuit()
    qubits = real_circ.add_q_register('q', n)

    for i in range(n) :
        real_circ.Rx(weights[i] , qubits[i])

    for i in range(n) :
        real_circ.Ry(weights[n+i], qubits[i])

    for i in range(n) :
        real_circ.Rz(weights[(2*n) + i], qubits[i])

    backend.compile_circuit(real_circ)
    state_handle = backend.process_circuit(real_circ)
    statevector = backend.get_state(state_handle)

    return real_circ, statevector

def generator(n, weights):

    generator_circ = Circuit()
    qubits = generator_circ.add_q_register('q', n)

    for i in range(n) :
        generator_circ.Rx(weights[i] , qubits[i])

    for i in range(n) :
        generator_circ.Ry(weights[n+i], qubits[i])

    for i in range(n) :
        generator_circ.Rz(weights[(2*n) + i] , qubits[i])

    backend.compile_circuit(generator_circ)
    state_handle = backend.process_circuit(generator_circ)
    statevector = backend.get_state(state_handle)

    return generator_circ, statevector

def discriminator(disc_weights, real_circ, real_sv, gen_circ, gen_sv):

    disc_weights_phi = disc_weights[:len(disc_weights)//2]
    disc_weights_psi = disc_weights[len(disc_weights)//2:]

    tuple_list_phi = [(weight, tup[0], tup[1]) for weight, tup in zip(disc_weights_phi, itertools.product(['X', 'Y', 'Z'], range(n)))]
    tuple_list_psi = [(weight, tup[0], tup[1]) for weight, tup in zip(disc_weights_psi, itertools.product(['X', 'Y', 'Z'], range(n)))]

    measurements_phi =  functools.reduce(operator.add, (weight * QubitOperator(f'{a}{n}') for weight, a, n in tuple_list_phi))
    measurements_psi =  functools.reduce(operator.add, (weight * QubitOperator(f'{a}{n}') for weight, a, n in tuple_list_psi))

    iden_phi =  functools.reduce(operator.add, ( (disc_weights_phi[len(disc_weights_phi)-1] ) * QubitOperator(" ") ))
    iden_psi =  functools.reduce(operator.add, ( (disc_weights_psi[len(disc_weights_psi)-1]) * QubitOperator(" ") ))

    phi = operator.add(iden_phi, measurements_phi)
    psi = operator.add(iden_psi, measurements_psi)

    psi_matrix = get_sparse_operator(psi).todense()
    phi_matrix = get_sparse_operator(phi).todense()

    psi_exp = backend.get_operator_expectation_value(real_circ, QubitPauliOperator.from_OpenFermion(psi))
    phi_exp = backend.get_operator_expectation_value(gen_circ, QubitPauliOperator.from_OpenFermion(phi)) 

    return psi_exp , phi_exp 

def disc_loss(disc_weights):

    psi_exp , phi_exp  = discriminator(disc_weights, real_circ, real_sv, gen_circ, gen_sv)
    loss = np.real(psi_exp - phi_exp )

    return -loss 

def gen_loss(gen_weights):

    generator(n, gen_weights)

    psi_exp , phi_exp = discriminator(disc_weights, real_circ, real_sv, gen_circ, gen_sv)
    loss = np.real(psi_exp - phi_exp )

    return loss 

n = 1 
lamb = np.float(2)   

real_weights = np.random.uniform(0, 2 , n*3)
init_gen_weights = np.random.uniform(0, 2 , ((6*n) - 3) )
init_disc_weights = np.random.uniform(0, 2 , (6*n) + 2)
gen_weights = init_gen_weights
disc_weights = init_disc_weights

bounds = (0, 2*np.pi)
bounds_gen_weights=[]
for i in range(len(gen_weights)):
    bounds_gen_weights.append(bounds)

bounds = (-10, 10)
bounds_disc_weights=[]
for i in range(len(disc_weights)):
    bounds_disc_weights.append(bounds)

real_circ, real_sv = real(n, real_weights)
gen_circ, gen_sv = generator(n, init_gen_weights)
init_fid = fidelity(real_sv, gen_sv)

# %%time

Import PySwarms
import pyswarms as ps
from pyswarms.utils.functions import single_obj as fx

# Some more magic so that the notebook will reload external python modules;
# see http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython
%load_ext autoreload
%autoreload 2
# Set-up hyperparameters
options = {'c1': 0.5, 'c2': 0.3, 'w':0.9}

# Call instance of PSO
optimizer = ps.single.GlobalBestPSO(n_particles=10, dimensions=8, options=options)

# Perform optimization
cost, pos = optimizer.optimize(disc_loss, iters=1000)
whzup commented 4 years ago

@zohimchandani Have you actually verify that your objective function works without pyswarms?

stale[bot] commented 4 years ago

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.