-
-
Notifications
You must be signed in to change notification settings - Fork 48
Add multi-control functionality #1380
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2134c2e
0ae2b61
f8c4503
894add1
fb32afb
2375b74
275e832
c873318
068560c
53032bb
5c68a2f
3f46cd3
33b48a7
453e00a
b81e3e3
2505f27
9ab82f3
06a40af
92ed957
0911f7c
3d74d1b
9915b6a
cdc0ec3
ee9b279
cbda9d6
a8af5a7
8236fbf
14e1955
9de9ac9
826829e
93bf49d
48caa99
8cbe448
e10767e
9816218
ef2f343
77dae77
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -307,6 +307,127 @@ void FunctionalityConstruction::addCcx(ZXDiagram& diag, const Qubit ctrl0, | |
| addCnot(diag, ctrl0, ctrl1, qubits); | ||
| } | ||
|
|
||
| void FunctionalityConstruction::addCcz(ZXDiagram& diag, const Qubit ctrl0, | ||
| const Qubit ctrl1, const Qubit target, | ||
| std::vector<Vertex>& qubits) { | ||
|
|
||
| addCnot(diag, ctrl1, target, qubits); | ||
| addZSpider(diag, target, qubits, PiExpression(PiRational(-1, 4))); | ||
| addCnot(diag, ctrl0, target, qubits); | ||
| addZSpider(diag, target, qubits, PiExpression(PiRational(1, 4))); | ||
| addCnot(diag, ctrl1, target, qubits); | ||
| addZSpider(diag, ctrl1, qubits, PiExpression(PiRational(1, 4))); | ||
| addZSpider(diag, target, qubits, PiExpression(PiRational(-1, 4))); | ||
| addCnot(diag, ctrl0, target, qubits); | ||
| addZSpider(diag, target, qubits, PiExpression(PiRational(1, 4))); | ||
| addCnot(diag, ctrl0, ctrl1, qubits); | ||
| addZSpider(diag, ctrl0, qubits, PiExpression(PiRational(1, 4))); | ||
| addZSpider(diag, ctrl1, qubits, PiExpression(PiRational(-1, 4))); | ||
| addZSpider(diag, target, qubits, PiExpression(PiRational(0, 1)), | ||
| EdgeType::Hadamard); | ||
| addCnot(diag, ctrl0, ctrl1, qubits); | ||
| addZSpider(diag, target, qubits, PiExpression(), EdgeType::Hadamard); | ||
| } | ||
|
|
||
| void FunctionalityConstruction::addCrz(ZXDiagram& diag, | ||
| const PiExpression& phase, | ||
| const Qubit q0, const Qubit q1, | ||
| std::vector<Vertex>& qubits) { | ||
| // CRZ decomposition uses reversed CNOT direction | ||
| addCnot(diag, q1, q0, qubits); | ||
| addZSpider(diag, q0, qubits, -phase / 2); | ||
| addZSpider(diag, q1, qubits, phase / 2); | ||
| addCnot(diag, q1, q0, qubits); | ||
| } | ||
|
|
||
| void FunctionalityConstruction::addMcrz(ZXDiagram& diag, | ||
| const PiExpression& phase, | ||
| std::vector<Qubit> controls, | ||
| const Qubit target, | ||
| std::vector<Vertex>& qubits) { | ||
|
|
||
| const Qubit nextControl = controls.back(); | ||
| controls.pop_back(); | ||
|
|
||
| addCrz(diag, phase / 2, nextControl, target, qubits); | ||
| addMcx(diag, controls, target, qubits); | ||
| addCrz(diag, -phase / 2, nextControl, target, qubits); | ||
| addMcx(diag, controls, target, qubits); | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| void FunctionalityConstruction::addMcx(ZXDiagram& diag, | ||
| std::vector<Qubit> controls, | ||
| const Qubit target, | ||
| std::vector<Vertex>& qubits) { | ||
|
|
||
| switch (controls.size()) { | ||
| case 0: | ||
| addXSpider(diag, target, qubits, PiExpression(PiRational(1, 1))); | ||
| return; | ||
| case 1: | ||
| addCnot(diag, controls.front(), target, qubits); | ||
| return; | ||
| case 2: | ||
| addCcx(diag, controls.front(), controls.back(), target, qubits); | ||
| return; | ||
| default: | ||
| const auto half = static_cast<std::ptrdiff_t>((controls.size() + 1) / 2); | ||
| const std::vector<Qubit> first(controls.begin(), controls.begin() + half); | ||
| std::vector<Qubit> second(controls.begin() + half, controls.end()); | ||
|
|
||
| if (qubits.size() > controls.size() + 1) { | ||
| controls.push_back(target); | ||
| std::optional<Qubit> anc{}; | ||
| for (std::size_t q = 0; q < qubits.size(); ++q) { | ||
| const auto qb = static_cast<Qubit>(q); | ||
| if (std::ranges::find(controls, qb) == controls.end()) { | ||
| anc = qb; | ||
| break; | ||
| } | ||
| } | ||
| if (!anc.has_value()) { | ||
| throw ZXException("No ancilla qubit available for MCX decomposition"); | ||
| } | ||
|
Comment on lines
+388
to
+390
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is unreachable code, right? There are more than I also think that you could be using https://en.cppreference.com/w/cpp/algorithm/set_difference.html here. |
||
|
|
||
| controls.pop_back(); | ||
| second.push_back(*anc); | ||
|
|
||
| addMcx(diag, first, *anc, qubits); | ||
| addMcx(diag, second, target, qubits); | ||
|
|
||
| addMcx(diag, first, *anc, qubits); | ||
| addMcx(diag, second, target, qubits); | ||
| } else { | ||
| addRx(diag, PiExpression(PiRational(1, 4)), target, qubits); | ||
| addMcz(diag, second, target, qubits); | ||
| addRx(diag, PiExpression(-PiRational(1, 4)), target, qubits); | ||
| addMcx(diag, first, target, qubits); | ||
|
|
||
| addRx(diag, PiExpression(PiRational(1, 4)), target, qubits); | ||
| addMcz(diag, second, target, qubits); | ||
| addRx(diag, PiExpression(-PiRational(1, 4)), target, qubits); | ||
| addMcx(diag, first, target, qubits); | ||
| const Qubit lastControl = controls.back(); | ||
| controls.pop_back(); | ||
| addMcrz(diag, PiExpression(PiRational(1, 2)), controls, lastControl, | ||
| qubits); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void FunctionalityConstruction::addMcz(ZXDiagram& diag, | ||
| std::vector<Qubit> controls, | ||
| const Qubit target, | ||
| std::vector<Vertex>& qubits) { | ||
| const Qubit nextControl = controls.back(); | ||
| controls.pop_back(); | ||
|
|
||
| addCrz(diag, PiExpression(PiRational(1, 2)), nextControl, target, qubits); | ||
| addMcx(diag, controls, target, qubits); | ||
| addCrz(diag, PiExpression(-PiRational(1, 2)), nextControl, target, qubits); | ||
| addMcx(diag, controls, target, qubits); | ||
|
Comment on lines
+425
to
+428
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't it be easier to either:
Does one of these yield a shorter decomposition? |
||
| } | ||
keefehuang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| FunctionalityConstruction::op_it | ||
| FunctionalityConstruction::parseOp(ZXDiagram& diag, op_it it, op_it end, | ||
| std::vector<Vertex>& qubits, | ||
|
|
@@ -538,6 +659,9 @@ FunctionalityConstruction::parseOp(ZXDiagram& diag, op_it it, op_it end, | |
| qubits[static_cast<std::size_t>(target)], | ||
| EdgeType::Hadamard); | ||
| break; | ||
| case qc::OpType::RZ: | ||
| addCrz(diag, parseParam(op.get(), 0), ctrl, target, qubits); | ||
| break; | ||
|
|
||
| case qc::OpType::I: | ||
| break; | ||
|
|
@@ -578,15 +702,39 @@ FunctionalityConstruction::parseOp(ZXDiagram& diag, op_it it, op_it end, | |
| ctrl1 = static_cast<Qubit>(p.at(ctrl.qubit)); | ||
| } | ||
| } | ||
| std::vector<Qubit> controls; | ||
| for (const auto& ctrl : op->getControls()) { | ||
| controls.push_back(static_cast<Qubit>(p.at(ctrl.qubit))); | ||
| } | ||
|
Comment on lines
+705
to
+708
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can just be inlined as |
||
| switch (op->getType()) { | ||
| case qc::OpType::X: | ||
| addCcx(diag, ctrl0, ctrl1, target, qubits); | ||
| break; | ||
|
|
||
| case qc::OpType::Z: | ||
| addZSpider(diag, target, qubits, PiExpression(), EdgeType::Hadamard); | ||
| addCcx(diag, ctrl0, ctrl1, target, qubits); | ||
| addZSpider(diag, target, qubits, PiExpression(), EdgeType::Hadamard); | ||
| addCcz(diag, ctrl0, ctrl1, target, qubits); | ||
| break; | ||
| case qc::OpType::RZ: | ||
| addMcrz(diag, parseParam(op.get(), 0), controls, target, qubits); | ||
| break; | ||
| default: | ||
| throw ZXException("Unsupported Multi-control operation: " + | ||
| qc::toString(op->getType())); | ||
| } | ||
| } else if (op->getNtargets() == 1) { | ||
| const auto target = static_cast<Qubit>(p.at(op->getTargets().front())); | ||
| std::vector<Qubit> controls; | ||
| for (const auto& ctrl : op->getControls()) { | ||
| controls.push_back(static_cast<Qubit>(p.at(ctrl.qubit))); | ||
| } | ||
|
Comment on lines
+725
to
+728
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Always good to use |
||
| switch (op->getType()) { | ||
| case qc::OpType::X: | ||
| addMcx(diag, controls, target, qubits); | ||
| break; | ||
| case qc::OpType::Z: | ||
| addMcz(diag, controls, target, qubits); | ||
| break; | ||
| case qc::OpType::RZ: | ||
| addMcrz(diag, parseParam(op.get(), 0), controls, target, qubits); | ||
| break; | ||
| default: | ||
| throw ZXException("Unsupported Multi-control operation: " + | ||
|
|
@@ -701,15 +849,16 @@ bool FunctionalityConstruction::transformableToZX(const qc::Operation* op) { | |
| case qc::OpType::S: | ||
| case qc::OpType::Tdg: | ||
| case qc::OpType::Sdg: | ||
| case qc::OpType::RZ: | ||
| return true; | ||
|
|
||
| default: | ||
| return false; | ||
| } | ||
| } else if (op->getNcontrols() == 2) { | ||
| } else if (op->getNtargets() == 1) { | ||
| switch (op->getType()) { | ||
| case qc::OpType::X: | ||
| case qc::OpType::Z: | ||
| case qc::OpType::RZ: | ||
| return true; | ||
| default: | ||
| return false; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These commute, so it does not really matter too much, but for consistency with the
mcrzpatter, I'd prefer this order.