from qiskit import QuantumCircuit

# Create circuit
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.draw('mpl',style="iqp",initial_state=True)

import qiskit.quantum_info as qi
from qiskit.visualization import array_to_latex

qc = QuantumCircuit(2)
qc.x(0)
qc.h(0)
qc.cx(0, 1)
psi = qi.Statevector.from_instruction(qc)
array_to_latex(psi)
# quiz-time!

from qiskit.visualization import plot_state_qsphere

plot_state_qsphere(psi)

from qiskit.visualization import plot_state_city

plot_state_city(psi)

from qiskit.visualization import plot_state_hinton

plot_state_hinton(psi)

from qiskit.visualization import plot_state_paulivec

plot_state_paulivec(psi)

circuit.measure_all()

circuit.draw('mpl',style="iqp",initial_state=True)

from qiskit_aer import AerSimulator

backend = AerSimulator() # this is the simulator we'll use
job = backend.run(circuit,shots=1000) # this runs the experiment

result = job.result()
counts = result.get_counts()
# quiz-time!

# quiz-time!

from qiskit_ibm_runtime import QiskitRuntimeService, Sampler, Options
# set account here https://quantum.ibm.com/
service = QiskitRuntimeService(instance="ibm-q-ikerbasque/industry-qiskit-/generic-project")
# when loading your IBM Quantum account for the first time you need to specify your token:
#service = QiskitRuntimeService(instance="ibm-q-ikerbasque/industry-qiskit-/generic-project", token="token")

[(b.name, b.configuration().n_qubits) for b in service.backends()]

from qiskit_ibm_provider import least_busy

backend = service.least_busy(simulator=False, operational=True)
#backend = service.backend("ibm_brisbane")
print(backend)

from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
pm = generate_preset_pass_manager(backend=backend, initial_layout=[0,6], optimization_level=3)
t_qc = pm.run(circuit)

t_qc.draw('mpl',style="iqp",idle_wires=False)

from qiskit.visualization import plot_circuit_layout, plot_gate_map
display(plot_circuit_layout(t_qc, backend))

pm = generate_preset_pass_manager(backend=backend, optimization_level=3)
t_qc = pm.run(circuit)
t_qc.draw('mpl',style="iqp",idle_wires=False)

options = Options()
options.resilience_level = 1
options.optimization_level = 3
 
# Create a Sampler object
sampler = Sampler(backend=backend, options=options)

# Submit the circuit to Sampler
job = sampler.run(t_qc,shots=1000)
print(job.job_id())

job.status()

# get results
job = service.job('cqcbzgyapgkg008jxcwg')
result = job.result()
counts = result.quasi_dists
plot_histogram(counts)

from qiskit.quantum_info import Operator

def phase_oracle(n, indices_to_mark, name = 'Oracle'):
    qc = QuantumCircuit(n, name=name)
    oracle_matrix = np.identity(2**n)
    for index_to_mark in indices_to_mark:
        oracle_matrix[index_to_mark, index_to_mark] = -1
    qc.unitary(Operator(oracle_matrix), range(n))
    return qc

def diffuser(n):
    qc = QuantumCircuit(n, name='Diff')
    qc.h(range(n))
    qc.append(phase_oracle(n,[0]),range(n))
    qc.h(range(n))
    return qc

def Grover(n, marked):
    qc = QuantumCircuit(n, n)
    r = int(np.round(np.pi/(4*np.arcsin(np.sqrt(len(marked)/2**n)))-1/2))
    print(f'{n} qubits, basis state {marked} marked, {r} rounds')
    qc.h(range(n))
    for _ in range(r):
        qc.append(phase_oracle(n,marked), range(n))
        qc.append(diffuser(n), range(n))
    qc.measure(range(n), range(n))
    return qc

import numpy as np

n = 5
x = np.random.randint(2**n)
marked = [x]
qc = Grover(n, marked)

qc.draw('mpl',style="iqp",initial_state=True)

from qiskit_aer import AerSimulator
from qiskit import transpile

backend = AerSimulator()
tqc = transpile(qc, backend)

result = backend.run(tqc, shots=10000).result()
counts = result.get_counts(qc)
print(counts)
plot_histogram(counts) 
# quiz-time!

def Grover_run_roundwise(n, marked):
    r = int(np.round(np.pi/(4*np.arcsin(np.sqrt(len(marked)/2**n)))-1/2))
    print(f'{n} qubits, basis state {marked} marked, {r} rounds')
    counts = []
    for i in range(r):
        qc = QuantumCircuit(n, n)
        qc.h(range(n))
        for _ in range(i+1):
            qc.append(phase_oracle(n,marked), range(n))
            qc.append(diffuser(n), range(n))
        qc.measure(range(n), range(n))
        tqc = transpile(qc, backend)
        result = backend.run(tqc, shots=10000).result()
        counts.append(result.get_counts())
    return counts

backend = AerSimulator()
counts = Grover_run_roundwise(n,marked) 
# quiz-time!

n = 3
x = np.random.randint(2**n)
y = np.random.randint(2**n)
while y==x:
    y = np.random.randint(2**n)
marked = [x,y]
qc = Grover(n, marked)

backend = service.least_busy(simulator=False, operational=True)
print("least busy backend: ", backend)
#backend = provider.get_backend('ibm_osaka')

shots = 10000
pm = generate_preset_pass_manager(backend=backend, optimization_level=3)
tqc = pm.run(qc)
job = sampler.run(tqc,shots=1000)
print(job.job_id())

old_job = service.job('cqcc09sqgrzg008cw7ng')
results = old_job.result()
counts = results.quasi_dists
plot_histogram(counts)

from qiskit.circuit.library import PhaseOracle

# this indicates that the input is CNF with five variables and seven clauses
input_3sat = '''
c example DIMACS-CNF 3-SAT
p cnf 5 7 
-1 -5 0
1 -3 0
-1 3 0
2 4 0
-2 -3 -4 0
1 -2 0
2 -4 0
'''

with open("3sat.dimacs", "w") as text_file:
    text_file.write(input_3sat)

oracle = PhaseOracle.from_dimacs_file("3sat.dimacs")

from qiskit_algorithms import Grover, AmplificationProblem
from qiskit.utils import QuantumInstance
from qiskit.primitives import Sampler
import warnings
#warnings.filterwarnings('ignore')

problem = AmplificationProblem(oracle=oracle)

# Use Grover's algorithm to solve the problem
grover = Grover(sampler = Sampler())
result = grover.amplify(problem)
result.top_measurement

plot_histogram(result.circuit_results) 
# quiz-time!

# transpile the circuit for our backend
qc = grover.construct_circuit(problem, max(result.iterations))
qc.measure_all()
backend = service.backend("ibm_osaka")
grover_compiled = transpile(qc, backend=backend, optimization_level=3)

print('gates = ', grover_compiled.count_ops())
print('depth = ', grover_compiled.depth())

from qiskit import QuantumCircuit, transpile

# GHZ state
n = 3
qc = QuantumCircuit(n, n)
qc.h(1)
qc.cx(1, 0)
qc.cx(1, 2)
qc.measure(range(n), range(n))
layout = [0,14,18]
pm = generate_preset_pass_manager(backend=backend, initial_layout=layout, optimization_level=3)
t_qc = pm.run(qc)

from qiskit_ibm_runtime import Sampler
options.resilience_level = 1
sampler = Sampler(backend=backend,options=options)
#job = sampler.run(t_qc, shots=shots)
#print(job.job_id())

options.resilience_level = 0
sampler = Sampler(backend=backend,options=options)
#job = sampler.run(t_qc, shots=shots)
#print(job.job_id())

ghz_mem = service.job('cqdryehfejeg0085wt00') # [0,14,18]
ghz_nomem = service.job('cqdryfsgtagg008qr8s0')
results = ghz_nomem.result()
counts_nomem = results.quasi_dists
results = ghz_mem.result()
counts_mem = results.quasi_dists
plot_histogram([counts_nomem[0],counts_mem[0]], legend=['noisy', 'mitigated'])
# quiz-time!

print(counts_nomem[0])
print(counts_mem[0])

import qiskit.tools.jupyter
%qiskit_version_table