# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Windows 不可以執行!!!!  請到IBM的LAB進行實驗

# ### 練習 5 - 變分量子特徵求解器
#
# ## 歷史背景
#
# 在過去的十年中，量子計算機迅速成熟並開始實現費曼最初的夢想，即能夠以量子方式模擬自然規律的計算系統。 2014 年由 <NAME> 首次撰寫的一篇論文介紹了變分量子特徵求解器 (VQE)，這是一種用於尋找分子基態能量（最低能量）的算法，其電路比其他方法淺得多。 [1] 並且，在 2017 年，IBM Quantum 團隊使用 VQE 算法來模擬氫化鋰分子的基態能量。 [2]
#
# VQE 的特色是將一些問題的處理工作量外包給一台經典計算機。 該算法從稱為 ansatz（最佳猜測）的參數化量子電路開始，然後使用經典優化器找到該電路的最佳參數。 VQE 相對於經典算法的優勢來自這樣一個事實，即量子處理單元可以表示和存儲問題的確切波函數，這對於經典計算機來說是一個指數級的難題。
#
# T
# 這項練習5使您可以自己實現費曼的夢想，設置變分量子特徵值來確定分子的基態和能量。這很有趣因為可以使用基態來計算各種分子性質，例如精準作用在核上立。可以用來進行分子動力學模擬，探索化學系統中隨時間變化的情況。
#
#
#
# ### 參考文獻
#
# 1. <NAME>, et al. "A variational eigenvalue solver on a photonic quantum processor." Nature communications 5.1 (2014): 1-7.
# 2. <NAME>, et al. "Hardware-efficient variational quantum eigensolver for small molecules and quantum magnets." Nature 549.7671 (2017): 242-246.
# 3. Sokolov, <NAME>., et al. "Microcanonical and finite-temperature ab initio molecular dynamics simulations on quantum computers." Physical Review Research 3.1 (2021): 013125.
#
# ## 簡介
#
# 對於VQE的應用，您將能夠選擇如何編寫模擬，尤其是ansatz量子電路。.
# 這是因為在誤差大的量子計算機上運行VQE時重要，的任務之一是通過找到能夠代表基態的最精簡的量子電路來減少真實度的損失(來減少錯誤)。.
# 實際上,這需要減少雙味原量子閘的數量(例如. CNOT),同時又不失去準確性。.
#
# <div class="alert alert-block alert-success">
#
# <b>Goal</b> 
# 查找最精簡的ansatz電路，以準確表示給定問題的基態。發揮創意。
#
#     
# <b>Plan</b> 
#
# 首先,您將學習如何為最小的分子組成VQE模擬,然後將所學到的知識應用於較大的分子。
#
# **1. Tutorial -  VQE for H$_2$:** 熟悉VQE,並通過運行特徵向量模擬來選擇ansatz /經典優化器的最佳組合。.
#
# **2. Final Challenge - VQE for LiH:** 
# 執行與第一部分類似的調查,但僅限於特徵模擬器。. 使用Qiskit中可用的qubit數量減少方案,並為該較大的系統找到最佳電路。優化電路,並發揮您的想像力,找到選擇參數化電路的最佳構建塊的方法,並組成它們以構建用於基態的最精簡的ansatz電路,這比Qiskit中已經提供的電路要好。
#
# </div>
#
#
# <div class="alert alert-block alert-danger">
#
# 以下是VQE模擬背後理論的介紹。. 在繼續之前,您不必了解整個過程。. 別害怕!
#
# </div>
#
#
#
#

# ## Theory
#
# 以下是代表如何在量子計算機上執行使用VQE的分子模擬的一般工作流程。.
#
# <img src="resources/workflow.png" width=800 height= 1400/>
#
# 他的核心思想混合量子和古典方法是將其最擅長的部分外包給** CPU(經典處理單元)**和** QPU(量子處理單元)**。. CPU負責列出需要測量的語法以計算能量並優化電路參數。. QPU實現代表系統量子態的量子電路並測量能量。. 以下是一些更多詳細信息:
#
# The [Hartree–Fock (HF) method](https://en.wikipedia.org/wiki/Hartree%E2%80%93Fock_method#:~:text=In%20computational%20physics%20and%20chemistry,system%20in%20a%20stationary%20state.)
# efficiently computes an approximate grounds state wavefunction by assuming that the latter can be represented by a single Slater determinant (e.g. for H$_2$ molecule in STO-3G basis with 4 spin-orbitals and qubits, $|\Psi_{HF} \rangle = |0101 \rangle$ where electrons occupy the lowest energy spin-orbitals). What QPU does later in VQE is finding a quantum state (corresponding circuit and its parameters) that can also represent other states associated missing electronic correlations (i.e. $\sum_i c_i |i\rangle$ states in  $|\Psi \rangle = c_{HF}|\Psi_{HF} \rangle + \sum_i c_i |i\rangle $ where $i$ is a bitstring).  
#
# 計算HF後,將Hamiltonian中的運算符映射到使用費米子到量子變換的QPU上的測量值(請參見下面的Hamiltonian部分)。.可以進一步分析系統的屬性,以減少量子位的數量或縮短ansatz電路:。
#
# - For Z2 symmetries and two-qubit reduction, see [Bravyi *et al*, 2017](https://arxiv.org/abs/1701.08213v1).
# - For entanglement forging, see [Eddins *et al.*, 2021](https://arxiv.org/abs/2104.10220v1).
# - For the adaptive ansatz see, [Grimsley *et al.*,2018](https://arxiv.org/abs/1812.11173v2), [Rattew *et al.*,2019](https://arxiv.org/abs/1910.09694), [Tang *et al.*,2019](https://arxiv.org/abs/1911.10205). You may use the ideas found in those works to find ways to shorten the quantum circuits.
#
# **QPU** 運用量子電路 (看下方 Ansatzes 的部分), 參數化角度 $\vec\theta$, 通過放置各種單個量子位旋轉和糾纏器來表示基態波函數。 (e.g. 雙位元量子閘).  量子優勢在於,QPU可以有效地表示和存儲確切的波函數,這對於具有多個原子的系統在經典計算機上變得難以計算。.  最後,QPU測量選擇的運算符(例如. 代表漢密爾頓人)。.
# 以下是VQE算法每個部分的數學細節。. 如果您觀看我們的內容,可能會有所幫助。 [video episode about VQE](https://www.youtube.com/watch?v=Z-A6G0WVI9w).
#
#
# ### Hamiltonian 
#
# 在這裡,我們解釋瞭如何獲得需要測量的運算符以獲取給定係統的能量。.
# 這些術語包含在分子漢密爾頓語中,定義為:
# $$
# \begin{aligned}
# \hat{H} &=\sum_{r s} h_{r s} \hat{a}_{r}^{\dagger} \hat{a}_{s} \\
# &+\frac{1}{2} \sum_{p q r s} g_{p q r s} \hat{a}_{p}^{\dagger} \hat{a}_{q}^{\dagger} \hat{a}_{r} \hat{a}_{s}+E_{N N}
# \end{aligned}
# $$
# 與
# $$
# h_{p q}=\int \phi_{p}^{*}(r)\left(-\frac{1}{2} \nabla^{2}-\sum_{I} \frac{Z_{I}}{R_{I}-r}\right) \phi_{q}(r)
# $$
# $$
# g_{p q r s}=\int \frac{\phi_{p}^{*}\left(r_{1}\right) \phi_{q}^{*}\left(r_{2}\right) \phi_{r}\left(r_{2}\right) \phi_{s}\left(r_{1}\right)}{\left|r_{1}-r_{2}\right|} 
# $$
#
#
# 其中$ h_ {r s} $和$ g_ {p q r s} $是一體/二體積分(使用Hartree-Fock方法)和$ E_ {N N} $核排斥能。.
#  單體積分代表電子的動能及其與核的相互作用。.
#  兩體積分代表電子-電子相互作用。.
# $\ hat {a} _ {r} ^ {\ dagger},\ hat {a} _ {r} $運算符表示自旋軌道$ r $中電子的創建和an滅,並要求對運算符進行映射,以便我們可以在量子計算機上測量它們。.
# 請注意,VQE使電子能源最小化,因此您必須檢索並添加核排斥能$ E_ {NN} $才能計算總能量。.
#      
#
#     
#
# 因此,對於$ h_ {r s} $和$ g_ {p q r s} $張量中的每個非零矩陣元素,我們都可以通過以下費米子到量子位轉換來構造相應的Pauli字符串(Pauli運算符的張量乘積)。.
#  例如,在Jordan-Wigner映射中,軌道$ r = 3 $,我們獲得以下Pauli字符串:。
# $$
# \hat a_{3}^{\dagger}= \hat \sigma_z \otimes \hat \sigma_z \otimes\left(\frac{ \hat \sigma_x-i \hat \sigma_y}{2}\right) \otimes 1 \otimes \cdots \otimes 1
# $$
# 其中$\ hat \ sigma_x,\ hat \ sigma_y,\ hat \ sigma_z $是著名的Pauli運算符。. 放置$ \ hat \ sigma_z $運算符的張量乘積以執行費米離子反換向關係。.
# 下面給出了水分子的14個自旋軌道與約14個量子位之間的Jordan-Wigner映射的表示形式:
#
# <img src="resources/mapping.png" width=600 height= 1200/>
#
#
# 然後,只需替換一個/兩個身體的興奮(例如. $ \ hat {a} _ {r} ^ {\ dagger} \ hat {a} _ {s} $,$ \ hat {a} _ {p} ^ \ dagger} \ hat {a} _ {r} \ hat {a} _ {s} $)。. $\ hat {P} _i $,請參見上圖)。. 生成的運算符集已準備好在QPU上進行測量。
# 有關其他詳細信息,請參見。  [Seeley *et al.*, 2012](https://arxiv.org/abs/1208.5986v1).
#
# ### Ansatzes
#
# 您主要可以使用兩種ansatzes的化學問題。. 
# - **q-UCC ansatzes** are physically inspired, and roughly map the electron excitations to quantum circuits. The q-UCCSD ansatz (`UCCSD`in Qiskit) possess all possible single and double electron excitations. The paired double q-pUCCD (`PUCCD`) and singlet q-UCCD0 (`SUCCD`) just consider a subset of such excitations (meaning significantly shorter circuits) and have proved to provide good results for dissociation profiles. For instance, q-pUCCD doesn't have single excitations and the double excitations are paired as in the image below.
# - **Heuristic ansatzes (`TwoLocal`)** were invented to shorten the circuit depth but still be able to represent the ground state. 
#
# 如下圖所示,R門代表參數化的單個量子位旋轉,$ U_ {CNOT} $糾纏器(兩個量子位門)。. 這樣做的想法是,在重複某些$ D $倍後,相同的塊(具有獨立的參數)可以到達地面狀態。. 
#
# For additional details refer to [Sokolov *et al.* (q-UCC ansatzes)](https://arxiv.org/abs/1911.10864v2) and [Barkoutsos *et al.* (Heuristic ansatzes)](https://arxiv.org/pdf/1805.04340.pdf).
#
# <img src="resources/ansatz.png" width=700 height= 1200/>
#
#
#
# ### VQE
#
#
# 給定一個具有未知最小特徵值$ E_ {min} $的Hermitian運算符$ \ hat H $,與特徵狀態$ | psi_ {min} \ rangle $相關聯,VQE提供了一個估計值$ E_ {\ theta} $,以$ E_ {min為界} $:
#
# \begin{align*}
#     E_{min} \le E_{\theta} \equiv \langle \psi(\theta) |\hat H|\psi(\theta) \rangle
# \end{align*}  
#
# 其中$ |\ psi(\ theta)\ rangle $是與$ E_ {\ theta} $關聯的試用狀態。. 通過將以$ U(\ theta)$表示的參數化電路應用於某些任意起始狀態$ |\ psi \ rangle $,該算法獲得估計值$ U(\ theta)|\ psi \ rangle \ equiv | psi(\ theta)\ rangle $ on $ | \ psi {min} \ rangle $。. 經典優化器通過更改參數$ \ theta $並最小化$ \ langle \ psi(\ theta)的期望值來迭代優化估計值| hat H |\ psi(\ theta)\ rangle $。
#
# As applications of VQE, there are possibilities in molecular dynamics simulations, see [Sokolov *et al.*, 2021](https://arxiv.org/abs/2008.08144v1), and excited states calculations, see [Ollitrault *et al.*, 2019](https://arxiv.org/abs/1910.12890) to name a few.
#
# <div class="alert alert-block alert-danger">
#  
# <b> References for additional details</b> 
#
# 有關實現此算法的qiskit-nature教程,請參見。  [here](https://qiskit.org/documentation/nature/tutorials/01_electronic_structure.html)
# 但這還不夠,您可能想看看。  [first page of github repository](https://github.com/Qiskit/qiskit-nature) and the [test folder](https://github.com/Qiskit/qiskit-nature/tree/main/test)它們包含為每個組件編寫的測試,它們提供了使用每個功能的基本代碼。.
#
# </div>

# ## 最終挑戰 - LiH 分子的 VQE
#
#
# 在這部分中，您將使用 STO-3G 基礎和 PySCF 驅動程序模擬 LiH 分子。
# </div>
#     
# <div class="alert alert-block alert-success">
#
# <b>目標</b> 
#
#
# 實驗所有參數,然後找到最好的ansatz。. 您可以根據需要發揮創造力。!
#
# 對於每個問題,請給出第1部分的“ ansatz”對象。. 您的最終分數將僅基於第2部分。.
#     
# </div>
#
# 請注意,該系統現在更大。. 通過檢索自旋軌道的數量來確定此系統需要多少量子位。. 
#
# ### Reducing the problem size
#
#
# 您可能想減少用於模擬的量子位數量:。
#
# - you could freeze the core electrons that do not contribute significantly to chemistry and consider only the valence electrons. Qiskit  already has this functionality implemented. So inspect the different transformers in `qiskit_nature.transformers`  and find the one that performs the freeze core approximation.
# - you could use `ParityMapper` with `two_qubit_reduction=True` to eliminate 2 qubits.
# - you could reduce the number of qubits by inspecting the symmetries of your Hamiltonian. Find a way to use `Z2Symmetries` in Qiskit.
#
# ### Custom ansatz 
#
# You might want to explore the ideas proposed in [Grimsley *et al.*,2018](https://arxiv.org/abs/1812.11173v2), [<NAME> *et al.*,2019](https://arxiv.org/abs/1911.10205), [Rattew *et al.*,2019](https://arxiv.org/abs/1910.09694), [Tang *et al.*,2019](https://arxiv.org/abs/1911.10205). 
# You can even get try machine learning algorithms to generate best ansatz circuits.
#
# ### Setup the simulation
#
#
# 現在讓我們運行Hartree-Fock計算,其餘的取決於您。!
#
# <div class="alert alert-block alert-danger">
#
# <b>Attention</b> 
#
# 我們在下面給出“驅動程序”,“ initial_point”,“ initial_state”應該保持給定的狀態。.
# 然後,您可以自由探索Qiskit中所有其他可用的東西。.
# 因此,您必須從此初始點開始(所有參數設置為0.01):。
#     
# `initial_point = [0.01] * len(ansatz.ordered_parameters)`
#     or
# `initial_point = [0.01] * ansatz.num_parameters`
#
# 您的初始狀態必須是Hartree-Fock狀態:。
#     
# `init_state = HartreeFock(num_spin_orbitals, num_particles, converter)`
#     
# 對於每個問題,請給出“ ansatz”對象。.
# 請記住,您必須達到化學精度$ | E_ {exact}-E_ {VQE} | \ leq 0.004 $ Ha $ = 4 $ mHa。.
#
# </div>

#匯入工具
from qiskit import IBMQ, BasicAer, Aer

# #### 1. Driver
# Qiskit中可用的經典化學代碼的接口稱為驅動程序。. 例如,我們有“ PSI4Driver”,“ PyQuanteDriver”,“ PySCFDriver”。.
#
# 通過在下面的單元格中運行驅動程序(給定基礎集和分子幾何的Hartree-Fock計算),我們獲得了有關分子的所有必要信息,然後應用了量子算法。.

# +
#匯入分子資訊
from qiskit_nature.drivers import PySCFDriver

molecule = 'Li 0.0 0.0 0.0; H 0.0 0.0 1.5474'
driver = PySCFDriver(atom=molecule)
qmolecule = driver.run()
# -

# <div class="alert alert-block alert-danger">
#
# <b>Questions</b> 
#     
# Look into the attributes of `qmolecule` and answer the questions below.
#
#     
# 1. We need to know the basic characteristics of our molecule. What is the total number of electrons in your system?
# 2. What is the number of molecular orbitals?
# 3. What is the number of spin-orbitals?
# 3. How many qubits would you need to simulate this molecule with Jordan-Wigner mapping?
# 5. What is the value of the nuclear repulsion energy?
#     
# </div>
#

# +
n_el = qmolecule.num_alpha + qmolecule.num_beta

n_mo = qmolecule.num_molecular_orbitals
n_so = 2 * qmolecule.num_molecular_orbitals
n_q = 2* qmolecule.num_molecular_orbitals

e_nn = qmolecule.nuclear_repulsion_energy
print(n_el)
print(n_mo)
print(n_so)
print(n_q)
# -

# #### 2. Electronic structure problem
#
# 然後,您可以創建一個`ElectronicStructureProblem',可以生成費米離子運算符的列表,然後再將它們映射到量子位(Pauli字符串)。.

# +
#寫下系統總能量
from qiskit_nature.problems.second_quantization.electronic import ElectronicStructureProblem
from qiskit_nature.transformers import FreezeCoreTransformer

# 冷凍可以忽略計算的軌域
freezeCoreTransfomer = FreezeCoreTransformer(freeze_core=True,remove_orbitals=[3,4])

#這裡是建立要解決問題的地方，我們改動了函式的相關參數
#可以在這裡找到更多答案 : https://qiskit.org/documentation/nature/tutorials/01_electronic_structure.html
qmolecule = freezeCoreTransfomer.transform(qmolecule)
problem = ElectronicStructureProblem(driver,q_molecule_transformers=[freezeCoreTransfomer])

# 創建二次量子化運算符 - 二次量子化的目的在於得到系統哈密頓量也就是總能量 
second_q_ops = problem.second_q_ops()

# 哈密頓量
main_op = second_q_ops[0]

#在這裡我建議print哈密頓量查看
print(main_op)
# -

# #### 3. QubitConverter
# 允許定義您將在模擬中使用的映射。. 您可以嘗試不同的映射。 我們將堅持使用“ JordanWignerMapper”,因為它允許簡單的對應關係:量子位代表分子中的自旋軌道。.

# +

from qiskit_nature.mappers.second_quantization import ParityMapper, BravyiKitaevMapper, JordanWignerMapper
from qiskit_nature.converters.second_quantization.qubit_converter import QubitConverter
from qiskit.opflow.primitive_ops import PauliSumOp
# 設置映射器和量子比特轉換器 - 在這裡我們轉化哈密頓量為 Qubits的相關參數
mapper_type = 'ParityMapper'

if mapper_type == 'ParityMapper':
    mapper = ParityMapper()
elif mapper_type == 'JordanWignerMapper':
    mapper = JordanWignerMapper()
elif mapper_type == 'BravyiKitaevMapper':
    mapper = BravyiKitaevMapper()


#two_qubit_reduction - 使我們能忽略兩個位元，進而降低CX閘的使用
#z2symmetry_reduction - Z2對稱約化 - 可以搜尋群論找到更多答案
converter = QubitConverter(mapper=mapper, two_qubit_reduction=True,z2symmetry_reduction = [-1])

# 費米子算符映射到量子比特算符
num_particles = (problem.molecule_data_transformed.num_alpha,
             problem.molecule_data_transformed.num_beta)
qubit_op = converter.convert(main_op, num_particles=num_particles)
# -

# #### 4. Initial state
# 正如我們在理論部分中所描述的那樣,化學的良好初始狀態是HF狀態(即.  | 𝑃𝑠𝑖𝐻𝐹 𝑟𝑎𝑛𝑔𝑙𝑒=|0101 𝑟𝑎𝑛𝑔𝑙𝑒 )。. 我們可以將其初始化如下:

# +
from qiskit_nature.circuit.library import HartreeFock

# 在這裡引入HartreeFock作為初始值 - 用來解多體量子系統的波函數
# 相關連結 :https://en.wikipedia.org/wiki/Hartree%E2%80%93Fock_method

num_particles = (problem.molecule_data_transformed.num_alpha,
             problem.molecule_data_transformed.num_beta)
num_spin_orbitals = 2 * problem.molecule_data_transformed.num_molecular_orbitals
init_state = HartreeFock(num_spin_orbitals, num_particles, converter)

#我猜可能的波函數
print(init_state)
# -

# ## 解題想法
#
# 在解題目的過程中，我們成功使用了TwoLocal成功拿到cost = 30，但是看到slack的討論中我們看到了有人只使用了3個CX完成!於是我們開始發想是什麼方法可以達成，在我們的努力不懈下，我們發現到TwoLocal也可以有3個CX的電路也就是重複一次，但我觀察到，電路中有被優化的參數只有Z方向，於是我就嚐試使用u閘一次控制三個參數，因此我們必須放置4x2個u閘，且每一個u的參數都是各自獨立的，藉由這個想法，在搭配上SLSQP的強力優化效果，得到了3分解。
#
# ### 優化器怎麼作用? 
# 比如 :     theta0 = Parameter('a0')
# 這行程式給定了一參數名為'a0'，優化器會自動調整他的角度，而不是我們手動調整，經過一次計算後發現實際值跟理想值優些差距，就會再次微調角度參數，再次送入量子電腦中計算，再得到一解，反覆循環直到收斂

# #### 5. Ansatz
# 最重要的選擇之一是選擇近似基態的量子電路。. 這是qiskit電路庫的示例,其中包含許多製作自己的電路的可能性。

# +
from qiskit.circuit.library import TwoLocal
from qiskit_nature.circuit.library import UCCSD, PUCCD, SUCCD

# 選擇我們想要的 ansatz - 可以理解程波函數
ansatz_type = "Custom"

# q-UCC antatze 的相關係數
num_particles = (problem.molecule_data_transformed.num_alpha,
             problem.molecule_data_transformed.num_beta)
num_spin_orbitals = 2 * problem.molecule_data_transformed.num_molecular_orbitals

# 定義五種ansatz，其中第五種是自訂義的
if ansatz_type == "TwoLocal":
    # 放置在所有具有獨立參數的量子位上的單個量子位旋轉
    rotation_blocks = ['ry', 'rz']
    # 糾纏閘
    entanglement_blocks = 'cx'
    # # 怎樣的糾纏方式?
    entanglement = 'full'
#   entanglement = 'linear'

    # 具有獨立參數的rotation_blocks + entanglement_blocks 的重複次數    
    repetitions = 1
    # 跳過最後的 rotation_blocks 層
    skip_final_rotation_layer = True
    ansatz = TwoLocal(qubit_op.num_qubits, rotation_blocks, entanglement_blocks, reps=repetitions, 
                      entanglement=entanglement, skip_final_rotation_layer=skip_final_rotation_layer)
    # 添加初始狀態
    ansatz.compose(init_state, front=True, inplace=True)
elif ansatz_type == "UCCSD":
    ansatz = UCCSD(converter,num_particles,num_spin_orbitals,initial_state = init_state)
elif ansatz_type == "PUCCD":
    ansatz = PUCCD(converter,num_particles,num_spin_orbitals,initial_state = init_state)
elif ansatz_type == "SUCCD":
    ansatz = SUCCD(converter,num_particles,num_spin_orbitals,initial_state = init_state)
elif ansatz_type == "Custom":
    # 如何編寫自己的電路的示例
    from qiskit.circuit import Parameter, QuantumCircuit, QuantumRegister
    # 定義變分參數 - 在這裡我們定義了每一個u的參數
    theta0 = Parameter('a0')
    phi0 = Parameter('a1')
    lam0 = Parameter('a2')
    theta1 = Parameter('a3')
    phi1 = Parameter('a4')
    lam1 = Parameter('a5')
    theta2 = Parameter('a6')
    phi2 = Parameter('a7')
    lam2 = Parameter('a8')
    theta3 = Parameter('a9')
    phi3 = Parameter('a10')
    lam3 = Parameter('a11')
    
    theta4 = Parameter('a12')
    phi4 = Parameter('a13')
    lam4 = Parameter('a14')
    theta5 = Parameter('a15')
    phi5 = Parameter('a16')
    lam5 = Parameter('a17')
    theta6 = Parameter('a18')
    phi6 = Parameter('a19')
    lam6 = Parameter('a20')
    theta7 = Parameter('a21')
    phi7 = Parameter('a22')
    lam7 = Parameter('a23')
    theta8 = Parameter('a24')
    phi8 = Parameter('a25')
    lam8 = Parameter('a26')
    gamma= Parameter('a27')
    
    n = qubit_op.num_qubits
    # 製作一個空的量子電路
    qc = QuantumCircuit(qubit_op.num_qubits)
    qubit_label = 0
    qc.u(theta0,phi0,lam0,0)
    qc.u(theta1,phi1,lam1,1)
    
    qc.u(theta2,phi2,lam2,2)
    qc.u(theta3,phi3,lam3,3)

    # Place a CNOT ladderCUGate(theta, phi, lam, gamma, label=None, ctrl_state=None)
    qc.cx(0,1)
    qc.cx(1,2)
    qc.cx(2,3)

    qc.barrier()
    qc.u(theta4,phi4,lam4,0)
    qc.u(theta5,phi5,lam5,1)
    
    qc.u(theta6,phi6,lam6,2)
    qc.u(theta7,phi7,lam7,3)
    
    
    ansatz = qc
    ansatz.compose(init_state, front=True, inplace=True)

print(ansatz)
# -

print( qubit_op.num_qubits)

# #### 6. Backend
# 最重要的選擇之一是選擇近似基態的量子電路。. 這是qiskit電路庫的示例,其中包含許多製作自己的電路的可能性。.

from qiskit import Aer
backend = Aer.get_backend('statevector_simulator')

# #### 7. Optimizer
# 優化器指導ansatz參數的演變,因此研究能量收斂非常重要,因為它將定義必須在QPU上執行的測量次數。 明智的選擇可能會大大減少所需的能源評估數量。.

# +
from qiskit.algorithms.optimizers import COBYLA, L_BFGS_B, SPSA, SLSQP,DIRECT_L

#選擇使用的優化器 - 在我的測試中 SLSQP為最佳優化器
optimizer_type = 'SLSQP'

# You may want to tune the parameters 
# of each optimizer, here the defaults are used
if optimizer_type == 'COBYLA':
    optimizer = COBYLA(maxiter=500)
elif optimizer_type == 'L_BFGS_B':
    optimizer = L_BFGS_B(maxfun=500)
elif optimizer_type == 'SPSA':
    optimizer = SPSA(maxiter=500)
elif optimizer_type == 'SLSQP':
    optimizer = SLSQP(maxiter=500)
# -

# #### 8. Exact eigensolver
# 出於學習目的,我們可以通過Hamiltonian矩陣的精確對角化準確地解決問題,因此我們知道VQE的目標。 當然,該矩陣的尺寸在分子軌道的數量上呈指數級,因此您可以嘗試對選擇的大分子進行此操作,並查看其變慢程度。. 對於非常大的系統,您將用盡內存來嘗試存儲其波函數。.

# +
from qiskit_nature.algorithms.ground_state_solvers.minimum_eigensolver_factories import NumPyMinimumEigensolverFactory
from qiskit_nature.algorithms.ground_state_solvers import GroundStateEigensolver
import numpy as np 

def exact_diagonalizer(problem, converter):
    solver = NumPyMinimumEigensolverFactory()
    calc = GroundStateEigensolver(converter, solver)
    result = calc.solve(problem)
    return result

result_exact = exact_diagonalizer(problem, converter)
exact_energy = np.real(result_exact.eigenenergies[0])
print("Exact electronic energy", exact_energy)
print(result_exact)

# The targeted electronic energy for H2 is -1.85336 Ha
# Check with your VQE result.
# -

# #### 9. VQE and initial parameters for the ansatz
# Now we can import the VQE class and run the algorithm.

# +
#匯入 VQE 函式 - 這個是IBM已經寫好的我們可以直接使用
from qiskit.algorithms import VQE
from IPython.display import display, clear_output


# Print and save the data in lists
def callback(eval_count, parameters, mean, std):  
    # Overwrites the same line when printing
    display("Evaluation: {}, Energy: {}, Std: {}".format(eval_count, mean, std))
    clear_output(wait=True)
    counts.append(eval_count)
    values.append(mean)
    params.append(parameters)
    deviation.append(std)

counts = []
values = []
params = []
deviation = []

# Set initial parameters of the ansatz
# We choose a fixed small displacement 
# So all participants start from similar starting point
try:
    initial_point = [0.01] * len(ansatz.ordered_parameters)
except:
    initial_point = [0.01] * ansatz.num_parameters
#執行VQE
#在這裡我們可以看到我們上面所定義的參數都在這裡被輸入
algorithm = VQE(ansatz,
                optimizer=optimizer,
                quantum_instance=backend,
                callback=callback,
                initial_point=initial_point)

result = algorithm.compute_minimum_eigenvalue(qubit_op)

print(result)

# +
# Check your answer using following code
from qc_grader import grade_ex5
freeze_core = True # change to True if you freezed core electrons

grade_ex5(ansatz,qubit_op,result,freeze_core)
# -

# ## 另解



StarcoderdataJupyterScriptsDedupFiltered