from qiskit.transpiler import AnalysisPass

class IJustShout(AnalysisPass):
    """Pass that just prints a message."""
    
    def __init__(self, important_message):
        super().__init__()
        self.important_message = important_message
        
    def run(self, dag):
        print(self.important_message)
        return dag

from qiskit.transpiler import PassManager


step1_pm = PassManager(IJustShout("Calling step 1!"))
step2_pm = PassManager(IJustShout("Calling step 2!"))

from qiskit.providers.aer import AerSimulator
from qiskit.utils import QuantumInstance

sim = AerSimulator()

quantum_instance = QuantumInstance(sim, pass_manager=step1_pm, bound_pass_manager=step2_pm)

from qiskit.circuit import QuantumCircuit, Parameter

x = Parameter("x")

circuit = QuantumCircuit(2)
circuit.ry(x, 0)
circuit.cx(0, 1)

circuit.draw("mpl", style="iqx")

from qiskit.opflow import CircuitSampler, AerPauliExpectation, StateFn, H

expectation = StateFn(H ^ H, is_measurement=True) @ StateFn(circuit)
expectation = AerPauliExpectation().convert(expectation)

sampler = CircuitSampler(quantum_instance)

sampler.convert(expectation, {x: 1}).eval()

sampler.convert(expectation, {x: 0.6}).eval()

sampler.convert(expectation, {x: 0.2}).eval()

from qiskit.test.mock import FakeBelem
from qiskit.transpiler import PassManagerConfig
from qiskit.transpiler.preset_passmanagers import level_1_pass_manager

backend = FakeBelem()

unbound_pm = level_1_pass_manager(PassManagerConfig.from_backend(FakeBelem()))
unbound_pm += PassManager(IJustShout("Level 1 pass manager"))

from qiskit.circuit.library.standard_gates.equivalence_library import StandardEquivalenceLibrary as std_eqlib
from qiskit.transpiler.passes import (
  Collect2qBlocks, ConsolidateBlocks, Optimize1qGatesDecomposition,
  RZXCalibrationBuilderNoEcho, UnrollCustomDefinitions, BasisTranslator
)
from qiskit.transpiler.passes.optimization.echo_rzx_weyl_decomposition import EchoRZXWeylDecomposition

# Build the pass manager for the parameterized circuit
rzx_basis = ['rzx', 'rz', 'x', 'sx']

# Build a pass manager for the CX decomposition (works only on bound circuits)
bound_pm = PassManager([
  IJustShout("Pulse-efficient pass manager"),
  
  # Consolidate consecutive two-qubit operations.
  Collect2qBlocks(),
  ConsolidateBlocks(basis_gates=['rz', 'sx', 'x', 'rxx']),

  # Rewrite circuit in terms of Weyl-decomposed echoed RZX gates.
  EchoRZXWeylDecomposition(backend.defaults().instruction_schedule_map),

  # Attach scaled CR pulse schedules to the RZX gates.
  RZXCalibrationBuilderNoEcho(backend),

  # Simplify single-qubit gates.
  UnrollCustomDefinitions(std_eqlib, rzx_basis),
  BasisTranslator(std_eqlib, rzx_basis),
  Optimize1qGatesDecomposition(rzx_basis),
])

from qiskit.algorithms import VQE
from qiskit.algorithms.optimizers import L_BFGS_B
from qiskit.opflow import Z

quantum_instance = QuantumInstance(
    backend, pass_manager=unbound_pm, bound_pass_manager=bound_pm
)

vqe = VQE(optimizer=L_BFGS_B(), quantum_instance=quantum_instance)
result = vqe.compute_minimum_eigenvalue(Z ^ Z)

print(result)

