eoqrid 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eoqrid-0.1.4/LICENSE +21 -0
- eoqrid-0.1.4/MANIFEST.in +2 -0
- eoqrid-0.1.4/PKG-INFO +136 -0
- eoqrid-0.1.4/README.md +114 -0
- eoqrid-0.1.4/eoqrid/__init__.py +8 -0
- eoqrid-0.1.4/eoqrid/eoq_simulator.py +372 -0
- eoqrid-0.1.4/eoqrid/exchange_interaction.py +22 -0
- eoqrid-0.1.4/eoqrid/measurement.py +22 -0
- eoqrid-0.1.4/eoqrid/quantum_state.py +197 -0
- eoqrid-0.1.4/eoqrid/result.py +33 -0
- eoqrid-0.1.4/eoqrid/transpiler.py +411 -0
- eoqrid-0.1.4/eoqrid/util.py +151 -0
- eoqrid-0.1.4/eoqrid.egg-info/PKG-INFO +136 -0
- eoqrid-0.1.4/eoqrid.egg-info/SOURCES.txt +21 -0
- eoqrid-0.1.4/eoqrid.egg-info/dependency_links.txt +1 -0
- eoqrid-0.1.4/eoqrid.egg-info/requires.txt +9 -0
- eoqrid-0.1.4/eoqrid.egg-info/top_level.txt +1 -0
- eoqrid-0.1.4/pyproject.toml +41 -0
- eoqrid-0.1.4/setup.cfg +4 -0
- eoqrid-0.1.4/tests/test_eoq_simulator_execute.py +32 -0
- eoqrid-0.1.4/tests/test_eoq_simulator_optimize.py +289 -0
- eoqrid-0.1.4/tests/test_eoq_simulator_run.py +830 -0
- eoqrid-0.1.4/tests/test_eoq_simulator_transpile.py +76 -0
eoqrid-0.1.4/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sam.N
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
eoqrid-0.1.4/MANIFEST.in
ADDED
eoqrid-0.1.4/PKG-INFO
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: eoqrid
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: Exchange-Only Quantum Computation Simulator
|
|
5
|
+
Author: Sam.N
|
|
6
|
+
License: MIT License
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Programming Language :: Python
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Requires-Python: >=3.12
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: numpy>=2.4.4
|
|
14
|
+
Requires-Dist: networkx>=3.6.1
|
|
15
|
+
Requires-Dist: matplotlib>=3.10.9
|
|
16
|
+
Requires-Dist: pylatexenc>=2.10
|
|
17
|
+
Requires-Dist: qiskit>=2.4.1
|
|
18
|
+
Requires-Dist: qiskit-aer>=0.17.2
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest; extra == "dev"
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
eoqrid
|
|
24
|
+
======
|
|
25
|
+
|
|
26
|
+
Exchange-Only Quantum Computing Simulator
|
|
27
|
+
|
|
28
|
+
## Feature
|
|
29
|
+
|
|
30
|
+
eoqrid is a Python library designed to simulate silicon quantum computers that control qubits using the Exchange-Only method. Itprovides the following two main features:
|
|
31
|
+
|
|
32
|
+
* **Logical Quantum Circuit Transpilation**
|
|
33
|
+
- It can translate logically described quantum circuits into sets of exchange interactions and measurements so they can be executed on silicon qubits. Furthermore, it allows for the transformation and optimization of circuits to match the specific topology of a quantum chip.
|
|
34
|
+
|
|
35
|
+
* **Physical Quantum Circuit Execution**
|
|
36
|
+
- It can simulate and verify the result from executing physical quantum circuits described by sets of exchange interactions and measurements.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install eoqrid
|
|
42
|
+
```
|
|
43
|
+
or
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
git clone https://github.com/samn33/eoqrid.git
|
|
47
|
+
cd eoqrid
|
|
48
|
+
pip install .
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Uninstall
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip uninstall eoqrid
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Usage
|
|
58
|
+
|
|
59
|
+
```pthon
|
|
60
|
+
$ cat sample.py
|
|
61
|
+
from qiskit import QuantumCircuit
|
|
62
|
+
from eoqrid import EoqSimulator
|
|
63
|
+
|
|
64
|
+
qc = QuantumCircuit(1)
|
|
65
|
+
qc.h(0)
|
|
66
|
+
|
|
67
|
+
print("== quantum circuit ==")
|
|
68
|
+
print(qc)
|
|
69
|
+
|
|
70
|
+
eoq = EoqSimulator()
|
|
71
|
+
qc_native = eoq.transpile(qc)
|
|
72
|
+
|
|
73
|
+
print("== transpiled quantum circuit ==")
|
|
74
|
+
print(qc_native)
|
|
75
|
+
print(f"depth = {qc_native.depth()}")
|
|
76
|
+
|
|
77
|
+
res = eoq.execute(qc_native)
|
|
78
|
+
|
|
79
|
+
print("== quantum state (logical) ==")
|
|
80
|
+
res.qstate.draw()
|
|
81
|
+
|
|
82
|
+
print("== quantum state (physical) ==")
|
|
83
|
+
res.qstate.draw(mode='physical')
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
$ python sample.py
|
|
88
|
+
== quantum circuit ==
|
|
89
|
+
┌───┐
|
|
90
|
+
q: ┤ H ├
|
|
91
|
+
└───┘
|
|
92
|
+
== transpiled quantum circuit ==
|
|
93
|
+
┌───────────────┐ ┌───────────────┐
|
|
94
|
+
q_0 -> 0 ┤0 ├─────────────────┤0 ├
|
|
95
|
+
│ Ex(5.3279,1) │┌───────────────┐│ Ex(5.3279,1) │
|
|
96
|
+
q_1 -> 1 ┤1 ├┤0 ├┤1 ├
|
|
97
|
+
└───────────────┘│ Ex(1.9106,1) │└───────────────┘
|
|
98
|
+
q_2 -> 2 ─────────────────┤1 ├─────────────────
|
|
99
|
+
└───────────────┘
|
|
100
|
+
depth = 3
|
|
101
|
+
== quantum state (logical) ==
|
|
102
|
+
c[0] = +0.7071+0.0000*i : 0.5000 |++++++
|
|
103
|
+
c[1] = +0.7071-0.0000*i : 0.5000 |++++++
|
|
104
|
+
== quantum state (physical) ==
|
|
105
|
+
c[000] = +0.0000+0.0000*i : 0.0000 |
|
|
106
|
+
c[001] = +0.5774-0.0000*i : 0.3333 |++++
|
|
107
|
+
c[010] = +0.2113-0.0000*i : 0.0447 |+
|
|
108
|
+
c[011] = +0.0000+0.0000*i : 0.0000 |
|
|
109
|
+
c[100] = -0.7887-0.0000*i : 0.6220 |+++++++
|
|
110
|
+
c[101] = +0.0000+0.0000*i : 0.0000 |
|
|
111
|
+
c[110] = +0.0000+0.0000*i : 0.0000 |
|
|
112
|
+
c[111] = -0.0000-0.0000*i : 0.0000 |
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Documents
|
|
116
|
+
|
|
117
|
+
- [Tutorial(japanese)](docs/tutorial_jp.md)
|
|
118
|
+
|
|
119
|
+
## References
|
|
120
|
+
|
|
121
|
+
1. [Aaron J. Weinstein, et al., "Universal logic with encoded spin qubits in silicon",arXiv:2202.03605](https://arxiv.org/abs/2202.03605)
|
|
122
|
+
|
|
123
|
+
2. [Exchange Only 量子ビットの仕組み:3つのスピンで「磁場」を超える(YuichiroMinato)](https://zenn.dev/yuichirominato/articles/96b88617c4bffa)
|
|
124
|
+
|
|
125
|
+
## Requirements
|
|
126
|
+
|
|
127
|
+
- Linux (Ubuntu 24.04 LTS)
|
|
128
|
+
- Python 3.12
|
|
129
|
+
|
|
130
|
+
## Licence
|
|
131
|
+
|
|
132
|
+
MIT
|
|
133
|
+
|
|
134
|
+
## Author
|
|
135
|
+
|
|
136
|
+
[Sam.N](http://github.com/samn33)
|
eoqrid-0.1.4/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
eoqrid
|
|
2
|
+
======
|
|
3
|
+
|
|
4
|
+
Exchange-Only Quantum Computing Simulator
|
|
5
|
+
|
|
6
|
+
## Feature
|
|
7
|
+
|
|
8
|
+
eoqrid is a Python library designed to simulate silicon quantum computers that control qubits using the Exchange-Only method. Itprovides the following two main features:
|
|
9
|
+
|
|
10
|
+
* **Logical Quantum Circuit Transpilation**
|
|
11
|
+
- It can translate logically described quantum circuits into sets of exchange interactions and measurements so they can be executed on silicon qubits. Furthermore, it allows for the transformation and optimization of circuits to match the specific topology of a quantum chip.
|
|
12
|
+
|
|
13
|
+
* **Physical Quantum Circuit Execution**
|
|
14
|
+
- It can simulate and verify the result from executing physical quantum circuits described by sets of exchange interactions and measurements.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install eoqrid
|
|
20
|
+
```
|
|
21
|
+
or
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
git clone https://github.com/samn33/eoqrid.git
|
|
25
|
+
cd eoqrid
|
|
26
|
+
pip install .
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Uninstall
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip uninstall eoqrid
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
```pthon
|
|
38
|
+
$ cat sample.py
|
|
39
|
+
from qiskit import QuantumCircuit
|
|
40
|
+
from eoqrid import EoqSimulator
|
|
41
|
+
|
|
42
|
+
qc = QuantumCircuit(1)
|
|
43
|
+
qc.h(0)
|
|
44
|
+
|
|
45
|
+
print("== quantum circuit ==")
|
|
46
|
+
print(qc)
|
|
47
|
+
|
|
48
|
+
eoq = EoqSimulator()
|
|
49
|
+
qc_native = eoq.transpile(qc)
|
|
50
|
+
|
|
51
|
+
print("== transpiled quantum circuit ==")
|
|
52
|
+
print(qc_native)
|
|
53
|
+
print(f"depth = {qc_native.depth()}")
|
|
54
|
+
|
|
55
|
+
res = eoq.execute(qc_native)
|
|
56
|
+
|
|
57
|
+
print("== quantum state (logical) ==")
|
|
58
|
+
res.qstate.draw()
|
|
59
|
+
|
|
60
|
+
print("== quantum state (physical) ==")
|
|
61
|
+
res.qstate.draw(mode='physical')
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
$ python sample.py
|
|
66
|
+
== quantum circuit ==
|
|
67
|
+
┌───┐
|
|
68
|
+
q: ┤ H ├
|
|
69
|
+
└───┘
|
|
70
|
+
== transpiled quantum circuit ==
|
|
71
|
+
┌───────────────┐ ┌───────────────┐
|
|
72
|
+
q_0 -> 0 ┤0 ├─────────────────┤0 ├
|
|
73
|
+
│ Ex(5.3279,1) │┌───────────────┐│ Ex(5.3279,1) │
|
|
74
|
+
q_1 -> 1 ┤1 ├┤0 ├┤1 ├
|
|
75
|
+
└───────────────┘│ Ex(1.9106,1) │└───────────────┘
|
|
76
|
+
q_2 -> 2 ─────────────────┤1 ├─────────────────
|
|
77
|
+
└───────────────┘
|
|
78
|
+
depth = 3
|
|
79
|
+
== quantum state (logical) ==
|
|
80
|
+
c[0] = +0.7071+0.0000*i : 0.5000 |++++++
|
|
81
|
+
c[1] = +0.7071-0.0000*i : 0.5000 |++++++
|
|
82
|
+
== quantum state (physical) ==
|
|
83
|
+
c[000] = +0.0000+0.0000*i : 0.0000 |
|
|
84
|
+
c[001] = +0.5774-0.0000*i : 0.3333 |++++
|
|
85
|
+
c[010] = +0.2113-0.0000*i : 0.0447 |+
|
|
86
|
+
c[011] = +0.0000+0.0000*i : 0.0000 |
|
|
87
|
+
c[100] = -0.7887-0.0000*i : 0.6220 |+++++++
|
|
88
|
+
c[101] = +0.0000+0.0000*i : 0.0000 |
|
|
89
|
+
c[110] = +0.0000+0.0000*i : 0.0000 |
|
|
90
|
+
c[111] = -0.0000-0.0000*i : 0.0000 |
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Documents
|
|
94
|
+
|
|
95
|
+
- [Tutorial(japanese)](docs/tutorial_jp.md)
|
|
96
|
+
|
|
97
|
+
## References
|
|
98
|
+
|
|
99
|
+
1. [Aaron J. Weinstein, et al., "Universal logic with encoded spin qubits in silicon",arXiv:2202.03605](https://arxiv.org/abs/2202.03605)
|
|
100
|
+
|
|
101
|
+
2. [Exchange Only 量子ビットの仕組み:3つのスピンで「磁場」を超える(YuichiroMinato)](https://zenn.dev/yuichirominato/articles/96b88617c4bffa)
|
|
102
|
+
|
|
103
|
+
## Requirements
|
|
104
|
+
|
|
105
|
+
- Linux (Ubuntu 24.04 LTS)
|
|
106
|
+
- Python 3.12
|
|
107
|
+
|
|
108
|
+
## Licence
|
|
109
|
+
|
|
110
|
+
MIT
|
|
111
|
+
|
|
112
|
+
## Author
|
|
113
|
+
|
|
114
|
+
[Sam.N](http://github.com/samn33)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
__version__ = "0.1.4"
|
|
2
|
+
from .eoq_simulator import EoqSimulator
|
|
3
|
+
from .quantum_state import QuantumState
|
|
4
|
+
from .transpiler import Transpiler
|
|
5
|
+
from .exchange_interaction import ExchangeInteraction
|
|
6
|
+
from .measurement import Measurement
|
|
7
|
+
from .result import Result
|
|
8
|
+
from .util import plot_qc, plot_graph, random_connected_graph, random_quantum_circuit
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import itertools
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
import numpy as np
|
|
5
|
+
import networkx as nx
|
|
6
|
+
from qiskit import QuantumCircuit, transpile
|
|
7
|
+
from qiskit.quantum_info import Statevector
|
|
8
|
+
from qiskit_aer import AerSimulator
|
|
9
|
+
|
|
10
|
+
from eoqrid.quantum_state import QuantumState
|
|
11
|
+
from eoqrid.transpiler import Transpiler
|
|
12
|
+
from eoqrid.result import Result
|
|
13
|
+
|
|
14
|
+
DEF_EXCHANGE_INTEGRAL = 1.0
|
|
15
|
+
|
|
16
|
+
class EoqSimulator:
|
|
17
|
+
"""
|
|
18
|
+
Exchange-Only Quantum Computing Simulator
|
|
19
|
+
|
|
20
|
+
Attributes
|
|
21
|
+
----------
|
|
22
|
+
topology : nx.Graph
|
|
23
|
+
quantum chip topology
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
def __init__(self, topology: nx.Graph = None) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
topology : nx.Graph
|
|
31
|
+
quantum chip topology
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
None
|
|
36
|
+
|
|
37
|
+
"""
|
|
38
|
+
self._topology = topology
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def topology(self) -> nx.Graph:
|
|
42
|
+
return self._topology
|
|
43
|
+
|
|
44
|
+
@topology.setter
|
|
45
|
+
def topology(self, value) -> None:
|
|
46
|
+
self._topology = value
|
|
47
|
+
|
|
48
|
+
def _qc_is_noops(self, qc: QuantumCircuit) -> bool:
|
|
49
|
+
"""
|
|
50
|
+
quantum circuit contains no gates operation or not.
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
qc : QuantumCircuit
|
|
55
|
+
quantum circuit
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
bool
|
|
60
|
+
true if quantum circuit contains no gates operation, false otherwise
|
|
61
|
+
|
|
62
|
+
"""
|
|
63
|
+
return qc.count_ops() == {}
|
|
64
|
+
|
|
65
|
+
def _qc_is_transpiled(self, qc: QuantumCircuit) -> bool:
|
|
66
|
+
"""
|
|
67
|
+
quantum circuit is already transpiled or not.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
qc : QuantumCircuit
|
|
72
|
+
quantum circuit
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
bool
|
|
77
|
+
true if quantum circuit is transpiled, false otherwise
|
|
78
|
+
|
|
79
|
+
"""
|
|
80
|
+
if qc.num_qubits % 3 != 0:
|
|
81
|
+
return False
|
|
82
|
+
for name in qc.count_ops():
|
|
83
|
+
if name != 'ex' and name != 'm':
|
|
84
|
+
return False
|
|
85
|
+
return True
|
|
86
|
+
|
|
87
|
+
def _qc_is_native(self, qc: QuantumCircuit) -> bool:
|
|
88
|
+
"""
|
|
89
|
+
quantum circuit is for physical device.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
qc : QuantumCircuit
|
|
94
|
+
quantum circuit
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
bool
|
|
99
|
+
true if quantum circuit is transpiled, false otherwise
|
|
100
|
+
|
|
101
|
+
"""
|
|
102
|
+
for name in qc.count_ops():
|
|
103
|
+
if name == 'ex' or name == 'm':
|
|
104
|
+
return True
|
|
105
|
+
return False
|
|
106
|
+
|
|
107
|
+
def optimize(self, qc_native: QuantumCircuit,
|
|
108
|
+
optimization_level: int = 0,
|
|
109
|
+
seed: int | None = None) -> QuantumCircuit:
|
|
110
|
+
"""
|
|
111
|
+
optimize the native quantum circuit.
|
|
112
|
+
|
|
113
|
+
Parameters
|
|
114
|
+
----------
|
|
115
|
+
qc_native : QuantumCircuit
|
|
116
|
+
quantum circuits for native device.
|
|
117
|
+
optimization_level : int
|
|
118
|
+
optimization level.
|
|
119
|
+
seed : int | None, default None
|
|
120
|
+
seed of random generation.
|
|
121
|
+
|
|
122
|
+
Returns
|
|
123
|
+
-------
|
|
124
|
+
QuantumCircuit
|
|
125
|
+
optimized quantum circuit.
|
|
126
|
+
|
|
127
|
+
"""
|
|
128
|
+
if not isinstance(qc_native, QuantumCircuit):
|
|
129
|
+
raise TypeError("the qc must be a QuantumCircuit object.")
|
|
130
|
+
for name in qc_native.count_ops():
|
|
131
|
+
if name != 'ex' and name != 'm':
|
|
132
|
+
raise ValueError("the qc_native contains gates other than exchange interaction.")
|
|
133
|
+
if optimization_level not in (0, 1, 2, 3):
|
|
134
|
+
raise ValueError("the optimization_level must be 0, 1, 2, or 3.")
|
|
135
|
+
|
|
136
|
+
num_dots = qc_native.num_qubits
|
|
137
|
+
topology = nx.Graph()
|
|
138
|
+
if self._topology is None:
|
|
139
|
+
for pair in itertools.combinations(range(num_dots), 2):
|
|
140
|
+
topology.add_edge(pair[0], pair[1], weight=DEF_EXCHANGE_INTEGRAL)
|
|
141
|
+
else:
|
|
142
|
+
topology = self._topology
|
|
143
|
+
trans = Transpiler(topology)
|
|
144
|
+
return trans.optimize(qc_native, optimization_level, seed)
|
|
145
|
+
|
|
146
|
+
def transpile(self, qc: QuantumCircuit, optimization_level: int = 0, seed: int | None = None) -> QuantumCircuit:
|
|
147
|
+
"""
|
|
148
|
+
transpile the quantum circuit.
|
|
149
|
+
|
|
150
|
+
Parameters
|
|
151
|
+
----------
|
|
152
|
+
qc_native : QuantumCircuit
|
|
153
|
+
quantum circuits for native device.
|
|
154
|
+
optimization_level : int, default 1
|
|
155
|
+
optimization level.
|
|
156
|
+
seed : int | None, default None
|
|
157
|
+
seed of random generation.
|
|
158
|
+
|
|
159
|
+
Returns
|
|
160
|
+
-------
|
|
161
|
+
qc_t : QuantumCircuit
|
|
162
|
+
transpiled quantum circuit.
|
|
163
|
+
|
|
164
|
+
"""
|
|
165
|
+
if not isinstance(qc, QuantumCircuit):
|
|
166
|
+
raise TypeError("the qc must be a QuantumCircuit object.")
|
|
167
|
+
if not self._qc_is_noops(qc) and self._qc_is_native(qc):
|
|
168
|
+
raise ValueError("the qc is for physical device.")
|
|
169
|
+
|
|
170
|
+
num_dots = qc.num_qubits * 3
|
|
171
|
+
topology = nx.Graph()
|
|
172
|
+
if self._topology is None:
|
|
173
|
+
for pair in itertools.combinations(range(num_dots), 2):
|
|
174
|
+
topology.add_edge(pair[0], pair[1], weight=DEF_EXCHANGE_INTEGRAL)
|
|
175
|
+
else:
|
|
176
|
+
topology = self._topology
|
|
177
|
+
trans = Transpiler(topology)
|
|
178
|
+
qc_t = trans.run(qc, optimization_level, seed)
|
|
179
|
+
|
|
180
|
+
return qc_t
|
|
181
|
+
|
|
182
|
+
def _execute_measurement(self, qc_native: QuantumCircuit, shots: int = 1) -> Result:
|
|
183
|
+
"""
|
|
184
|
+
execute the native quantum circuit with measurements.
|
|
185
|
+
|
|
186
|
+
Parameters
|
|
187
|
+
----------
|
|
188
|
+
qc_native : QuantumCircuit
|
|
189
|
+
quantum circuits for native device.
|
|
190
|
+
shots : int, default 1
|
|
191
|
+
shots of execute the quantumcircuit.
|
|
192
|
+
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
res : Result
|
|
196
|
+
result of execution.
|
|
197
|
+
|
|
198
|
+
"""
|
|
199
|
+
if not isinstance(qc_native, QuantumCircuit):
|
|
200
|
+
raise TypeError("the qc_native must be a QuantumCircuit object.")
|
|
201
|
+
if not self._qc_is_noops(qc_native) and not self._qc_is_transpiled(qc_native):
|
|
202
|
+
raise ValueError("the qc_native must be transpiled.")
|
|
203
|
+
|
|
204
|
+
num_dots = qc_native.num_qubits
|
|
205
|
+
num_qubits = num_dots // 3
|
|
206
|
+
num_clbits = qc_native.num_clbits
|
|
207
|
+
|
|
208
|
+
qstate = QuantumState(num_qubits)
|
|
209
|
+
backend = AerSimulator(method='statevector')
|
|
210
|
+
qc_t = QuantumCircuit(num_dots, num_clbits)
|
|
211
|
+
qc_t.set_statevector(qstate.statevector)
|
|
212
|
+
qc_t = qc_t.compose(
|
|
213
|
+
transpile(qc_native.decompose(), backend=backend, optimization_level=0)
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
freq_qiskit = defaultdict(int)
|
|
217
|
+
if shots > 1:
|
|
218
|
+
result = backend.run(qc_t, shots=shots-1).result()
|
|
219
|
+
freq_qiskit |= result.get_counts()
|
|
220
|
+
|
|
221
|
+
result = backend.run(qc_t, shots=1).result()
|
|
222
|
+
for k,v in result.get_counts().items():
|
|
223
|
+
m_last = k[::-1]
|
|
224
|
+
freq_qiskit[k] += v
|
|
225
|
+
|
|
226
|
+
freq = {k[::-1]:v for k,v in freq_qiskit.items()}
|
|
227
|
+
|
|
228
|
+
res = Result(
|
|
229
|
+
num_qubits = num_qubits,
|
|
230
|
+
num_clbits = num_clbits,
|
|
231
|
+
num_dots = num_dots,
|
|
232
|
+
qstate = None,
|
|
233
|
+
m_last = m_last,
|
|
234
|
+
freq = freq,
|
|
235
|
+
)
|
|
236
|
+
return res
|
|
237
|
+
|
|
238
|
+
def _execute_no_measurement(self, qc_native: QuantumCircuit, shots: int = 1) -> Result:
|
|
239
|
+
"""
|
|
240
|
+
execute the native quantum circuit without measurements.
|
|
241
|
+
|
|
242
|
+
Parameters
|
|
243
|
+
----------
|
|
244
|
+
qc_native : QuantumCircuit
|
|
245
|
+
quantum circuits for native device.
|
|
246
|
+
shots : int, default 1
|
|
247
|
+
shots of execute the quantumcircuit.
|
|
248
|
+
|
|
249
|
+
Returns
|
|
250
|
+
-------
|
|
251
|
+
res : Result
|
|
252
|
+
result of execution.
|
|
253
|
+
|
|
254
|
+
"""
|
|
255
|
+
if not isinstance(qc_native, QuantumCircuit):
|
|
256
|
+
raise TypeError("the qc_native must be a QuantumCircuit object.")
|
|
257
|
+
|
|
258
|
+
num_dots = qc_native.num_qubits
|
|
259
|
+
num_qubits = num_dots // 3
|
|
260
|
+
num_clbits = qc_native.num_clbits
|
|
261
|
+
|
|
262
|
+
qstate = QuantumState(num_qubits)
|
|
263
|
+
|
|
264
|
+
qstate.statevector = qstate.statevector.evolve(qc_native)
|
|
265
|
+
|
|
266
|
+
if qc_native.layout is None:
|
|
267
|
+
logical_indices = list(range(num_dots))
|
|
268
|
+
else:
|
|
269
|
+
logical_indices = qc_native.layout.final_index_layout()
|
|
270
|
+
|
|
271
|
+
data = np.zeros(2 ** num_dots, dtype=complex)
|
|
272
|
+
for p_id in range(2 ** num_dots):
|
|
273
|
+
b_str = f"{p_id:0{num_dots}b}"
|
|
274
|
+
b_list = list(map(int, list(b_str)))[::-1]
|
|
275
|
+
bb_list = [0] * num_dots
|
|
276
|
+
l_id = 0
|
|
277
|
+
for k in range(num_dots):
|
|
278
|
+
bb_list[logical_indices[k]] = b_list[k]
|
|
279
|
+
if b_list[k] == 1:
|
|
280
|
+
l_id += (1 << logical_indices[k])
|
|
281
|
+
data[p_id] = qstate.statevector.data[l_id]
|
|
282
|
+
|
|
283
|
+
qstate.statevector = Statevector(data)
|
|
284
|
+
|
|
285
|
+
res = Result(
|
|
286
|
+
num_qubits = num_qubits,
|
|
287
|
+
num_clbits = num_clbits,
|
|
288
|
+
num_dots = num_dots,
|
|
289
|
+
qstate = qstate,
|
|
290
|
+
m_last = None,
|
|
291
|
+
freq = None,
|
|
292
|
+
)
|
|
293
|
+
return res
|
|
294
|
+
|
|
295
|
+
def execute(self, qc_native: QuantumCircuit, shots: int = 1) -> Result:
|
|
296
|
+
"""
|
|
297
|
+
execute the native quantum circuit.
|
|
298
|
+
|
|
299
|
+
Parameters
|
|
300
|
+
----------
|
|
301
|
+
qc_native : QuantumCircuit
|
|
302
|
+
quantum circuits for native device.
|
|
303
|
+
shots : int, default 1
|
|
304
|
+
shots of execute the quantumcircuit.
|
|
305
|
+
|
|
306
|
+
Returns
|
|
307
|
+
-------
|
|
308
|
+
res : Result
|
|
309
|
+
result of execution.
|
|
310
|
+
|
|
311
|
+
"""
|
|
312
|
+
if self._qc_is_transpiled(qc_native) is False:
|
|
313
|
+
raise ValueError("qc_native must be a transpiled native quantum circuit.")
|
|
314
|
+
|
|
315
|
+
if 'm' in qc_native.count_ops():
|
|
316
|
+
res = self._execute_measurement(qc_native, shots)
|
|
317
|
+
else:
|
|
318
|
+
res = self._execute_no_measurement(qc_native, shots)
|
|
319
|
+
return res
|
|
320
|
+
|
|
321
|
+
def run(self, qc: QuantumCircuit, optimization_level: int = 0, shots: int = 1, seed: int | None = None) -> Result:
|
|
322
|
+
"""
|
|
323
|
+
run the quantum circuit (transpile and execute).
|
|
324
|
+
|
|
325
|
+
Parameters
|
|
326
|
+
----------
|
|
327
|
+
qc_native : QuantumCircuit
|
|
328
|
+
quantum circuits for native device.
|
|
329
|
+
optimization_level : int, default 1
|
|
330
|
+
optimization level.
|
|
331
|
+
shots : int, default 1
|
|
332
|
+
shots of execute the quantumcircuit.
|
|
333
|
+
seed : int | None, default None
|
|
334
|
+
seed of random generation.
|
|
335
|
+
|
|
336
|
+
Returns
|
|
337
|
+
-------
|
|
338
|
+
res : Result
|
|
339
|
+
result of execution.
|
|
340
|
+
|
|
341
|
+
"""
|
|
342
|
+
qc_native = self.transpile(qc, optimization_level = optimization_level, seed = seed)
|
|
343
|
+
res = self.execute(qc_native, shots)
|
|
344
|
+
return res
|
|
345
|
+
|
|
346
|
+
def fidelity(self, qc: QuantumCircuit, qc_native: QuantumCircuit) -> float:
|
|
347
|
+
"""
|
|
348
|
+
fidelity of the quantum circuit execution.
|
|
349
|
+
|
|
350
|
+
Parameters
|
|
351
|
+
----------
|
|
352
|
+
qc : QuantumCircuit
|
|
353
|
+
quantum circuits.
|
|
354
|
+
qc_native : QuantumCircuit
|
|
355
|
+
quantum circuits for native device.
|
|
356
|
+
|
|
357
|
+
Returns
|
|
358
|
+
-------
|
|
359
|
+
fidelity : float
|
|
360
|
+
fidelity
|
|
361
|
+
|
|
362
|
+
"""
|
|
363
|
+
if 'measure' in qc.count_ops():
|
|
364
|
+
raise ValueError("can't calculate fidelity in quantum circuits that include measurements.")
|
|
365
|
+
|
|
366
|
+
sv_qiskit = Statevector.from_int(0, 2 ** qc.num_qubits).evolve(qc)
|
|
367
|
+
state_expect = sv_qiskit.reverse_qargs().data
|
|
368
|
+
|
|
369
|
+
res = self.execute(qc_native)
|
|
370
|
+
|
|
371
|
+
fidelity = np.abs(np.vdot(state_expect, res.qstate.logical_qstate)) ** 2
|
|
372
|
+
return fidelity
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from qiskit.circuit import Gate, QuantumCircuit
|
|
3
|
+
|
|
4
|
+
class ExchangeInteraction(Gate):
|
|
5
|
+
"""
|
|
6
|
+
Exchange Interaction
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
def __init__(self, t: float, J: float = 1.0, label: str = None):
|
|
10
|
+
super().__init__(name="ex", num_qubits=2, params=[t, J], label=label)
|
|
11
|
+
|
|
12
|
+
def _define(self):
|
|
13
|
+
duration = self.params[0]
|
|
14
|
+
exchange_integral = self.params[1]
|
|
15
|
+
if duration < 0.0:
|
|
16
|
+
raise ValueError("duration must be a positive value.")
|
|
17
|
+
qc = QuantumCircuit(self.num_qubits, name=self.name)
|
|
18
|
+
phase = 0.5 * exchange_integral * duration
|
|
19
|
+
qc.rxx(phase, 0, 1)
|
|
20
|
+
qc.ryy(phase, 0, 1)
|
|
21
|
+
qc.rzz(phase, 0, 1)
|
|
22
|
+
self.definition = qc
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from qiskit.circuit import Instruction, QuantumCircuit
|
|
3
|
+
|
|
4
|
+
class Measurement(Instruction):
|
|
5
|
+
"""
|
|
6
|
+
Measurement
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
def __init__(self):
|
|
10
|
+
super().__init__(name="m", num_qubits=2, num_clbits=1, params=[])
|
|
11
|
+
|
|
12
|
+
def _define(self):
|
|
13
|
+
qc = QuantumCircuit(self.num_qubits, 1)
|
|
14
|
+
qc.cx(0, 1)
|
|
15
|
+
qc.h(0)
|
|
16
|
+
qc.x(0)
|
|
17
|
+
qc.x(1)
|
|
18
|
+
qc.measure(0, 0)
|
|
19
|
+
with qc.if_test((0, 0)):
|
|
20
|
+
qc.measure(1, 0)
|
|
21
|
+
|
|
22
|
+
self.definition = qc
|