Skip to content

Commit

Permalink
Merge pull request #541 from Avimita-amc8313/hamlib-changes
Browse files Browse the repository at this point in the history
Hamlib with varying paramaters
  • Loading branch information
rtvuser1 authored Jul 3, 2024
2 parents 28f6166 + 041d76a commit 031db58
Show file tree
Hide file tree
Showing 7 changed files with 436 additions and 222 deletions.
37 changes: 37 additions & 0 deletions hamlib/_common/hamiltonian_simulation_exact.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit_algorithms import TimeEvolutionProblem, SciPyRealEvolver
from qiskit_aer import Aer
from qiskit import transpile
import numpy as np
np.random.seed(0)
import execute as ex
Expand Down Expand Up @@ -171,3 +173,38 @@ def HamiltonianSimulationExact(n_spins: int):
# print (result)

return result.evolved_state.probabilities_dict()

def HamiltonianSimulationExact_Noiseless(n_spins: int):
"""
Simulate a quantum Hamiltonian circuit for a specified number of spins using a noiseless quantum simulator.
This function creates a quantum circuit, transpiles it for optimal execution, and runs it on a quantum simulator.
It simulates the circuit with a specified number of shots and collects the results to compute the probability
distribution of measurement outcomes, normalized to represent probabilities.
Args:
n_spins (int): The number of spins (qubits) to simulate in the circuit.
Returns:
dict: A dictionary with keys representing the outcomes and values representing the probabilities of these outcomes.
Note:
This function uses the 'qasm_simulator' backend from Qiskit's Aer module, which simulates a quantum circuit
that measures qubits and returns a count of the measurement outcomes. The function assumes that the circuit
creation and the simulator are perfectly noiseless, meaning there are no errors during simulation.
"""
qc, _, _ = create_circuit(n_spins)
num_shots = 100000
backend = Aer.get_backend("qasm_simulator")
# Transpile and run the circuits
transpiled_qc = transpile(qc, backend, optimization_level=0)
job = backend.run(transpiled_qc, shots=num_shots)
result = job.result()
counts = result.get_counts(qc)
# Normalize probabilities for Heisenberg model circuit
dist = {}
for key in counts.keys():
prob = counts[key] / num_shots
dist[key] = prob

return dist
327 changes: 190 additions & 137 deletions hamlib/qiskit/benchmarks-qiskit.ipynb

Large diffs are not rendered by default.

12 changes: 0 additions & 12 deletions hamlib/qiskit/dataset.json

This file was deleted.

30 changes: 30 additions & 0 deletions hamlib/qiskit/hamlib_parameter_use_input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"FH_D-1.hdf5": {
"fh": "graph-1D-grid-nonpbc-qubitnodes",
"Lx": "{n_qubits/2}",
"U": "0",
"enc": "jw"
},
"tfim.hdf5": {
"graph": "1D-grid-nonpbc-qubitnodes",
"Lx": "{n_qubits}",
"h": "0.1"
},
"random_max3sat-hams.hdf5": {
"max3sat_n": "{n_qubits}",
"ratio": "2",
"rinst": "00"
},
"heis.hdf5": {
"graph": "1D-grid-nonpbc-qubitnodes",
"Lx": "{n_qubits}",
"h": "0"
},
"BH_D-1_d-4.hdf5": {
"bh_graph": "1D-grid-nonpbc-qubitnodes",
"Lx": "{n_qubits/2}",
"U": "10",
"enc": "gray",
"d": "4"
}
}
6 changes: 4 additions & 2 deletions hamlib/qiskit/hamlib_simulation_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import metrics as metrics

from hamlib_simulation_kernel import HamiltonianSimulation, kernel_draw, create_circuit, get_valid_qubits
from hamiltonian_simulation_exact import HamiltonianSimulationExact
from hamiltonian_simulation_exact import HamiltonianSimulationExact, HamiltonianSimulationExact_Noiseless
# from hamlib_test import create_circuit, HamiltonianSimulationExact
from qiskit_algorithms import TimeEvolutionProblem, SciPyRealEvolver

Expand Down Expand Up @@ -87,6 +87,8 @@ def analyze_and_print_result(qc, result, num_qubits: int,
correct_dist = precalculated_data[f"TFIM - Qubits{num_qubits}"]
elif method == 2 and hamiltonian == "tfim":
correct_dist = precalculated_data[f"Exact TFIM - Qubits{num_qubits}"]
elif method == 1 and hamiltonian == "hamlib":
correct_dist = HamiltonianSimulationExact_Noiseless(num_qubits)
elif method == 2 and hamiltonian == "hamlib":
if verbose:
print(f"... begin exact computation ...")
Expand Down Expand Up @@ -289,7 +291,7 @@ def execution_handler(qc, result, num_qubits, type, num_shots):
##########

# draw a sample circuit
kernel_draw(hamiltonian, use_XX_YY_ZZ_gates, method)
# kernel_draw(hamiltonian, use_XX_YY_ZZ_gates, method)

# Plot metrics for all circuit sizes
options = {"ham": hamiltonian, "method":method, "shots": num_shots, "reps": max_circuits}
Expand Down
113 changes: 57 additions & 56 deletions hamlib/qiskit/hamlib_simulation_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import os
import requests
import zipfile
import json
from qiskit.quantum_info import SparsePauliOp, Pauli
from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import PauliEvolutionGate
Expand Down Expand Up @@ -86,8 +87,57 @@ def sparse_pauliop(terms, num_qubits):
hamiltonian = SparsePauliOp.from_list(pauli_list, num_qubits=num_qubits)
return hamiltonian

dataset_name_template = ""
filename = ""
def get_valid_qubits(min_qubits, max_qubits, skip_qubits):
"""
Get an array of valid qubits within the specified range, removing duplicates.
Returns:
list: A list of valid qubits.
"""
global dataset_name_template, filename

# Create an array with the given min, max, and skip values
qubit_candidates = list(range(min_qubits, max_qubits + 1, skip_qubits))
valid_qubits_set = set() # Use a set to avoid duplicates

for qubits in qubit_candidates:
initial_n_spins = qubits // 2 if "{n_qubits/2}" in dataset_name_template else qubits
n_spins = initial_n_spins

# print(f"Starting check for qubits = {qubits}, initial n_spins = {n_spins}")

found_valid_dataset = False

while n_spins <= max_qubits:
dataset_name = dataset_name_template.replace("{n_qubits}", str(n_spins)).replace("{n_qubits/2}", str(n_spins))
# print(f"Checking dataset: {dataset_name}")

data = process_hamiltonian_file(filename, dataset_name)
if data is not None:
# print(f"Valid dataset found for n_spins = {n_spins}")
if "{n_qubits/2}" in dataset_name_template:
valid_qubits_set.add(n_spins * 2) # Add the original qubits value
else:
valid_qubits_set.add(qubits)
found_valid_dataset = True
break
else:
# print(f"Dataset not available for n_spins = {n_spins}. Trying next value...")
n_spins += 1
if n_spins >= (qubits + skip_qubits) // 2 if "{n_qubits/2}" in dataset_name_template else (qubits + skip_qubits):
print(f"No valid dataset found for qubits = {qubits}")
break

if found_valid_dataset:
continue # Move to the next candidate in the original skip sequence

valid_qubits = list(valid_qubits_set) # Convert set to list to remove duplicates
valid_qubits.sort() # Sorting the qubits for consistent order

if verbose:
print(f"Final valid qubits: {valid_qubits}")

return valid_qubits

# In hamiltonian_simulation_kernel.py

Expand All @@ -108,10 +158,13 @@ def create_circuit(n_spins: int, time: float = 0.2, num_trotter_steps: int = 5):
tuple: A tuple containing the constructed QuantumCircuit and the Hamiltonian as a SparsePauliOp.
"""
global dataset_name_template, filename
# global filename
global QCI_


# dataset_name_template = construct_dataset_name(filename)
process_data(dataset_name_template)
# Replace placeholders with actual n_spins value
dataset_name = dataset_name_template.replace("{n_spins}", str(n_spins)).replace("{n_spins/2}", str(n_spins // 2))
dataset_name = dataset_name_template.replace("{n_qubits}", str(n_spins)).replace("{n_qubits/2}", str(n_spins // 2))

if verbose:
print(f"Trying dataset: {dataset_name}") # Debug print
Expand Down Expand Up @@ -156,58 +209,6 @@ def create_circuit(n_spins: int, time: float = 0.2, num_trotter_steps: int = 5):
# print(f"Dataset not available for n_spins = {n_spins}.")
return None, None, None

def get_valid_qubits(min_qubits, max_qubits, skip_qubits):
"""
Get an array of valid qubits within the specified range, removing duplicates.
Returns:
list: A list of valid qubits.
"""
global dataset_name_template, filename

# Create an array with the given min, max, and skip values
qubit_candidates = list(range(min_qubits, max_qubits + 1, skip_qubits))
valid_qubits_set = set() # Use a set to avoid duplicates

for qubits in qubit_candidates:
initial_n_spins = qubits // 2 if "{n_spins/2}" in dataset_name_template else qubits
n_spins = initial_n_spins

# print(f"Starting check for qubits = {qubits}, initial n_spins = {n_spins}")

found_valid_dataset = False

while n_spins <= max_qubits:
dataset_name = dataset_name_template.replace("{n_spins}", str(n_spins)).replace("{n_spins/2}", str(n_spins))
# print(f"Checking dataset: {dataset_name}")

data = process_hamiltonian_file(filename, dataset_name)
if data is not None:
# print(f"Valid dataset found for n_spins = {n_spins}")
if "{n_spins/2}" in dataset_name_template:
valid_qubits_set.add(n_spins * 2) # Add the original qubits value
else:
valid_qubits_set.add(qubits)
found_valid_dataset = True
break
else:
# print(f"Dataset not available for n_spins = {n_spins}. Trying next value...")
n_spins += 1
if n_spins >= (qubits + skip_qubits) // 2 if "{n_spins/2}" in dataset_name_template else (qubits + skip_qubits):
print(f"No valid dataset found for qubits = {qubits}")
break

if found_valid_dataset:
continue # Move to the next candidate in the original skip sequence

valid_qubits = list(valid_qubits_set) # Convert set to list to remove duplicates
valid_qubits.sort() # Sorting the qubits for consistent order

if verbose:
print(f"Final valid qubits: {valid_qubits}")

return valid_qubits


############### Circuit Definition

Expand Down
Loading

0 comments on commit 031db58

Please sign in to comment.