mirror of https://github.com/intel/intel-qs.git
175 lines
5.2 KiB
C++
175 lines
5.2 KiB
C++
//------------------------------------------------------------------------------
|
|
// Copyright (C) 2017 Intel Corporation
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "../include/qureg.hpp"
|
|
|
|
using Type = ComplexDP;
|
|
using namespace std;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
template<typename Type>
|
|
void GenerateGateSet(std::vector <std::pair<std::string,TM2x2<Type>>> &sqg,
|
|
std::vector <std::pair<std::string,TM2x2<Type>>> &cqg)
|
|
{
|
|
TM2x2<Type> eye, X, sqrtX, Y, sqrtY, Z, sqrtZ, H, T;
|
|
|
|
sqg.resize(0);
|
|
cqg.resize(0);
|
|
|
|
// create vector of single qubit gates
|
|
eye(0,0) = {1., 0.};
|
|
eye(0,1) = {0., 0.};
|
|
eye(1,0) = {0., 0.};
|
|
eye(1,1) = {1., 0.};
|
|
eye.name = "i";
|
|
|
|
X(0, 0) = Type(0., 0.); X(0, 1) = Type(1., 0.);
|
|
X(1, 0) = Type(1., 0.); X(1, 1) = Type(0., 0.);
|
|
X.name = "x";
|
|
|
|
sqrtX(0, 0) = Type(0.5, 0.5); sqrtX(0, 1) = Type(0.5, -0.5);
|
|
sqrtX(1, 0) = Type(0.5, -0.5); sqrtX(1, 1) = Type(0.5, 0.5);
|
|
sqrtX.name = "x_1_2";
|
|
|
|
Y(0, 0) = Type(0., 0.); Y(0, 1) = Type(0., -1.);
|
|
Y(1, 0) = Type(0., 1.); Y(1, 1) = Type(0., 0.);
|
|
Y.name = "y";
|
|
|
|
sqrtY(0, 0) = Type(0.5, 0.5); sqrtY(0, 1) = Type(-0.5, -0.5);
|
|
sqrtY(1, 0) = Type(0.5, 0.5); sqrtY(1, 1) = Type(0.5, 0.5);
|
|
sqrtY.name = "y_1_2";
|
|
|
|
Z(0, 0) = Type(1., 0.); Z(0, 1) = Type(0., 0.);
|
|
Z(1, 0) = Type(0., 0.); Z(1, 1) = Type(-1., 0.);
|
|
Z.name = "z";
|
|
|
|
sqrtZ(0, 0) = Type(1., 0.); sqrtZ(0, 1) = Type(0., 0.);
|
|
sqrtZ(1, 0) = Type(0., 0.); sqrtZ(1, 1) = Type(0., 1.);
|
|
sqrtZ.name = "z_1_2";
|
|
|
|
T(0, 0) = Type(1.0, 0.0); T(0, 1) = Type(0.0, 0.0);
|
|
T(1, 0) = Type(0.0, 0.0); T(1, 1) = Type(cos(M_PI/4.0), sin(M_PI/4.0));
|
|
T.name = "t";
|
|
|
|
double f = 1. / std::sqrt(2.);
|
|
H(0, 0) = H(0, 1) = H(1, 0) = Type(f, 0.);
|
|
H(1, 1) = Type(-f, 0.);
|
|
H.name = "h";
|
|
|
|
sqg = {{" h ", H }, {" x_1_2 ", sqrtX}, {" y_1_2 ", sqrtY}, {" z_1_2 ", sqrtZ}, {" t ", T }};
|
|
cqg = {{" cz ", Z}, {" ch ", H }};
|
|
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
unsigned myrank;
|
|
qhipster::mpi::Environment env(argc, argv);
|
|
if (env.IsUsefulRank() == false) return 0;
|
|
myrank = env.GetStateRank();
|
|
|
|
unsigned num_qubits = 3, num_threads = 1;
|
|
std::size_t tmp_size = 0;
|
|
if(argc != 2)
|
|
{
|
|
fprintf(stderr, "usage: %s <num_qubits>\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
else
|
|
{
|
|
int _qubits = atoi(argv[1]);
|
|
|
|
if ((_qubits <= 0) || (_qubits > 1000000)) {
|
|
fprintf(stderr, "<num_qubits> was (%d) which is invalid or negative.\n", _qubits);
|
|
exit(1);
|
|
}
|
|
|
|
num_qubits = (unsigned)_qubits;
|
|
}
|
|
|
|
|
|
std::vector <std::pair<std::string,TM2x2<Type>>> sqg, cqg;
|
|
GenerateGateSet<Type>(sqg, cqg);
|
|
|
|
// To generate a random state, we need to create a random number generator first.
|
|
qhipster::mpi::PoolPrint("---- State initialization |psi_1>.\n");
|
|
qhipster::RandomNumberGenerator<double> rnd_generator_1;
|
|
rnd_generator_1.SetSeedStreamPtrs(20971);
|
|
QubitRegister<ComplexDP> psi1(num_qubits, "base", 0, 2097152);
|
|
psi1.SetRngPtr(&rnd_generator_1);
|
|
psi1.Initialize("rand",1);
|
|
|
|
qhipster::mpi::PoolPrint("---- State initialization |psi_2>.\n");
|
|
qhipster::RandomNumberGenerator<double> rnd_generator_2;
|
|
rnd_generator_2.SetSeedStreamPtrs(20971);
|
|
QubitRegister<ComplexDP> psi2(num_qubits, "base", 0, 2097152);
|
|
psi2.SetRngPtr(&rnd_generator_2);
|
|
psi2.Initialize("rand",1);
|
|
|
|
psi2.TurnOnSpecialize();
|
|
#ifdef INTELQS_HAS_MPI
|
|
psi2.EnableStatistics();
|
|
#endif
|
|
|
|
qhipster::mpi::PoolPrint("---- One-qubit gates.\n");
|
|
|
|
for(auto g: sqg)
|
|
{
|
|
for(int pos = 16; pos < num_qubits; pos++)
|
|
{
|
|
psi1.Apply1QubitGate(pos, g.second);
|
|
psi2.Apply1QubitGate(pos, g.second);
|
|
assert(psi1 == psi2);
|
|
}
|
|
}
|
|
|
|
qhipster::mpi::PoolPrint("---- Two-qubit gates.\n");
|
|
|
|
for (auto &g : cqg)
|
|
{
|
|
TM2x2<Type> &m = g.second;
|
|
for (unsigned q1 = 0; q1 < num_qubits; q1++)
|
|
{
|
|
for (unsigned q2 = 0; q2 < num_qubits; q2++)
|
|
{
|
|
if (q1 != q2)
|
|
{
|
|
psi1.ApplyControlled1QubitGate(q1, q2, m);
|
|
psi2.ApplyControlled1QubitGate(q1, q2, m);
|
|
assert(psi1 == psi2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
qhipster::mpi::PoolPrint("---- End of test.\n");
|
|
|
|
#ifdef INTELQS_HAS_MPI
|
|
psi2.GetStatistics();
|
|
#else
|
|
std::cout << "The test was successfully executed.\n"
|
|
<< "However the output statistics are not available when the "
|
|
<< "compiler flag INTELQS_HAS_MPI is not defined.\n";
|
|
#endif
|
|
|
|
return 1;
|
|
}
|