"""Time evolution builder usage examples."""

# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

################################################################################
# start-cell-create
from qdk_chemistry.algorithms import create

# Create a time evolution builder
trotter = create("hamiltonian_unitary_builder", "trotter")
# end-cell-create
################################################################################

################################################################################
# start-cell-configure-trotter
# Configure a second-order Trotter builder with automatic step count
trotter = create("hamiltonian_unitary_builder", "trotter")
trotter.settings().set("order", 2)
trotter.settings().set("target_accuracy", 1e-3)
trotter.settings().set("error_bound", "commutator")
# end-cell-configure-trotter
################################################################################

################################################################################
# start-cell-configure-qdrift
# Configure qDRIFT with a fixed seed for reproducibility
qdrift = create("hamiltonian_unitary_builder", "qdrift")
qdrift.settings().set("num_samples", 500)
qdrift.settings().set("seed", 42)
qdrift.settings().set("merge_duplicate_terms", True)
qdrift.settings().set("commutation_type", "qubit_wise")
# end-cell-configure-qdrift
################################################################################

################################################################################
# start-cell-configure-pr
# Configure partially randomized builder
pr = create("hamiltonian_unitary_builder", "partially_randomized")
pr.settings().set("weight_threshold", 0.1)
pr.settings().set("trotter_order", 2)
pr.settings().set("num_random_samples", 200)
pr.settings().set("seed", 42)
# end-cell-configure-pr
################################################################################

################################################################################
# start-cell-run
import numpy as np
from qdk_chemistry.algorithms import create
from qdk_chemistry.data import Structure

# 1. Setup molecule
coords = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.4]])
symbols = ["H", "H"]
structure = Structure(coords, symbols=symbols)

# 2. SCF
scf_solver = create("scf_solver")
E_scf, wfn_scf = scf_solver.run(
    structure, charge=0, spin_multiplicity=1, basis_or_guess="sto-3g"
)

# 3. Hamiltonian construction
hamiltonian_constructor = create("hamiltonian_constructor")
hamiltonian = hamiltonian_constructor.run(wfn_scf.get_orbitals())

# 4. Qubit mapping
from qdk_chemistry.data import MajoranaMapping

n_spin_orbitals = 2 * hamiltonian.get_orbitals().get_num_molecular_orbitals()
qubit_mapper = create("qubit_mapper")
qubit_ham = qubit_mapper.run(
    hamiltonian, MajoranaMapping.jordan_wigner(n_spin_orbitals)
)

# 5. Build time evolution unitary
trotter = create("hamiltonian_unitary_builder", "trotter", order=2, time=0.1)
evolution = trotter.run(qubit_ham)

print(f"Container type: {evolution.get_container_type()}")
print(f"Number of qubits: {evolution.get_num_qubits()}")
print(evolution.get_summary())
# end-cell-run
################################################################################

################################################################################
# start-cell-list-implementations
from qdk_chemistry.algorithms import registry

# List all registered time evolution builder implementations
implementations = registry.available("hamiltonian_unitary_builder")
print(implementations)  # e.g. ['trotter', 'qdrift', 'partially_randomized', 'lcu']
# end-cell-list-implementations
################################################################################

################################################################################
# start-cell-configure-lcu
from qdk_chemistry.algorithms import create

# Create an LCU block encoding builder
lcu = create("hamiltonian_unitary_builder", "lcu")

# Configure for qubitization (quantum walk operator)
lcu.settings().set("quantum_walk", True)
lcu.settings().set("power", 1)
# end-cell-configure-lcu
################################################################################

################################################################################
# start-cell-run-lcu
import numpy as np
from qdk_chemistry.algorithms import create
from qdk_chemistry.data import Structure

# 1. Setup molecule
coords = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.4]])
symbols = ["H", "H"]
structure = Structure(coords, symbols=symbols)

# 2. SCF
scf_solver = create("scf_solver")
E_scf, wfn_scf = scf_solver.run(
    structure, charge=0, spin_multiplicity=1, basis_or_guess="sto-3g"
)

# 3. Hamiltonian construction
hamiltonian_constructor = create("hamiltonian_constructor")
hamiltonian = hamiltonian_constructor.run(wfn_scf.get_orbitals())

# 4. Qubit mapping
from qdk_chemistry.data import MajoranaMapping

n_spin_orbitals = 2 * hamiltonian.get_orbitals().get_num_molecular_orbitals()
qubit_mapper = create("qubit_mapper")
qubit_ham = qubit_mapper.run(
    hamiltonian, MajoranaMapping.jordan_wigner(n_spin_orbitals)
)

# 5. Build LCU block encoding with quantum walk
lcu = create("hamiltonian_unitary_builder", "lcu", quantum_walk=True)
unitary = lcu.run(qubit_ham)

print(f"Container type: {unitary.get_container_type()}")
print(f"Number of qubits: {unitary.get_num_qubits()}")
print(unitary.get_summary())
# end-cell-run-lcu
################################################################################
