intel-qs/unit_test/include/expectation_values_test.hpp

244 lines
9.7 KiB
C++

#ifndef EXPECTATION_VALUES_TEST_HPP
#define EXPECTATION_VALUES_TEST_HPP
#include "../../include/qureg.hpp"
//////////////////////////////////////////////////////////////////////////////
// Test fixture class.
class ExpectationValuesTest : public ::testing::Test
{
protected:
ExpectationValuesTest()
{ }
// just after the 'constructor'
void SetUp() override
{
// All tests are skipped if the rank is dummy.
if (qhipster::mpi::Environment::IsUsefulRank() == false)
GTEST_SKIP();
// All tests are skipped if the 4-qubit state is distributed in more than 8 ranks.
if (qhipster::mpi::Environment::GetStateSize() > 8)
GTEST_SKIP();
}
const std::size_t num_qubits_ = 6;
double accepted_error_ = 1e-14;
std::vector<unsigned> observables_;
std::vector<unsigned> qubits_;
double expectation_ = 0.;
double coeff_ = 1.;
double sqrt2_ = std::sqrt(2.);
};
//////////////////////////////////////////////////////////////////////////////
// Test macros:
TEST_F(ExpectationValuesTest, YZBaseChange)
{
ComplexDP amplitude_0, amplitude_1;
// In the implementation, the matrix G is used.
// G is matrix from change of basis Y --> Z, such that Ginv.Z.G = Y
qhipster::TinyMatrix<ComplexDP, 2, 2, 32> G;
double f = 1. / std::sqrt(2.);
G(0, 0) = G(1, 0) = ComplexDP(f , 0.);
G(0, 1) = ComplexDP(0.,-f);
G(1, 1) = ComplexDP(0., f);
// G^dagger = G^-1
qhipster::TinyMatrix<ComplexDP, 2, 2, 32> Ginv;
Ginv(0, 0) = Ginv(0, 1) = ComplexDP(f , 0.);
Ginv(1, 0) = ComplexDP(0., f);
Ginv(1, 1) = ComplexDP(0.,-f);
// Test from Y to Z basis (using matrix G).
QubitRegister<ComplexDP> psi (num_qubits_,"base",0);
psi.ApplyRotationX(0,-M_PI/2.);
// |psi> = |+y>|00000>
psi.Apply1QubitGate(0,G);
// |psi> = |0> |00000>
amplitude_0 = { 1. , 0. };
amplitude_1 = { 0. , 0. };
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(0), amplitude_0, accepted_error_);
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(1), amplitude_1, accepted_error_);
psi.Apply1QubitGate(0,Ginv);
// |psi> = |+y> |00000>
amplitude_0 = { f , 0. };
amplitude_1 = { 0. , f };
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(0), amplitude_0, accepted_error_);
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(1), amplitude_1, accepted_error_);
//
psi.Initialize("base",0);
psi.ApplyRotationX(0, M_PI/2.);
// |psi> = |-y>|00000>
psi.Apply1QubitGate(0,G);
// |psi> = |1> |00000>
amplitude_0 = { 0. , 0. };
amplitude_1 = { 1. , 0. };
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(0), amplitude_0, accepted_error_);
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(1), amplitude_1, accepted_error_);
psi.Apply1QubitGate(0,Ginv);
// |psi> = |1> |00000>
amplitude_0 = { f , 0. };
amplitude_1 = { 0. , -f };
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(0), amplitude_0, accepted_error_);
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(1), amplitude_1, accepted_error_);
// Test from Z to Y basis (using the inverse G^-1).
psi.Initialize("base",0);
psi.Apply1QubitGate(0,Ginv);
// |psi> = |+y>|00000>
amplitude_0 = { f , 0. };
amplitude_1 = { 0. , f };
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(0), amplitude_0, accepted_error_);
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(1), amplitude_1, accepted_error_);
psi.Apply1QubitGate(0,G);
// |psi> = |0> |00000>
amplitude_0 = { 1. , 0. };
amplitude_1 = { 0. , 0. };
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(0), amplitude_0, accepted_error_);
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(1), amplitude_1, accepted_error_);
//
psi.Initialize("base",1);
psi.Apply1QubitGate(0,Ginv);
// |psi> = |-y>|00000>
amplitude_0 = { f , 0. };
amplitude_1 = { 0. , -f };
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(0), amplitude_0, accepted_error_);
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(1), amplitude_1, accepted_error_);
psi.Apply1QubitGate(0,G);
// |psi> = |1> |00000>
amplitude_0 = { 0. , 0. };
amplitude_1 = { 1. , 0. };
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(0), amplitude_0, accepted_error_);
ASSERT_COMPLEX_NEAR(psi.GetGlobalAmplitude(1), amplitude_1, accepted_error_);
}
//////////////////////////////////////////////////////////////////////////////
TEST_F(ExpectationValuesTest, ExpectationOneQubit)
{
QubitRegister<ComplexDP> psi (num_qubits_,"base",10);
// |psi> = |010100> = |"2+8">
psi.ApplyHadamard(2);
psi.ApplyHadamard(3);
psi.ApplyRotationX(4,-M_PI/2.);
psi.ApplyRotationX(5, M_PI/2.);
// |psi> = |01> |+-> |+y-y>
ASSERT_NEAR(psi.ExpectationValueX(0, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueX(1, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueX(2, coeff_), 1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueX(3, coeff_), -1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueX(4, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueX(5, coeff_), 0., accepted_error_);
//
ASSERT_NEAR(psi.ExpectationValueY(0, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueY(1, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueY(2, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueY(3, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueY(4, coeff_), 1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueY(5, coeff_), -1., accepted_error_);
//
ASSERT_NEAR(psi.ExpectationValueZ(0, coeff_), 1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueZ(1, coeff_), -1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueZ(2, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueZ(3, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueZ(4, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueZ(5, coeff_), 0., accepted_error_);
}
//////////////////////////////////////////////////////////////////////////////
TEST_F(ExpectationValuesTest, ExpectationTwoQubits)
{
QubitRegister<ComplexDP> psi (num_qubits_,"base",10);
// |psi> = |010100> = |"2+8">
psi.ApplyHadamard(2);
psi.ApplyHadamard(3);
psi.ApplyRotationX(4,-M_PI/2.);
psi.ApplyRotationX(5, M_PI/2.);
// |psi> = |01> |+-> |+y-y>
ASSERT_NEAR(psi.ExpectationValueXX(0, 1, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueXX(1, 2, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueXX(2, 3, coeff_), -1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueXY(3, 4, coeff_), -1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueXY(3, 5, coeff_), 1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueXZ(2, 1, coeff_), -1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueXZ(2, 1, coeff_), -1., accepted_error_);
//
ASSERT_NEAR(psi.ExpectationValueYY(0, 1, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueYY(1, 2, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueYY(4, 5, coeff_), -1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueYZ(4, 0, coeff_), 1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueYZ(4, 1, coeff_), -1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueYX(5, 2, coeff_), -1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueYX(5, 3, coeff_), 1., accepted_error_);
//
ASSERT_NEAR(psi.ExpectationValueZZ(0, 1, coeff_), -1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueZZ(1, 2, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueZZ(2, 3, coeff_), 0., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueZX(0, 2, coeff_), 1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueZX(0, 3, coeff_), -1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueZY(1, 4, coeff_), -1., accepted_error_);
ASSERT_NEAR(psi.ExpectationValueZY(1, 5, coeff_), 1., accepted_error_);
}
//////////////////////////////////////////////////////////////////////////////
TEST_F(ExpectationValuesTest, GeneralMethod)
{
QubitRegister<ComplexDP> psi (num_qubits_,"base",2+8);
// |psi_0> = |010100> = |"2+8">
ASSERT_EQ(psi.GetProbability(0),0);
ASSERT_EQ(psi.GetProbability(1),1);
psi.ApplyHadamard(0);
psi.ApplyHadamard(1);
// |psi> = |+-0100>
ASSERT_DOUBLE_EQ(psi.GetProbability(0), 0.5);
ASSERT_DOUBLE_EQ(psi.GetProbability(1), 0.5);
// observable = X0 . X1 . Z2 . Z3
qubits_ = {0,1,2,3};
observables_ = {1,1,3,3};
expectation_ = psi.ExpectationValue(qubits_, observables_, coeff_);
ASSERT_NEAR(expectation_, 1., accepted_error_);
// observable = X1 . X0 . Z2 . Z4
qubits_ = {1,0,2,4};
expectation_ = psi.ExpectationValue(qubits_, observables_, coeff_);
ASSERT_NEAR(expectation_, -1., accepted_error_);
// observable = X0 . Z2 . Z3 . Z5 . Z4
qubits_ = {0,2,3,5,4};
observables_ = {1,3,3,3,3};
expectation_ = psi.ExpectationValue(qubits_, observables_, coeff_);
ASSERT_NEAR(expectation_, -1., accepted_error_);
// observable = X0 . id1 . Z2 . Z3
qubits_ = {3,0,2};
observables_ = {3,1,3};
ASSERT_NEAR(psi.ExpectationValue(qubits_, observables_, coeff_), -1., accepted_error_);
psi.Initialize("base",10);
psi.ApplyHadamard(2);
psi.ApplyHadamard(3);
psi.ApplyRotationX(4,-M_PI/2.);
psi.ApplyRotationX(5, M_PI/2.);
// |psi> = |01> |+-> |+y-y>
// observable = Z1 . X2 . Y5
qubits_ = {1,2,5};
observables_ = {3,1,2};
ASSERT_NEAR(psi.ExpectationValue(qubits_, observables_, coeff_), 1., accepted_error_);
// observable = Z0 . X2 . Y4 . Y5
qubits_ = {0,2,4,5};
observables_ = {3,1,2,2};
ASSERT_NEAR(psi.ExpectationValue(qubits_, observables_, coeff_), -1., accepted_error_);
// observable = Z0 . Z1 . X2 . X3 . Y4 . Y5
qubits_ = {0,1,2,3,4,5};
observables_ = {3,3,1,1,2,2};
ASSERT_NEAR(psi.ExpectationValue(qubits_, observables_, coeff_), -1., accepted_error_);
}
//////////////////////////////////////////////////////////////////////////////
#endif // header guard EXPECTATION_VALUES_TEST_HPP