Exemplo n.º 1
0
def createPlot(exactGroundStateEnergy=-1.14,
               numberOfIterations=1000,
               bondLength=0.735,
               initialParameters=None,
               numberOfParameters=16,
               shotsPerPoint=1000,
               registerSize=12,
               map_type='jordan_wigner'):
    if initialParameters is None:
        initialParameters = np.random.rand(numberOfParameters)
    global qubitOp
    global qr_size
    global shots
    global values
    global plottingTime
    plottingTime = True
    shots = shotsPerPoint
    qr_size = registerSize
    optimizer = COBYLA(maxiter=numberOfIterations)
    iterations = []
    values = []
    for i in range(numberOfIterations):
        iterations.append(i + 1)

    #Build molecule with PySCF
    driver = PySCFDriver(atom="H .0 .0 .0; H .0 .0 " + str(bondLength),
                         unit=UnitsType.ANGSTROM,
                         charge=0,
                         spin=0,
                         basis='sto3g')
    molecule = driver.run()
    repulsion_energy = molecule.nuclear_repulsion_energy
    num_spin_orbitals = molecule.num_orbitals * 2
    num_particles = molecule.num_alpha + molecule.num_beta

    #Map fermionic operator to qubit operator and start optimization
    ferOp = FermionicOperator(h1=molecule.one_body_integrals,
                              h2=molecule.two_body_integrals)
    qubitOp = ferOp.mapping(map_type=map_type, threshold=0.00000001)
    sol_opt = optimizer.optimize(numberOfParameters,
                                 energy_opt,
                                 gradient_function=None,
                                 variable_bounds=None,
                                 initial_point=initialParameters)

    #Adjust values to obtain Energy Error
    for i in range(len(values)):
        values[i] = values[i] + repulsion_energy - exactGroundStateEnergy

    #Saving and Plotting Data
    filename = 'Energy Error - Iterations'
    with open(filename, 'wb') as f:
        pickle.dump([iterations, values], f)
    plt.plot(iterations, values)
    plt.ylabel('Energy Error')
    plt.xlabel('Iterations')
    plt.show()
Exemplo n.º 2
0
def main():
    # Parse all command line arguments
    args = parser.parse_args()
    shots = args.shots
    seed = args.seed
    basis = args.bell
    logfile = args.logfile
    verbose = args.verbose

    # Define the logger
    logger = logging.getLogger('task2')
    if logfile:
        logger.addHandler(logging.FileHandler(logfile))
    if verbose:
        logger.addHandler(logging.StreamHandler())
    logger.setLevel(logging.DEBUG)

    np.random.seed(seed=seed)

    # Get the noise model
    device_backend = FakeVigo()
    noise_model = NoiseModel.from_backend(device_backend)
    coupling_map = device_backend.configuration().coupling_map
    basis_gates = noise_model.basis_gates

    backend = Aer.get_backend('qasm_simulator')
    statevector_backend = Aer.get_backend('statevector_simulator')

    circuit = build_circuit(measure=basis)
    circuit_for_counts = build_circuit(measure='computational')
    unmeasured_circuit = build_circuit(measure=None)

    # qiskit's COBYLA can't take args to pass to the objective function, so we freeze them with functools.partial
    optimizer = COBYLA(maxiter=1000, tol=1e-8, disp=True)

    for nshots in shots:
        logger.debug('====================================================================================')
        logger.debug(f'\nShots per iteration: {nshots}')
        logger.debug(circuit)

        partial_objective_function = partial(objective_function, circuit=circuit, shots=nshots, backend=backend, bell_basis=(basis == 'bell'),
                                            noise_model=noise_model, coupling_map=coupling_map, basis_gates=basis_gates)
        ret = optimizer.optimize(num_vars=2, objective_function=partial_objective_function, 
                                initial_point=np.random.rand(len(circuit.parameters))*4*np.pi - 2*np.pi)


        params = ret[0]
        logger.debug(f'\nParameters:\n{params}')
        logger.debug(f'\nStatevector:\n{execute_circuit(unmeasured_circuit, params, statevector_backend).result().get_statevector()}')
        logger.debug(f'\nSimulated results:\n{execute_circuit(circuit_for_counts, params, backend, nshots, noise_model, coupling_map, basis_gates).result().get_counts()}')
        logger.debug('====================================================================================\n')

    sys.exit(ExitStatus.success)
Exemplo n.º 3
0
def createPlot1(bondLengthMin=0.5,
                bondLengthMax=1.5,
                numberOfPoints=10,
                initialParameters=None,
                numberOfParameters=16,
                shotsPerPoint=1000,
                registerSize=12,
                map_type='jordan_wigner'):
    if initialParameters is None:
        initialParameters = np.random.rand(numberOfParameters)
    global qubitOp
    global qr_size
    global shots
    shots = shotsPerPoint
    qr_size = registerSize
    optimizer = COBYLA(maxiter=20)
    bondLengths = []
    values = []
    delta = (bondLengthMax - bondLengthMin) / numberOfPoints
    for i in range(numberOfPoints):
        bondLengths.append(bondLengthMin + i * delta)
    for bondLength in bondLengths:
        driver = PySCFDriver(atom="H .0 .0 .0; H .0 .0 " + str(bondLength),
                             unit=UnitsType.ANGSTROM,
                             charge=0,
                             spin=0,
                             basis='sto3g')
        molecule = driver.run()
        repulsion_energy = molecule.nuclear_repulsion_energy
        num_spin_orbitals = molecule.num_orbitals * 2
        num_particles = molecule.num_alpha + molecule.num_beta
        ferOp = FermionicOperator(h1=molecule.one_body_integrals,
                                  h2=molecule.two_body_integrals)
        qubitOp = ferOp.mapping(map_type=map_type, threshold=0.00000001)
        sol_opt = optimizer.optimize(numberOfParameters,
                                     energy_opt,
                                     gradient_function=None,
                                     variable_bounds=None,
                                     initial_point=initialParameters)
        values.append(sol_opt[1] + repulsion_energy)
    filename = 'Energy - BondLengths'
    with open(filename, 'wb') as f:
        pickle.dump([bondLengths, values], f)
    plt.plot(bondLengths, values)
    plt.ylabel('Ground State Energy')
    plt.xlabel('Bond Length')
    plt.show()
    def optimize(self):

        # Define objective function
        def objfunc(params):
            return -self.expectation(beta=params[0:self.p],
                                     gamma=params[self.p:2 * self.p])

        # Optimize parameters
        optimizer = COBYLA(maxiter=1000, tol=0.0001)
        params = self.beta_val + self.gamma_val
        ret = optimizer.optimize(num_vars=2 * self.p,
                                 objective_function=objfunc,
                                 initial_point=params)
        self.beta_val = ret[0][0:self.p]
        self.gamma_val = ret[0][self.p:2 * self.p]
        self.error = ret[1]
        return
Exemplo n.º 5
0
    def optimize_params(self, n_iterations, tolerance):
        '''
        This function will take care of optimizing the parameters for the circuit.
        Algorithm being used: COBYLA
        
        Parameters:
            n_iterations  : Maximum number of iterations for the optimizer
            tolerance     : Consecutive loss tolerance value for convergence check
            
        Returns:
            List of optimized parameters, final loss value, iterations performed 
        '''

        cobyla_optimizer = COBYLA(maxiter=n_iterations,
                                  disp=True,
                                  tol=tolerance)

        return cobyla_optimizer.optimize(num_vars=2,
                                         variable_bounds=[(0, np.pi),
                                                          (0, np.pi)],
                                         objective_function=self.entropy_loss,
                                         initial_point=np.random.uniform(
                                             0, 2 * np.pi, 2))
Exemplo n.º 6
0
    # Execute the quantum circuit to obtain the probability distribution associated with the current parameters
    result = execute(qc, backend, shots=NUM_SHOTS).result()
    # Obtain the counts for each measured state, and convert those counts into a probability vector
    output_distr = get_probability_distribution(result.get_counts(qc))
    # Calculate the cost as the distance between the output distribution and the target distribution
    cost = sum([np.abs(output_distr[i] - target_distr[i]) for i in range(2)])
    return cost


# Initialize the COBYLA optimizer; number of shots will increase accuracy
optimizer = COBYLA(maxiter=500, tol=0.0001)

# Create the initial parameters (noting that our single qubit variational form has 3 parameters)
params = np.random.rand(3)
ret = optimizer.optimize(num_vars=3,
                         objective_function=objective_function,
                         initial_point=params)

# Obtain the output distribution using the final parameters
qc = get_var_form(ret[0])
counts = execute(qc, backend, shots=NUM_SHOTS).result().get_counts(qc)
output_distr = get_probability_distribution(counts)

print("Target Distribution:", target_distr)
print("Obtained Distribution:", output_distr)
print("Output Error (Manhattan Distance):", ret[1])
print("Parameters Found:", ret[0])

################################################################################################
################ https: // qiskit.org/textbook/ch-applications/vqe-molecules.html ##############
################################################################################################
class HeuristicOpt(Optimizer):
    def __init__(self, ansatz: Ansatz, budget=120):
        super().__init__(ansatz)
        self.__similarity_thresh = 1e-2
        self.sweep_count = 1
        self.maxiter = 200
        self.budget = budget
        self.sweep_divisions = 4
        self.optimizer = COBYLA(maxiter=self.maxiter, tol=1e-3)
        self.objective_function = None
        self.sweepspace_dimension = None
        self.num_vars = None

    def optimal_single_parameter(self, param_index):
        objective_function = self.ansatz.cost_function
        initial_point = self.get_parameter_list()
        # Yields the optimal parameterization when ONLY considering param_index (not globally optimal)
        initial_point[param_index] = 0
        self.set_parameter_list(initial_point)
        exp_0 = objective_function()
        initial_point[param_index] = np.pi
        self.set_parameter_list(initial_point)
        exp_pi = objective_function()

        # If the two evaluations are very close to each other, there is no need to waste another 2 function calls
        if np.abs(exp_0 - exp_pi) < self.__similarity_thresh:
            self.set_parameter_list(initial_point)
            return

        initial_point[param_index] = np.pi / 2
        self.set_parameter_list(initial_point)
        exp_pi_div_2 = objective_function()
        initial_point[param_index] = -np.pi / 2
        self.set_parameter_list(initial_point)
        exp_minus_pi_div_2 = objective_function()

        # If all evaluations where the same, just return.
        if exp_0 == exp_pi == exp_pi_div_2 == exp_minus_pi_div_2:
            self.set_parameter_list()
            return

        B = np.arctan2(exp_0 - exp_pi, exp_pi_div_2 - exp_minus_pi_div_2)
        # Set the parameter optimally
        theta_opt = -(np.pi / 2) - B + 2 * np.pi
        initial_point[param_index] = theta_opt
        self.set_parameter_list(initial_point)
        return

    def get_parameter_index(self, best_node):
            targ_q = best_node.cell.get_qubit()
            targ_d = best_node.cell.get_depth()
            # Get the index in the parameter array of the node to optimize
            index = 0
            for ii in range(self.max_depth):
                for i in range(self.num_qubits):
                    if (i == targ_q) and (ii == targ_d):
                        return index - 1
                    else:
                        index += self.ansatz[i, ii].get_param_count()
            raise AssertionError("[ASSERTION FAILURE] Unreachable code reached.")

    @staticmethod
    def gram_schmidt_columns(X):
        Q, R = np.linalg.qr(X)
        return Q

    def meta_cost_function(self, hyperparams):
        sweeps = []
        for i in range(self.sweepspace_dimension):
            sweeps.append(np.array(self.gram_schmidt_columns(self.X[:,[i]])))
        vec = 0
        for i, hyperparam in enumerate(hyperparams):
            vec += sweeps[i] * hyperparam
        params = [vec[i] for i in range(self.num_vars)]
        self.set_parameter_list(params)
        return self.objective_function()

    def sweep(self):
        initial_point = self.get_parameter_list()
        num_vars = len(initial_point)
        self.sweepspace_dimension = int(num_vars / self.sweep_divisions)
        self.num_vars = num_vars
        best = self.objective_function()
        sweep_params = [np.random.rand()] * self.sweepspace_dimension
        best_params = sweep_params
        for sweep in range(self.sweep_count):
            self.X = np.random.normal(size=(num_vars, self.sweepspace_dimension))
            ret = self.optimizer.optimize(num_vars=self.sweepspace_dimension, objective_function=self.meta_cost_function,
                                          initial_point=np.asarray(sweep_params))
            sweep_params = ret[0]
            if ret[1] < best:
                best = ret[1]
                best_params = sweep_params

        self.meta_cost_function(best_params)

    def optimize(self, random=False):
        # params = self.get_parameter_list()
        budget = self.budget

        if random:
            # permutation = list(np.random.permutation([i for i in range(len(self.get_parameter_list()))]))
            permutation = [i for i in range(len(self.get_parameter_list()))]
            permutation *= int(budget / len(permutation))
            for i in permutation:
                self.optimal_single_parameter(i)
        else:
            target_n = self.num_qubits - 1
            target_d = 0
            # target_n = np.random.randint(0, self.num_qubits)
            # target_d = np.random.randint(0, self.max_depth)
            # @TODO Run sweep opt on the parameters on the deepest layer
            # Pick a random node to add to the priority queue first.
            self.objective_function = self.ansatz.cost_function
            self.sweep()

            first_cell = self.ansatz[target_n, target_d]
            pq = _PriorityQueue(first_cell)

            # Iterate over all nodes in the ansatz, and add each to the PQ, if it is not the node that was already selected
            for i in range(self.num_qubits):
                for ii in range(self.max_depth):
                    if (i != target_n) or (ii != target_d):
                        new_item = _Node(self.ansatz[i, ii])
                        pq.insert(new_item)


            for i in range(budget):
                best_node = pq.pop()
                next_cell = best_node.cell.get_next_cell()

                if next_cell is not None:
                    next_cell_n = next_cell.get_qubit()
                    next_cell_d = next_cell.get_depth()
                    f = lambda xn, xd: (next_cell_n == xn) and (next_cell_d == xd)
                    pq.increment_priority(f)
                bd = best_node.cell.get_depth()
                bn = best_node.cell.get_qubit()
                if bn + 1 < self.num_qubits:
                    f = lambda xn, xd: (xn == bn + 1) and (xd == bd)
                    pq.increment_priority(f)
                if bd + 1 < self.max_depth:
                    f = lambda xn, xd: (xn == bn) and (xd == bd + 1)
                    pq.increment_priority(f)
                if bd - 1 >= 0:
                    f = lambda xn, xd: (xn == bn) and (xd == bd - 1)
                    pq.increment_priority(f)

                param_index = self.get_parameter_index(best_node)
                self.optimal_single_parameter(param_index)
                pq.insert(best_node)

                if np.random.rand() < 0.005:
                    self.sweep()


        return
Exemplo n.º 8
0
def createPlot3(minShots=50,
                stepSize=50,
                maxShots=1000,
                exactGroundStateEnergy=-1.14,
                totalNumberOfShots=10000,
                bondLength=0.735,
                initialParameters=None,
                numberOfParameters=16,
                registerSize=12,
                map_type='jordan_wigner'):
    if initialParameters is None:
        initialParameters = np.random.rand(numberOfParameters)
    global qubitOp
    global qr_size
    global shots
    global values
    qr_size = registerSize

    #Build Molecule and stuff
    driver = PySCFDriver(atom="H .0 .0 .0; H .0 .0 " + str(bondLength),
                         unit=UnitsType.ANGSTROM,
                         charge=0,
                         spin=0,
                         basis='sto3g')
    molecule = driver.run()
    repulsion_energy = molecule.nuclear_repulsion_energy
    num_spin_orbitals = molecule.num_orbitals * 2
    num_particles = molecule.num_alpha + molecule.num_beta
    ferOp = FermionicOperator(h1=molecule.one_body_integrals,
                              h2=molecule.two_body_integrals)
    qubitOp = ferOp.mapping(map_type=map_type, threshold=0.00000001)

    #create Shots Array
    shotValues = []
    numberOfDataPoints = math.floor((maxShots - minShots) / stepSize)
    for i in range(numberOfDataPoints):
        shotValues.append(minShots + i * stepSize)

    values = []
    print(shotValues)
    for shotsPerPoint in shotValues:
        shots = shotsPerPoint
        if shotsPerPoint <= totalNumberOfShots:
            optimizer = COBYLA(maxiter=math.floor(totalNumberOfShots /
                                                  shotsPerPoint))
            sol_opt = optimizer.optimize(numberOfParameters,
                                         energy_opt,
                                         gradient_function=None,
                                         variable_bounds=None,
                                         initial_point=initialParameters)
            values.append(sol_opt[1] + repulsion_energy)
        else:
            raise Exception('Error: Total number of shots too small.')

    #Calculate Energy Error
    for i in range(len(values)):
        values[i] = values[i] + repulsion_energy - exactGroundStateEnergy

    #Saving and Plotting Data
    filename = 'Energy Error - Number of Shots'
    with open(filename, 'wb') as f:
        pickle.dump([shotValues, values], f)
    plt.plot(shotValues, values)
    plt.ylabel('Energy Error')
    plt.xlabel('Number of Shots')
    plt.show()
Exemplo n.º 9
0
class VQE:
    def __init__(self, num_qubits, cost_function,
                 variational_circuit: VariationalCircuit):

        self._num_qubits = num_qubits
        self._cost_function = cost_function
        self._variational_circuit = variational_circuit

        self._num_shots = 10000

        self.min_cost = 9e9
        self._max_itr = int(2000 * (num_qubits / 4))
        self._tol = float('1e-' + str(num_qubits))

        print(self._max_itr, "tol", self._tol)

        self._num_itr = 0

        self._backend = Aer.get_backend("qasm_simulator")
        self._optimizer = COBYLA(rhobeg=1.5,
                                 maxiter=self._max_itr,
                                 tol=self._tol)

        self._SCALE_FACTOR = 1  # Factor by which the expectation value is scaled by

    # This method is similar to the objective_function method in the piazza example.
    def objective_function(self, params):

        qc = self._variational_circuit.generateCircuit(params)
        result = execute(qc, self._backend,
                         shots=self._num_shots).result().get_counts()
        cost = self._cost_function(result)

        if cost < self.min_cost:
            self.min_cost = cost

        self._num_itr += 1

        if self._num_itr == self._max_itr:
            print("max itr reached")

        return cost

    def execute(self):

        # Bool to check whether the variational circuit is a custom one
        isCustom = self._variational_circuit.isCustom()

        num_params = self._num_qubits
        num_params *= 9 if isCustom else 6  # Scaling the number of parameters according the the circuit

        print("Processing...")
        # Using the optimizer to optimize the parameters for the quantum circuit.
        self._optimizer.optimize(num_vars=num_params,
                                 objective_function=self.objective_function,
                                 initial_point=np.zeros(num_params))

        print("Processing Complete")

        # Returning the min cost.
        return -self.min_cost / self._SCALE_FACTOR