//---------------------------------------------------------------------------
// Controlled Rotate Gate
//---------------------------------------------------------------------------
#include <cmath>
#include <math.h>
#include "QC_crot.h"
//---------------------------------------------------------------------------
/**
 * Constructor
 */
QC_crot::QC_crot(int _TargetBit,int _ControlBit, double degree) : QCalcUnit() {
    TargetBit = _TargetBit;
    ControlBit = _ControlBit;
    Theta = M_PI * degree / 180.0;
}
//---------------------------------------------------------------------------
/**
 * Calculation
 */
void
QC_crot::calc(int Target, int Control, double theta,
              double R[], double I[], int NumberOfBits) {
    unsigned int states = 1<< (NumberOfBits - 2);

    int Bit0 = Target;
    int Bit1 = Control;
    if (Bit0 > Bit1) swap(Bit0, Bit1);

    const double c     = std::cos(theta);
    const double s     = std::sin(theta);

    double r1, i1;
    for (unsigned int i = 0; i < states; i++) {
        unsigned int ix1 = QCalcUnit::insert1(i,   Bit0);
        ix1 = QCalcUnit::insert1(ix1, Bit1);
        double r1 = R[ix1];
        double i1 = I[ix1];

        R[ix1] =  c*r1 - s*i1;
        I[ix1] =  s*r1 + c*i1;
    }
}
//---------------------------------------------------------------------------
void
QC_crot::Calc(QBits *qBits) {
    int N = qBits->GetNumberOfQBits();
    double *R = qBits->GetBitsR();//Real Part
    double *I = qBits->GetBitsI();//Imaginary Part

    QC_crot::calc(TargetBit, ControlBit, Theta, R, I, N);
}
//---------------------------------------------------------------------------
#ifdef __USE__MPI
void
QC_crot::calcmpi(int t1, int c1, double theta, double R[], double I[], int N) {
    const double c     = std::cos(theta);
    const double s     = std::sin(theta);
    double r0 = 0.0;
    double i0 = 0.0;
    double r1 = 0.0;
    double i1 = 0.0;
    unsigned int ix0, ix1;

    // Sort BitsNumber to regular order
    int Bit0 = t1;
    int Bit1 = c1;
    if (Bit0 > Bit1) {
        swap(Bit0, Bit1);
    }

    for (int i = 0; i < (1 << (N - 2)); i++) {
        // Obtain indices of state:
        unsigned int ix1 = QCalcUnit::insert1(i,   Bit0);
        ix1 = QCalcUnit::insert1(ix1, Bit1);
        unsigned int ix0 = ix1 & ~(1 << t1);

        bool bstore = setup(R, I, ix0, ix1, r0, i0, r1, i1);
        if (bstore) {
            double nr0 = r0;
            double ni0 = i0;
            double nr1 = c*r1 - s*i1;
            double ni1 = s*r1 + c*i1;
            // Store:
            store(R, I, ix0, ix1, nr0, ni0, nr1, ni1);
        }
    }
}
#endif
//---------------------------------------------------------------------------
