From e89a3bccbe4bbf431ff0816d085686276f3f3ccc Mon Sep 17 00:00:00 2001 From: Hiroshi Horii Date: Sun, 1 Sep 2019 02:52:44 +0900 Subject: [PATCH 1/2] support cu1 fusion --- src/transpile/fusion.hpp | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/transpile/fusion.hpp b/src/transpile/fusion.hpp index fe83d9875f..ce326e0d80 100644 --- a/src/transpile/fusion.hpp +++ b/src/transpile/fusion.hpp @@ -15,6 +15,8 @@ #ifndef _aer_transpile_fusion_hpp_ #define _aer_transpile_fusion_hpp_ +//#define DEBUG + #include "transpile/circuitopt.hpp" namespace AER { @@ -116,6 +118,7 @@ const std::vector Fusion::supported_gates({ // Two-qubit gates "CX", // Controlled-X gate (CNOT) "cx", // Controlled-X gate (CNOT) + "cu1", // Controlled-U1 gate "cz", // Controlled-Z gate "swap" // SWAP gate // Three-qubit gates @@ -514,21 +517,21 @@ bool Fusion::only_u1(const std::vector& ops, const uint_t until) const { for (uint_t i = from; i <= until; ++i) { - if (ops[i].name == "u1") - continue; - if (from < i && (i + 2) <= until - && ops[i - 1].name == "u1" - && ops[i ].name == "cx" - && ops[i + 1].name == "u1" - && ops[i + 2].name == "cx" - && ops[i - 1].qubits[0] == ops[i ].qubits[1] - && ops[i ].qubits[1] == ops[i + 1].qubits[0] - && ops[i + 1].qubits[0] == ops[i + 2].qubits[1] - && ops[i ].qubits[0] == ops[i + 2].qubits[0] ) + if ((i + 3) <= until + && ops[i ].name == "u1" + && ops[i + 1].name == "cx" + && ops[i + 2].name == "u1" + && ops[i + 3].name == "cx" + && ops[i ].qubits[0] == ops[i + 1].qubits[1] + && ops[i + 1].qubits[1] == ops[i + 2].qubits[0] + && ops[i + 2].qubits[0] == ops[i + 3].qubits[1] + && ops[i + 1].qubits[0] == ops[i + 3].qubits[0] ) { - i += 2; + i += 3; continue; } + if (ops[i].name == "u1" || ops[i].name == "cu1") + continue; return false; } return true; @@ -579,6 +582,13 @@ cmatrix_t Fusion::matrix(const op_t& op) const { { {1, 0}, {0, 0} }, { {0, 0}, std::exp( complex_t(0, 1.) * std::real(op.params[0])) }} ); + } else if (op.name == "cu1") { // zero-X90 pulse waltz gate + return Utils::make_matrix( { + { {1, 0}, {0, 0}, {0, 0}, {0, 0} }, + { {0, 0}, {1, 0}, {0, 0}, {0, 0} }, + { {0, 0}, {0, 0}, {1, 0}, {0, 0} }, + { {0, 0}, {0, 0}, {0, 0}, std::exp( complex_t(0, 1.) * std::real(op.params[0])) }} + ); } else if (op.name == "u2") { // single-X90 pulse waltz gate return Utils::Matrix::u3( M_PI / 2., std::real(op.params[0]), std::real(op.params[1])); } else if (op.name == "u3" || op.name == "U") { // two X90 pulse waltz gate From f3c075e9c52fd11f9accdcaa558ec2b053d17463 Mon Sep 17 00:00:00 2001 From: Hiroshi Horii Date: Fri, 6 Sep 2019 21:44:58 +0900 Subject: [PATCH 2/2] simplify a logic to identify an unrolled cu1 --- src/transpile/fusion.hpp | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/transpile/fusion.hpp b/src/transpile/fusion.hpp index ce326e0d80..9c6cd2a349 100644 --- a/src/transpile/fusion.hpp +++ b/src/transpile/fusion.hpp @@ -15,8 +15,6 @@ #ifndef _aer_transpile_fusion_hpp_ #define _aer_transpile_fusion_hpp_ -//#define DEBUG - #include "transpile/circuitopt.hpp" namespace AER { @@ -73,9 +71,9 @@ class Fusion : public CircuitOptimization { const reg_t& dst_sorted_qubits, const cmatrix_t& mat) const; - bool only_u1(const oplist_t& ops, - const uint_t from, - const uint_t until) const; + bool is_diagonal(const oplist_t& ops, + const uint_t from, + const uint_t until) const; double estimate_cost(const oplist_t& ops, const uint_t from, @@ -512,22 +510,26 @@ cmatrix_t Fusion::sort_matrix(const reg_t &src, return ret; } -bool Fusion::only_u1(const std::vector& ops, - const uint_t from, - const uint_t until) const { +bool Fusion::is_diagonal(const std::vector& ops, + const uint_t from, + const uint_t until) const { + + // check unitary matrix of ops between "from" and "to" is a diagonal matrix for (uint_t i = from; i <= until; ++i) { - if ((i + 3) <= until - && ops[i ].name == "u1" - && ops[i + 1].name == "cx" - && ops[i + 2].name == "u1" - && ops[i + 3].name == "cx" - && ops[i ].qubits[0] == ops[i + 1].qubits[1] - && ops[i + 1].qubits[1] == ops[i + 2].qubits[0] - && ops[i + 2].qubits[0] == ops[i + 3].qubits[1] - && ops[i + 1].qubits[0] == ops[i + 3].qubits[0] ) + // ┌───┐┌────┐┌───┐ + // ─┤ X ├┤ U1 ├┤ X ├ + // └─┬─┘└────┘└─┬─┘ + // ───■──────────■─- + if ((i + 2) <= until + && ops[i + 0].name == "cx" + && ops[i + 1].name == "u1" + && ops[i + 2].name == "cx" + && ops[i + 0].qubits[1] == ops[i + 1].qubits[0] + && ops[i + 1].qubits[0] == ops[i + 2].qubits[1] + && ops[i + 0].qubits[0] == ops[i + 2].qubits[0] ) { - i += 3; + i += 2; continue; } if (ops[i].name == "u1" || ops[i].name == "cu1") @@ -540,7 +542,7 @@ bool Fusion::only_u1(const std::vector& ops, double Fusion::estimate_cost(const std::vector& ops, const uint_t from, const uint_t until) const { - if (only_u1(ops, from, until)) + if (is_diagonal(ops, from, until)) return cost_factor_; reg_t fusion_qubits;