12 #include <unordered_map>    28     template <
class SimulatorType>
    31         std::unordered_set<std::string> 
default_gates {
"X", 
"Y", 
"Z", 
"I", 
"H"};
    55             using Mat2x2Type = decltype(std::declval<SimulatorType>().getGateX());
   104             void addToMaps( SimulatorType& qSim, std::string U_label, 
const Mat2x2Type& U, std::size_t num_ctrl_lines){
   105                 gate_cache.addToCache(qSim, U_label, U, num_ctrl_lines);
   137                     const std::vector<std::size_t> ctrlIndices,
   138                     const std::vector<std::size_t> auxIndices,
   139                     const unsigned int qTarget,
   140                     const std::string gateLabel,
   142                     const std::size_t depth
   145                 int local_depth = depth + 1;
   148                 std::size_t cOps = ctrlIndices.size();
   175                 if( (cOps >= 5) && ( auxIndices.size() >= cOps-2 ) && (gateLabel == 
"X") && (depth == 0) ){ 
   176                     qSim.applyGateCCX( ctrlIndices.back(), *(auxIndices.begin() + ctrlIndices.size() - 3), qTarget);
   178                     for (std::size_t i = ctrlIndices.size()-2; i >= 2; i--){
   179                         qSim.applyGateCCX( *(ctrlIndices.begin()+i), *(auxIndices.begin() + (i-2)), *(auxIndices.begin() + (i-1)));
   181                     qSim.applyGateCCX( *(ctrlIndices.begin()), *(ctrlIndices.begin()+1), *(auxIndices.begin()) );
   183                     for (std::size_t i = 2; i <= ctrlIndices.size()-2; i++){
   184                         qSim.applyGateCCX( *(ctrlIndices.begin()+i), *(auxIndices.begin()+(i-2)), *(auxIndices.begin()+(i-1)));
   186                     qSim.applyGateCCX( ctrlIndices.back(), *(auxIndices.begin() + ctrlIndices.size() - 3), qTarget);
   188                     for (std::size_t i = ctrlIndices.size()-2; i >= 2; i--){
   189                         qSim.applyGateCCX( *(ctrlIndices.begin()+i), *(auxIndices.begin() + (i-2)), *(auxIndices.begin() + (i-1)));
   191                     qSim.applyGateCCX( *(ctrlIndices.begin()), *(ctrlIndices.begin()+1), *(auxIndices.begin()) );
   192                     for (std::size_t i = 2; i <= ctrlIndices.size()-2; i++){
   193                         qSim.applyGateCCX( *(ctrlIndices.begin()+i), *(auxIndices.begin()+(i-2)), *(auxIndices.begin()+(i-1)));
   199                     qSim.applyGateCU( 
gate_cache.gateCacheMap[gateLabel][local_depth+1].first, ctrlIndices[0], qTarget, gateLabel );
   200                     qSim.applyGateCX( ctrlIndices[0], ctrlIndices[1]);
   202                     qSim.applyGateCU( 
gate_cache.gateCacheMap[gateLabel][local_depth+1].second, ctrlIndices[1], qTarget, gateLabel );
   203                     qSim.applyGateCX( ctrlIndices[0], ctrlIndices[1]);
   205                     qSim.applyGateCU( 
gate_cache.gateCacheMap[gateLabel][local_depth+1].first, ctrlIndices[1], qTarget, gateLabel );
   206                     qSim.applyGateCX( ctrlIndices[1], ctrlIndices[2]);
   208                     qSim.applyGateCU( 
gate_cache.gateCacheMap[gateLabel][local_depth+1].second, ctrlIndices[2], qTarget, gateLabel );
   209                     qSim.applyGateCX( ctrlIndices[0], ctrlIndices[2]);
   211                     qSim.applyGateCU( 
gate_cache.gateCacheMap[gateLabel][local_depth+1].first, ctrlIndices[2], qTarget, gateLabel );
   212                     qSim.applyGateCX( ctrlIndices[1], ctrlIndices[2]);
   214                     qSim.applyGateCU( 
gate_cache.gateCacheMap[gateLabel][local_depth+1].second, ctrlIndices[2], qTarget, gateLabel );
   215                     qSim.applyGateCX( ctrlIndices[0], ctrlIndices[2]);
   217                     qSim.applyGateCU( 
gate_cache.gateCacheMap[gateLabel][local_depth+1].first, ctrlIndices[2], qTarget, gateLabel );
   220                 else if (cOps >= 2 && cOps !=3){
   221                     std::vector<std::size_t> subCtrlIndices(ctrlIndices.begin(), ctrlIndices.end()-1);
   223                     qSim.applyGateCU( 
gate_cache.gateCacheMap[gateLabel][local_depth].first, ctrlIndices.back(), qTarget, gateLabel );
   225                     applyNQubitControl(qSim, subCtrlIndices, auxIndices, ctrlIndices.back(), 
"X", qSim.getGateX(), 0 );
   227                     qSim.applyGateCU( 
gate_cache.gateCacheMap[gateLabel][local_depth].second, ctrlIndices.back(), qTarget, gateLabel );
   229                     applyNQubitControl(qSim, subCtrlIndices, auxIndices, ctrlIndices.back(), 
"X", qSim.getGateX(), 0 );
   231                     applyNQubitControl(qSim, subCtrlIndices, auxIndices, qTarget, gateLabel, 
gate_cache.gateCacheMap[gateLabel][local_depth+1].first, local_depth );
   236                     qSim.applyGateCU(
gate_cache.gateCacheMap[gateLabel][depth].first, ctrlIndices[0], qTarget, gateLabel); 
   248             std::size_t num_ops = 0;
   251                 std::cout << 
"get_op_calls CTRL=" << num_ctrl_lines << 
"  OPS=" << it->second << std::endl;
   255             else if (num_ctrl_lines >= 2){
   262             std::cout << 
"get_op_calls CTRL=" << num_ctrl_lines << 
"  OPS=" << num_ops << std::endl;
   291                 std::cout << 
"FOUND OPTIMAL PARAMS SEARCH FOR CTRL=" << num_ctrl_lines << 
"  M=" << it->second.m << 
" L=" << it->second.l << 
" OPS=" << it->second.num_ops << std::endl;
   297             std::size_t num_comp = static_cast<std::size_t>(std::floor((
float)(num_ctrl_lines)/2.0)) +1;
   300             std::size_t tmp_num_ops;
   302             for(std::size_t _m = 2; _m <= num_comp; ++_m){
   303                 std::size_t _l = (num_ctrl_lines - _m + 1);
   306                     optimal_params = 
OptParamsCX{num_ctrl_lines, _m, _l, tmp_num_ops};
   308                 else if ( tmp_num_ops < optimal_params.
num_ops){
   309                     optimal_params = 
OptParamsCX{num_ctrl_lines, _m, _l, tmp_num_ops};
   311                 std::cout << 
"OPTIMAL PARAMS SEARCH FOR CTRL=" << num_ctrl_lines << 
"  M=" << _m << 
" L=" << _l << 
" OPS=" << tmp_num_ops << std::endl;
   315             std::cout << 
"OPTIMAL PARAMS FOR CTRL=" << num_ctrl_lines << 
"  M=" << optimal_params.
m << 
" L=" << optimal_params.
l << 
" OPS=" << optimal_params.
num_ops << std::endl;
   316             return optimal_params;
 GateCache< SimulatorType > gate_cache
 
OptParamsCX find_optimal_params(std::size_t num_ctrl_lines)
Returns the number of 2-qubit operations an optimised decomposition will make for nCX....
 
std::unordered_set< std::string > default_gates
 
For the 5+ controlled NCX decomposition routines defined within https://arxiv.org/pdf/quant-ph/950301...
 
static std::size_t num_gate_ops
 
NCU(SimulatorType &qSim)
Construct a new NCU object.
 
Class to cache intermediate matrix values used within other parts of the computation....
 
Templated methods to manipulate small matrices.
 
std::unordered_map< std::size_t, std::size_t > op_call_counts_CX
 
Class definition for applying n-qubit controlled unitary operations.
 
void addToMaps(SimulatorType &qSim, std::string U_label, const Mat2x2Type &U, std::size_t num_ctrl_lines)
Add the given unitary matrix to the maps up to the required depth.
 
~NCU()
Destroy the NCU object.
 
void applyNQubitControl(SimulatorType &qSim, const std::vector< std::size_t > ctrlIndices, const std::vector< std::size_t > auxIndices, const unsigned int qTarget, const std::string gateLabel, const Mat2x2Type &U, const std::size_t depth)
Decompose n-qubit controlled op into 1 and 2 qubit gates. Control indices can be in any specified loc...
 
std::unordered_map< std::size_t, OptParamsCX > opt_op_call_params_CX
 
GateCache< SimulatorType > & getGateCache()
Get the Map of cached gates. Keys are strings, and values are vectors of paired (gate,...
 
void clearMaps()
Clears the maps of stored sqrt matrices.
 
void initialiseMaps(SimulatorType &qSim, std::size_t num_ctrl_lines)
Add the PauliX and the given unitary U to the maps.
 
std::size_t get_op_calls(std::size_t num_ctrl_lines)
Returns the number of 2-qubit operations a non optimised decomposition will make. Cache intermediate ...
 
NCU()
Construct a new NCU object.
 
std::size_t get_ops_for_params(std::size_t l, std::size_t m)
Helper method to get optimised number of 2-gate ops for given decomposition params.
 
decltype(std::declval< SimulatorType >().getGateX()) Mat2x2Type