Skip to main content
IBM Quantum Platform

SqDRIFT 회로 생성하기

샘플 기반 양자 대각화( SQD )를 사용할 때는 비트열을 샘플링할 안자츠를 선택해야 합니다. SqDRIFT 변형은 대신 대상 해밀토니안으로부터 직접 구성된 시간 진화 회로들의 앙상블을 사용합니다. 이는 해밀토니안의 계수를 바탕으로 해밀토니안에서 더 작은 시간 진화 연산자를 부분 표본 추출함으로써 달성되며, 이를 ‘ qDRIFT ’ 트로터화(Trotterization) 방법이라고 한다.

이 시작 가이드에서는 이러한 무작위 회로들의 앙상블을 생성하는 방법을 설명합니다.


1. 해밀토니안 설정

이 가이드의 목적을 위해, FCIDUMP 파일에서 ‘ N2 ’의 전자 구조 해밀토니안을 불러오십시오. .을 구성하는 다른 방법들도 있습니다 FermionOperator. 반드시 해당 문서를 참고하고, 또한 qiskit_fermions.operators.library.

[x] 파이썬

>>> from qiskit_fermions.operators.library import FCIDump
>>> from qiskit_fermions.operators import FermionOperator
>>>
>>> fcidump = FCIDump.from_file("docs/guides/n2.fcidump")
>>> num_modes = 2 * fcidump.norb
>>> hamil = FermionOperator.from_fcidump(fcidump)

[] C

#include <qiskit_fermions.h>

QfFCIDump* fcidump = qf_fcidump_from_file("docs/guides/n2.fcidump");
QfFermionOperator* hamil = qf_ferm_op_from_fcidump(fcidump);
uint32_t num_modes = 2 * qf_fcidump_norb(fcidump);

2. 그룹 해밀토니안 항

계수가 동일한 관련 항들을 묶음으로써, 전자 구조 해밀토니안에 존재하는 다양한 대칭성을 활용하십시오. 이 작업은 ‘ qDRIFT ’ 프로토콜이 샘플링하는 연산자 계수 분포를 변경하지만, 수렴성 보증에는 영향을 미치지 않습니다. 특히, 대칭성을 통해 관련이 있는 항들을 묶으면 파울리 항들이 유리하게 상쇄되어, 그 작용 하에서 상태의 시간 진화를 수행할 때 전체적인 회로 깊이가 줄어든다.

qiskit_fermions.operators.terms.grouping 모듈은 연산자의 항들을 그룹화하기 위한 편리한 함수들을 제공합니다. 이에 대한 자세한 내용은 안내서에서 확인할 수 있습니다.

주의

이 구현은 해밀토니안의 항들이 정규 순서로 배열되어 있음을 전제로 합니다 group_terms_by_electronic_structure() !

[x] 파이썬

>>> from qiskit_fermions.operators.terms.grouping import group_terms_by_electronic_structure
>>> from qiskit_fermions.operators.terms.ordering import canonical_order
>>>
>>> canon = canonical_order(hamil.normal_ordered().simplify(atol=1e-16))
>>> exit_code = group_terms_by_electronic_structure(canon, num_modes, two_body_physicist_order=False)
>>> assert exit_code is None
>>> print(canon.groups)  # the groups attribute now contains some list of group indices
[0, ...]

[] C

QfFermionOperator* normal;
QfExitCode exit = qf_ferm_op_group_terms_by_electronic_structure(normal, num_modes, false);
QfFermionOperator* canon = qf_ferm_op_canonical_order(normal);
힌트

전체 전자 구조 해밀토니안에는 시간 진화 회로에 포함되더라도 관측된 비트열에 아무런 영향을 미치지 않는 특정 항들이 포함되어 있어, 결과적으로 샘플링 오버헤드만 증가시킬 뿐이다. 따라서 다음 단계에서 Evolution 게이트를 구성하기 전에, 이 시점에서 해밀토니안에서 이러한 항들을 제거하는 것이 권장됩니다.

이 설명에 부합하는 항들은 점유-수(occupation-number) 기저에서 대각선인 것들, 즉 수 연산자(number operator)들의 곱( aiaia^\dagger_i a_i )이다. 여기에는 회로에 전역 위상만 도입하는 시간 진화를 갖는 상수 에너지 오프셋과, 시간 진화가 단일 큐비트의 Z 회전에 해당하는 개별 수 연산자, 그리고 ninjn_i n_j 와 같은 고차 곱들이 포함된다. 이들 중 어느 것도 샘플링된 비트열에 영향을 미치지 않는다.

이 함수는 filter_diagonal_terms() 연산자에서 해당 항들을 제자리에서 제거합니다:

[x] 파이썬

>>> from qiskit_fermions.operators.terms.filtering import filter_diagonal_terms
>>>
>>> filter_diagonal_terms(canon)

[] C

qf_ferm_op_filter_diagonal_terms(canon);

이 단계에서 한 번 필터링하는 것이 반복적으로 필터링하는 것보다 비용이 훨씬 적게 듭니다. QDriftTrotterization 트랜스파일된 회로 하나당 한 번씩 실행되므로, 매 호출 시마다 필터링하는 대신 초기에 해밀토니안을 필터링하면, 이를 기반으로 생성된 모든 회로마다 작업을 반복할 필요가 없습니다.


3. 시간 변화 회로를 준비한다

해밀토니안의 시간 진화 회로와 표본을 추출할 기준 회로를 준비하십시오. 이 코드에는 Qiskit 규약을 준수하면서 이를 수행하는 데 필요한 모든 구성 요소가 포함되어 qiskit_fermions.circuit.library 있습니다.

[x] 파이썬

>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import Evolution
>>>
>>> time = 1.0  # you can choose a desired scaling factor here
>>> evo_gate = Evolution(num_modes, canon, time)
>>>
>>> circ = FermionicCircuit(num_modes)
>>> circ.append(evo_gate, circ.modes)

[] C

// WARNING: Qiskit's C API does not yet allow us to implement circuits
// with custom gate definitions.
참고

이 예제에서는 페르미온 모드에 입자를 초기화하지도 않고, 그 최종 상태를 측정하지도 않습니다.


4. QDrift 트로터라이제이션을 사용하여 회로를 트랜스파일하기

qiskit_fermions.transpiler 모듈은 Qiskit의 트랜스파일링 파이프라인과 직접 연동되어, 위에서 생성된 FermionicCircuit 코드를.로 직접 트랜스파일할 수 있게 해줍니다 QuantumCircuit.

jordan_wigner() 페르미온-큐비트 대응 관계를 이용하여, 페르미온으로 표현된 해밀토니안을 파울리 문자열로 표현되도록 변환하십시오. 이는 EvolutionSynthesis 트랜스파일레이션 패스 플러그인을 사용하여 트랜스파일레이션 과정의 일부로 직접 수행할 수 있습니다. 를 사용하여 를 생성하면 generate_preset_jw_pass_manager()FermionicStagedPassManager , 모든 회로 명령어에 대해 조던-위그너 인코딩이 일관되게 사용되도록 보장됩니다.

가장 중요한 점은, 트랜스파일레이션 파이프라인의 해당 optimization 단계에 트랜스파일레이션 QDriftTrotterization 패스를 추가하는 것입니다. 이를 통해 회로가 전체 해밀토니안의 시간적 진화를 사용하지 않도록 보장하며, 이 해밀토니안의 복잡도는 현재 이용 가능한 양자 컴퓨팅 하드웨어의 처리 능력을 초과할 것입니다.

대신, 회로가 트랜스파일될 때마다 각 회로에 대해 고정된 수의 해밀턴 연산 항을 groups 부분 표본 추출합니다. 이를 통해 트랜스파일레이션 파이프라인을 반복적으로 실행함으로써, SqDRIFT 알고리즘에서 요구하는 대로 여러 개의 회로 무작위화 결과를 생성할 수 있습니다.

이 단계에서는 생성할 회로를 사용자 정의하는 데 사용할 수 있는 몇 가지 매개변수도 소개합니다:

  • 생성할 회로 수: num_sqdrift_randomizations
  • 각 회로의 길이를 여기 그룹 단위로 나타내면 다음과 같습니다: num_groups

[x] 파이썬

>>> from qiskit_fermions.transpiler import FermionicPassManager
>>> from qiskit_fermions.transpiler.presets import generate_preset_jw_pass_manager
>>> from qiskit_fermions.transpiler.passes import QDriftTrotterization
>>>
>>> num_groups = 10
>>> qdrift = QDriftTrotterization(num_groups, rng=19)
>>>
>>> pm = generate_preset_jw_pass_manager()
>>> pm.optimization = FermionicPassManager([qdrift])
>>>
>>> num_sqdrift_randomizations = 10
>>> sqdrift_circuits = [
...     pm.run(circ) for _ in range(num_sqdrift_randomizations)
... ]

[] C

// WARNING: Qiskit's C API does not yet allow us to implement circuits
// with custom gate definitions, which we therefore also cannot transpile
// via this API.
참고

앞의 예제는 트랜스파일레이션 QDriftTrotterization 패스 내에서 사용되는 난수 생성기의 seed 값을 고정합니다.


5. 사소한 여진을 걸러낸다

이전 단계에서 걸러진 대각선 항들 외에도, 샘플링된 여기 신호가 샘플링된 비트열에 영향을 미치지 못할 수도 있습니다. 이미 상태가 고정되어 있는(모두 점유되어 있거나 모두 비어 있는) 일련의 모드 내에서만 작용할 때는, 입자를 한 모드에서 다른 모드로 이동시킬 수 없으므로, 그 상태(그리고 결과적으로 최종 측정 결과)를 변화시키지 않는다. QDriftTrotterization 패스에서 설정을 filter_trivial=True 적용하면, 해당 용어들이 샘플링될 때 이를 거부하고 대신 대체 용어를 다시 추출하므로, 결과 회로의 각 슬롯이 num_groups 비사소한 여기 신호를 기여하게 됩니다.

이 필터링 작업에서는 어떤 모드가 처음부터 사용 중 상태인지 파악해야 합니다. 따라서 회로 내의 Evolution 게이트들 앞에 InitializeModes 게이트가 하나 필요하며, 는 이를 구성하는 편리한 방법입니다 InitializeModes.from_hartree_fock() . N2 의 하트리-팍(Hartree-Fock) 참고 문헌(14개의 공간 궤도에 7개의 알파 전자와 7개의 베타 전자)을 여기에 추가하고, 다음을 적용한 경우와 적용하지 않은 경우의 샘플링된 여기 상태를 비교해 보십시오 filter_trivial=True:

[x] 파이썬

>>> from qiskit_fermions.circuit.library import InitializeModes
>>>
>>> init = InitializeModes.from_hartree_fock(fcidump.norb, (7, 7))
>>>
>>> hf_circ = FermionicCircuit(num_modes)
>>> hf_circ.append(init, hf_circ.modes)
>>> hf_circ.append(Evolution(num_modes, canon, time), hf_circ.modes)
>>>
>>> num_groups = 5
>>> qdrift_unfiltered = QDriftTrotterization(num_groups, rng=3480)
>>> qdrift_trivial = QDriftTrotterization(
...     num_groups, filter_trivial=True, rng=3480
... )
>>>
>>> for instruction in FermionicPassManager(qdrift_unfiltered).run(hf_circ)._inner.data:
...     if instruction.operation.name == "Evolution":
...         print(sorted(instruction.operation.operator.get_support()))
[2, 4]
[41, 45, 52]
[15, 45, 55]
[41, 52, 53]
[10, 16, 37, 38]
>>>
>>> for instruction in FermionicPassManager(qdrift_trivial).run(hf_circ)._inner.data:
...     if instruction.operation.name == "Evolution":
...         print(sorted(instruction.operation.operator.get_support()))
[0, 1, 6, 7]
[0, 1, 28, 29]
[4, 13, 55]
[13, 20, 40, 41]
[0, 1, 28, 29]

[] C

// WARNING: Qiskit's C API does not yet allow us to implement circuits
// with custom gate definitions, which we therefore also cannot transpile
// via this API.

필터링 없이 샘플링된 여기 중 어느 것도 점유 집합(0-628-34)에 전혀 닿지 않으므로, 이들 중 어느 것도 입자를 점유 모드와 비점유 모드 사이로 이동시킬 수 없습니다. 모든 여기 현상은 사소한 것이며, 샘플링된 비트열에 아무런 영향도 미치지 않을 것입니다. 의 경우 filter_trivial=True, 이 다섯 가지 모두 거부되고, 점유된 모드와 비점유된 모드가 결합하는 여기 상태로 대체된다. 예를 들어, 최초로 허용된 여기 과정은 입자를 점유 모드 0, 1, 및 6 와 비점유 모드 사이에서 이동시킨다 [0, 1, 6, 7]``7 .

한 번의 여기 상태가 받아들여지면, 그 지지역 내의 모든 모드는 “불확실한” 상태가 되며, 따라서 이후의 샘플에 대해 두 역할 중 어느 쪽이든 수행할 수 있게 된다. 따라서 더 많은 여기 상태가 받아들여질수록 점유된 모드 집합과 비점유된 모드 집합은 계속해서 증가하게 된다. 이것이 바로 두 번째 여기, [0, 1, 28, 29],가 허용되는 이유입니다. 이 모드의 네 가지 모두는 원래 점유된 모드에 속하므로, 원래 비점유된 모드와는 결합하지 않습니다. 첫 번째 여기 상태가 0 와 모드에 닿자마자 이 모드들이 불확정 상태가 되었기 1 때문에(따라서 결합의 “비어 있는” 쪽으로 간주될 수 있게 되었기 때문에) 비로소 받아들여지는 것이다.

참고

앞에 InitializeModes 게이트가 없으면, 필터링할 직업 정보가 filter_trivial=True 없습니다. 해당 Evolution 게이트에 대해 신호를 방출하고 UserWarning , 해당 게이트에 대한 샘플링 신호를 필터링하지 않은 채로 둡니다.


(선택 사항) 페르미온 모드 인덱싱 최적화

트랜스파일레이션 파이프라인에 페르미온 모드 인덱스를 재지정하여 페르미온 여기 스팬 간의 거리를 최소화하는 추가 최적화 단계를 추가할 수 있습니다. 이 최적화는 ‘ SqDRIFT ’ 논문을 통해 소개되었으며, 에 의해 구현되었습니다 build_excitation_span_minimization_model(). 다음과 같은 RelabelModes pass를 사용하면 트랜스파일러 파이프라인에 쉽게 삽입할 수 있습니다:

[x] 파이썬

>>> from pyomo.environ import SolverFactory
>>> from qiskit_fermions.transpiler.passes import RelabelModes
>>>
>>> solver = SolverFactory("appsi_highs")
>>> solver.options["time_limit"] = 10
>>>
>>> qdrift = QDriftTrotterization(5, rng=19)
>>> relabel = RelabelModes(solver=solver)
>>>
>>> pm.optimization = FermionicPassManager([qdrift, relabel])
>>>
>>> relabeled_circ = pm.run(circ)
>>> # if the automatic mode relabeling was successful, the circuit's
>>> # metadata will contain the mode `permutation` information

[] C

// WARNING: This feature is not available via the C API.
참고

내부의 자동 최적화 기능( RelabelModes 이 기능을 활용함 build_excitation_span_minimization_model())을 사용하려면 가 관리하는 선택적 종속성이 필요합니다 HAS_PYOMO.

중요

올바른 부분공간 대각화를 수행하기 위해서는, 최적화 RelabelModes 단계에서 트랜스파일된 회로에서 샘플링된 비트스트링을 해당 회로의 메타데이터에 포함된 정보를 permutation 바탕으로 후처리해야 합니다!


다음 단계

이제 회로 앙상블을 성공적으로 생성했으므로, 이를 통해 비트열을 추출할 수 있습니다. 이를 위해서는 회로가 하드웨어에서 실행되어야 합니다. 자세한 지침은 Qiskit 문서를 참조하십시오.

비트스트링 샘플을 확보한 후에는, SQD 애드온 튜토리얼에서 설명된 바와 같이 이를 해밀토니안 계수와 함께 사용하여 SQD 후처리를 수행할 수 있습니다.

이 페이지가 도움이 되었습니까?
GitHub에서 버그, 오타를 보고하거나 컨텐츠를 요청하십시오.