qiskit
qiskit copied to clipboard
add improved ansatze
Summary
Following #8328, I've started to add the improved ansatze. First, I've added the tensor product ansatz, which at the moment can be used as follows:
from qiskit.circuit.library import TensorProductAnsatz
from qiskit import ansatz
qc = TensorProductAnsatz(8, 4, insert_barriers=True)
qc = transpile(qc, basis_gates=["cx", "cz", "u"])
qc.draw()
┌─────────────────┐ ░ ░ ┌─────────────────┐ ░ ░ ┌──────────────────┐ ░ ░ ┌──────────────────┐
q_0: ┤ U(θ[0],0.0,0.0) ├─░───■─────────────░─┤ U(θ[8],0.0,0.0) ├──░───■─────────────░─┤ U(θ[16],0.0,0.0) ├─░───■─────────────░─┤ U(θ[24],0.0,0.0) ├
├─────────────────┤ ░ ┌─┴─┐ ░ ├─────────────────┤ ░ ┌─┴─┐ ░ ├──────────────────┤ ░ ┌─┴─┐ ░ ├──────────────────┤
q_1: ┤ U(θ[1],0.0,0.0) ├─░─┤ X ├──■────────░─┤ U(θ[9],0.0,0.0) ├──░─┤ X ├──■────────░─┤ U(θ[17],0.0,0.0) ├─░─┤ X ├──■────────░─┤ U(θ[25],0.0,0.0) ├
├─────────────────┤ ░ └───┘┌─┴─┐ ░ ├─────────────────┴┐ ░ └───┘┌─┴─┐ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤
q_2: ┤ U(θ[2],0.0,0.0) ├─░──────┤ X ├──■───░─┤ U(θ[10],0.0,0.0) ├─░──────┤ X ├──■───░─┤ U(θ[18],0.0,0.0) ├─░──────┤ X ├──■───░─┤ U(θ[26],0.0,0.0) ├
├─────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤
q_3: ┤ U(θ[3],0.0,0.0) ├─░───────────┤ X ├─░─┤ U(θ[11],0.0,0.0) ├─░───────────┤ X ├─░─┤ U(θ[19],0.0,0.0) ├─░───────────┤ X ├─░─┤ U(θ[27],0.0,0.0) ├
├─────────────────┤ ░ └───┘ ░ ├──────────────────┤ ░ └───┘ ░ ├──────────────────┤ ░ └───┘ ░ ├──────────────────┤
q_4: ┤ U(θ[4],0.0,0.0) ├─░───■─────────────░─┤ U(θ[12],0.0,0.0) ├─░───■─────────────░─┤ U(θ[20],0.0,0.0) ├─░───■─────────────░─┤ U(θ[28],0.0,0.0) ├
├─────────────────┤ ░ ┌─┴─┐ ░ ├──────────────────┤ ░ ┌─┴─┐ ░ ├──────────────────┤ ░ ┌─┴─┐ ░ ├──────────────────┤
q_5: ┤ U(θ[5],0.0,0.0) ├─░─┤ X ├──■────────░─┤ U(θ[13],0.0,0.0) ├─░─┤ X ├──■────────░─┤ U(θ[21],0.0,0.0) ├─░─┤ X ├──■────────░─┤ U(θ[29],0.0,0.0) ├
├─────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤
q_6: ┤ U(θ[6],0.0,0.0) ├─░──────┤ X ├──■───░─┤ U(θ[14],0.0,0.0) ├─░──────┤ X ├──■───░─┤ U(θ[22],0.0,0.0) ├─░──────┤ X ├──■───░─┤ U(θ[30],0.0,0.0) ├
├─────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤
q_7: ┤ U(θ[7],0.0,0.0) ├─░───────────┤ X ├─░─┤ U(θ[15],0.0,0.0) ├─░───────────┤ X ├─░─┤ U(θ[23],0.0,0.0) ├─░───────────┤ X ├─░─┤ U(θ[31],0.0,0.0) ├
└─────────────────┘ ░ └───┘ ░ └──────────────────┘ ░ └───┘ ░ └──────────────────┘ ░ └───┘ ░ └──────────────────┘
Which is exactly as described in the original paper (with an extra rotation layer at the end, which can be disabled by setting skip_final_rotation_layer=True).
On top of this, I've added functionality similar to that of the TwoLocal circuit, in which you can choose different entanglement types and multiple gates for the rotation and entanglement layers. With this, you can create something like the following:
qc = TensorProductAnsatz(9, 3, ["rx", "ry"], ["cx", "cz"], entanglement="sca", insert_barriers=True, skip_final_rotation_layer=True)
qc = transpile(qc, basis_gates=["cx", "cz", "rx", "ry"])
qc.draw()
┌──────────┐ ┌──────────┐ ░ ┌───┐ ░ ┌───────────┐┌───────────┐ ░ ┌───┐ ░ ┌───────────┐┌───────────┐ ░ ┌───┐
q_0: ┤ Rx(θ[0]) ├─┤ Ry(θ[9]) ├─░─┤ X ├──■────────■──■─────░─┤ Rx(θ[18]) ├┤ Ry(θ[27]) ├─░────────■──┤ X ├────■──■──░─┤ Rx(θ[36]) ├┤ Ry(θ[45]) ├─░───■───────┤ X ├─■─────■─
├──────────┤┌┴──────────┤ ░ └─┬─┘┌─┴─┐ │ │ ░ ├───────────┤├───────────┤ ░ ┌───┐ │ └─┬─┘ │ │ ░ ├───────────┤├───────────┤ ░ ┌─┴─┐ └─┬─┘ │ │
q_1: ┤ Rx(θ[1]) ├┤ Ry(θ[10]) ├─░───┼──┤ X ├──■───┼──■──■──░─┤ Rx(θ[19]) ├┤ Ry(θ[28]) ├─░─┤ X ├──┼────■───■──┼──■──░─┤ Rx(θ[37]) ├┤ Ry(θ[46]) ├─░─┤ X ├──■────┼───■──■──┼─
├──────────┤├───────────┤ ░ │ └───┘┌─┴─┐ │ │ ░ ├───────────┤├───────────┤ ░ └─┬─┘┌─┴─┐ │ │ ░ ├───────────┤├───────────┤ ░ └───┘┌─┴─┐ │ │ │
q_2: ┤ Rx(θ[2]) ├┤ Ry(θ[11]) ├─░───■───────┤ X ├─■─────■──░─┤ Rx(θ[20]) ├┤ Ry(θ[29]) ├─░───■──┤ X ├──────■──■─────░─┤ Rx(θ[38]) ├┤ Ry(θ[47]) ├─░──────┤ X ├──■──────■──■─
├──────────┤├───────────┤ ░ ┌───┐ └───┘ ░ ├───────────┤├───────────┤ ░ └───┘┌───┐ ░ ├───────────┤├───────────┤ ░ └───┘┌───┐
q_3: ┤ Rx(θ[3]) ├┤ Ry(θ[12]) ├─░─┤ X ├──■────────■──■─────░─┤ Rx(θ[21]) ├┤ Ry(θ[30]) ├─░────────■──┤ X ├────■──■──░─┤ Rx(θ[39]) ├┤ Ry(θ[48]) ├─░───■───────┤ X ├─■─────■─
├──────────┤├───────────┤ ░ └─┬─┘┌─┴─┐ │ │ ░ ├───────────┤├───────────┤ ░ ┌───┐ │ └─┬─┘ │ │ ░ ├───────────┤├───────────┤ ░ ┌─┴─┐ └─┬─┘ │ │
q_4: ┤ Rx(θ[4]) ├┤ Ry(θ[13]) ├─░───┼──┤ X ├──■───┼──■──■──░─┤ Rx(θ[22]) ├┤ Ry(θ[31]) ├─░─┤ X ├──┼────■───■──┼──■──░─┤ Rx(θ[40]) ├┤ Ry(θ[49]) ├─░─┤ X ├──■────┼───■──■──┼─
├──────────┤├───────────┤ ░ │ └───┘┌─┴─┐ │ │ ░ ├───────────┤├───────────┤ ░ └─┬─┘┌─┴─┐ │ │ ░ ├───────────┤├───────────┤ ░ └───┘┌─┴─┐ │ │ │
q_5: ┤ Rx(θ[5]) ├┤ Ry(θ[14]) ├─░───■───────┤ X ├─■─────■──░─┤ Rx(θ[23]) ├┤ Ry(θ[32]) ├─░───■──┤ X ├──────■──■─────░─┤ Rx(θ[41]) ├┤ Ry(θ[50]) ├─░──────┤ X ├──■──────■──■─
├──────────┤├───────────┤ ░ ┌───┐ └───┘ ░ ├───────────┤├───────────┤ ░ └───┘┌───┐ ░ ├───────────┤├───────────┤ ░ └───┘┌───┐
q_6: ┤ Rx(θ[6]) ├┤ Ry(θ[15]) ├─░─┤ X ├──■────────■──■─────░─┤ Rx(θ[24]) ├┤ Ry(θ[33]) ├─░────────■──┤ X ├────■──■──░─┤ Rx(θ[42]) ├┤ Ry(θ[51]) ├─░───■───────┤ X ├─■─────■─
├──────────┤├───────────┤ ░ └─┬─┘┌─┴─┐ │ │ ░ ├───────────┤├───────────┤ ░ ┌───┐ │ └─┬─┘ │ │ ░ ├───────────┤├───────────┤ ░ ┌─┴─┐ └─┬─┘ │ │
q_7: ┤ Rx(θ[7]) ├┤ Ry(θ[16]) ├─░───┼──┤ X ├──■───┼──■──■──░─┤ Rx(θ[25]) ├┤ Ry(θ[34]) ├─░─┤ X ├──┼────■───■──┼──■──░─┤ Rx(θ[43]) ├┤ Ry(θ[52]) ├─░─┤ X ├──■────┼───■──■──┼─
├──────────┤├───────────┤ ░ │ └───┘┌─┴─┐ │ │ ░ ├───────────┤├───────────┤ ░ └─┬─┘┌─┴─┐ │ │ ░ ├───────────┤├───────────┤ ░ └───┘┌─┴─┐ │ │ │
q_8: ┤ Rx(θ[8]) ├┤ Ry(θ[17]) ├─░───■───────┤ X ├─■─────■──░─┤ Rx(θ[26]) ├┤ Ry(θ[35]) ├─░───■──┤ X ├──────■──■─────░─┤ Rx(θ[44]) ├┤ Ry(θ[53]) ├─░──────┤ X ├──■──────■──■─
└──────────┘└───────────┘ ░ └───┘ ░ └───────────┘└───────────┘ ░ └───┘ ░ └───────────┘└───────────┘ ░ └───┘
This still follows the tensor product structure introduced in the paper but is much more customizable.
Details and comments
I'm still working on the alternating layered ansatz, for which I'm doing basically the same but it is being more complicated since the blocks vary size every other layer. If I can get any feedback on this advancement of the tensor product ansatz that would be great so I can correct it and use the advice to develop the alternating layered ansatz!
Thank you for opening a new pull request.
Before your PR can be merged it will first need to pass continuous integration tests and be reviewed. Sometimes the review process can be slow, so please be patient.
While you're waiting, please feel free to review other open PRs. While only a subset of people are authorized to approve pull requests for merging, everyone is encouraged to review open pull requests. Doing reviews helps reduce the burden on the core team and helps make the project's code better for everyone.
One or more of the the following people are requested to review this:
- @Cryoris
- @Qiskit/terra-core
- @ajavadia
Pull Request Test Coverage Report for Build 5212406933
- 26 of 210 (12.38%) changed or added relevant lines in 3 files are covered.
- 20 unchanged lines in 6 files lost coverage.
- Overall coverage decreased (-0.2%) to 85.693%
| Changes Missing Coverage | Covered Lines | Changed/Added Lines | % |
|---|---|---|---|
| qiskit/circuit/library/n_local/tensor_product_ansatz.py | 12 | 94 | 12.77% |
| qiskit/circuit/library/n_local/alternating_layer_ansatz.py | 12 | 114 | 10.53% |
| <!-- | Total: | 26 | 210 |
| Files with Coverage Reduction | New Missed Lines | % |
|---|---|---|
| crates/accelerate/src/sabre_swap/mod.rs | 1 | 99.77% |
| crates/qasm2/src/expr.rs | 1 | 93.76% |
| qiskit/transpiler/passes/synthesis/unitary_synthesis.py | 1 | 90.39% |
| qiskit/extensions/quantum_initializer/squ.py | 2 | 80.0% |
| crates/qasm2/src/lex.rs | 3 | 90.38% |
| crates/qasm2/src/parse.rs | 12 | 95.71% |
| <!-- | Total: | 20 |
| Totals | |
|---|---|
| Change from base Build 5201330574: | -0.2% |
| Covered Lines: | 71209 |
| Relevant Lines: | 83098 |
💛 - Coveralls
I have added a first version of the alternating layer ansatz. The following code produces an ansatz just as described in the original paper.
from qiskit.circuit.library import AlternatingLayerAnsatz
from qiskit import ansatz
qc = AlternatingLayerAnsatz(8, 4, insert_barriers=True)
qc = transpile(qc, basis_gates=["cx", "cz", "u"])
qc.draw()
┌─────────────────┐ ░ ░ ┌─────────────────┐ ░ ░ ┌──────────────────┐ ░ ░ ┌──────────────────┐
q_0: ┤ U(θ[0],0.0,0.0) ├─░───■─────────────░─┤ U(θ[8],0.0,0.0) ├──░───■─────────────░─┤ U(θ[16],0.0,0.0) ├─░───■─────────────░─┤ U(θ[24],0.0,0.0) ├
├─────────────────┤ ░ ┌─┴─┐ ░ ├─────────────────┤ ░ ┌─┴─┐ ░ ├──────────────────┤ ░ ┌─┴─┐ ░ ├──────────────────┤
q_1: ┤ U(θ[1],0.0,0.0) ├─░─┤ X ├──■────────░─┤ U(θ[9],0.0,0.0) ├──░─┤ X ├───────────░─┤ U(θ[17],0.0,0.0) ├─░─┤ X ├──■────────░─┤ U(θ[25],0.0,0.0) ├
├─────────────────┤ ░ └───┘┌─┴─┐ ░ ├─────────────────┴┐ ░ └───┘ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤
q_2: ┤ U(θ[2],0.0,0.0) ├─░──────┤ X ├──■───░─┤ U(θ[10],0.0,0.0) ├─░───■─────────────░─┤ U(θ[18],0.0,0.0) ├─░──────┤ X ├──■───░─┤ U(θ[26],0.0,0.0) ├
├─────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤ ░ ┌─┴─┐ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤
q_3: ┤ U(θ[3],0.0,0.0) ├─░───────────┤ X ├─░─┤ U(θ[11],0.0,0.0) ├─░─┤ X ├──■────────░─┤ U(θ[19],0.0,0.0) ├─░───────────┤ X ├─░─┤ U(θ[27],0.0,0.0) ├
├─────────────────┤ ░ └───┘ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤ ░ └───┘ ░ ├──────────────────┤
q_4: ┤ U(θ[4],0.0,0.0) ├─░───■─────────────░─┤ U(θ[12],0.0,0.0) ├─░──────┤ X ├──■───░─┤ U(θ[20],0.0,0.0) ├─░───■─────────────░─┤ U(θ[28],0.0,0.0) ├
├─────────────────┤ ░ ┌─┴─┐ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤ ░ ┌─┴─┐ ░ ├──────────────────┤
q_5: ┤ U(θ[5],0.0,0.0) ├─░─┤ X ├──■────────░─┤ U(θ[13],0.0,0.0) ├─░───────────┤ X ├─░─┤ U(θ[21],0.0,0.0) ├─░─┤ X ├──■────────░─┤ U(θ[29],0.0,0.0) ├
├─────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤ ░ └───┘ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤
q_6: ┤ U(θ[6],0.0,0.0) ├─░──────┤ X ├──■───░─┤ U(θ[14],0.0,0.0) ├─░───■─────────────░─┤ U(θ[22],0.0,0.0) ├─░──────┤ X ├──■───░─┤ U(θ[30],0.0,0.0) ├
├─────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤ ░ ┌─┴─┐ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ ░ ├──────────────────┤
q_7: ┤ U(θ[7],0.0,0.0) ├─░───────────┤ X ├─░─┤ U(θ[15],0.0,0.0) ├─░─┤ X ├───────────░─┤ U(θ[23],0.0,0.0) ├─░───────────┤ X ├─░─┤ U(θ[31],0.0,0.0) ├
└─────────────────┘ ░ └───┘ ░ └──────────────────┘ ░ └───┘ ░ └──────────────────┘ ░ └───┘ ░ └──────────────────┘
And just like with the tensor product ansatz, there are several arguments that can give more customizable results.
qc = AlternatingLayerAnsatz(8, 4, ["ry"], ["cx", "cz"], reps=3, insert_barriers=True, entanglement="sca", skip_final_rotation_layer=True)
qc = transpile(qc, basis_gates=["cx", "cz", "u"])
print(qc.draw())
┌─────────────────┐ ░ ┌───┐ ░ ┌─────────────────┐ ░ ┌───┐ ░ ┌──────────────────┐ ░ ┌───┐
q_0: ┤ U(θ[0],0.0,0.0) ├─░─┤ X ├──■─────────────■──■────────░─┤ U(θ[8],0.0,0.0) ├──░─┤ X ├──■─────────────────────────░─┤ U(θ[16],0.0,0.0) ├─░───────────┤ X ├──■─────────■──■─
├─────────────────┤ ░ └─┬─┘┌─┴─┐ │ │ ░ ├─────────────────┤ ░ └─┬─┘ │ ░ ├──────────────────┤ ░ └─┬─┘┌─┴─┐ │ │
q_1: ┤ U(θ[1],0.0,0.0) ├─░───┼──┤ X ├──■────────┼──■──■─────░─┤ U(θ[9],0.0,0.0) ├──░───■────■─────────────────────────░─┤ U(θ[17],0.0,0.0) ├─░───■─────────┼──┤ X ├─■─────┼──■─
├─────────────────┤ ░ │ └───┘┌─┴─┐ │ │ ░ ├─────────────────┴┐ ░ ┌───┐ ░ ├──────────────────┤ ░ ┌─┴─┐ │ └───┘ │ │
q_2: ┤ U(θ[2],0.0,0.0) ├─░───┼───────┤ X ├──■───┼─────■──■──░─┤ U(θ[10],0.0,0.0) ├─░────────■──┤ X ├─────────■──■─────░─┤ U(θ[18],0.0,0.0) ├─░─┤ X ├──■────┼────────■──■──┼────
├─────────────────┤ ░ │ └───┘┌─┴─┐ │ │ ░ ├──────────────────┤ ░ │ └─┬─┘┌───┐ │ │ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ │ │ │
q_3: ┤ U(θ[3],0.0,0.0) ├─░───■────────────┤ X ├─■────────■──░─┤ U(θ[11],0.0,0.0) ├─░────────┼────■──┤ X ├────┼──■──■──░─┤ U(θ[19],0.0,0.0) ├─░──────┤ X ├──■───────────■──■────
├─────────────────┤ ░ ┌───┐ └───┘ ░ ├──────────────────┤ ░ ┌───┐ │ └─┬─┘ │ │ ░ ├──────────────────┤ ░ └───┘┌───┐
q_4: ┤ U(θ[4],0.0,0.0) ├─░─┤ X ├──■─────────────■──■────────░─┤ U(θ[12],0.0,0.0) ├─░─┤ X ├──┼─────────■───■──┼─────■──░─┤ U(θ[20],0.0,0.0) ├─░───────────┤ X ├──■─────────■──■─
├─────────────────┤ ░ └─┬─┘┌─┴─┐ │ │ ░ ├──────────────────┤ ░ └─┬─┘┌─┴─┐ │ │ ░ ├──────────────────┤ ░ └─┬─┘┌─┴─┐ │ │
q_5: ┤ U(θ[5],0.0,0.0) ├─░───┼──┤ X ├──■────────┼──■──■─────░─┤ U(θ[13],0.0,0.0) ├─░───■──┤ X ├───────────■──■────────░─┤ U(θ[21],0.0,0.0) ├─░───■─────────┼──┤ X ├─■─────┼──■─
├─────────────────┤ ░ │ └───┘┌─┴─┐ │ │ ░ ├──────────────────┤ ░ ┌───┐└───┘ ░ ├──────────────────┤ ░ ┌─┴─┐ │ └───┘ │ │
q_6: ┤ U(θ[6],0.0,0.0) ├─░───┼───────┤ X ├──■───┼─────■──■──░─┤ U(θ[14],0.0,0.0) ├─░─┤ X ├──■─────────────────────────░─┤ U(θ[22],0.0,0.0) ├─░─┤ X ├──■────┼────────■──■──┼────
├─────────────────┤ ░ │ └───┘┌─┴─┐ │ │ ░ ├──────────────────┤ ░ └─┬─┘ │ ░ ├──────────────────┤ ░ └───┘┌─┴─┐ │ │ │
q_7: ┤ U(θ[7],0.0,0.0) ├─░───■────────────┤ X ├─■────────■──░─┤ U(θ[15],0.0,0.0) ├─░───■────■─────────────────────────░─┤ U(θ[23],0.0,0.0) ├─░──────┤ X ├──■───────────■──■────
└─────────────────┘ ░ └───┘ ░ └──────────────────┘ ░ ░ └──────────────────┘ ░ └───┘
I seem to be getting a Parameters differ from overridden 'get_entangler_map' method (arguments-differ) error in lint.
If I understand correctly from the Pylint docs, adding a default value to the extra argument should solve this error. However, I added a default argument and the error is still showing up.
Any insight on this?