#include<mkl_service.h>
#include<mpi.h>
#include<mkl_cluster_sparse_solver.h>
#include<iostream>
#include<fstream>
#include<iterator>
#include<complex>
#include<vector>
#include<unistd.h>

int main()
{
  MPI::Init_thread(MPI::THREAD_FUNNELED);
  ::mkl_set_num_threads(2);
  for(auto counter(0);counter!=100;++counter)
  {
    std::vector<std::complex<double>>a,b,x;
    std::vector<int>ia,ja;
    std::vector<int>iparm(64);
    iparm.at(0)=1; 
    iparm.at(1)=2; 
    iparm.at(7)=2; 
    iparm.at(9)=13; 
    iparm.at(10)=1; 
    iparm.at(12)=1; 
    iparm.at(17)=-1; 
    iparm.at(18)=-1; 
    iparm.at(26)=1;
    iparm.at(34)=1; 
    iparm.at(39)=2;
    if(MPI::COMM_WORLD.Get_rank()==0)
    {
      std::cout<<getpid()<<std::endl;
      std::ifstream a0{"a0"},ia0{"ia0"},ja0{"ja0"},b0{"b0"};
      a=std::vector<std::complex<double>>(std::istream_iterator<std::complex<double>>{a0},std::istream_iterator<std::complex<double>>{});
      ia=std::vector<int>(std::istream_iterator<int>{ia0},std::istream_iterator<int>{});
      ja=std::vector<int>(std::istream_iterator<int>{ja0},std::istream_iterator<int>{});
      b=std::vector<std::complex<double>>(std::istream_iterator<std::complex<double>>{b0},std::istream_iterator<std::complex<double>>{});
      x.resize(b.size());
      iparm.at(40)=0;
      iparm.at(41)=1904;
    }
    else
    {
      std::ifstream a1{"a1"},ia1{"ia1"},ja1{"ja1"},b1{"b1"};
      a=std::vector<std::complex<double>>(std::istream_iterator<std::complex<double>>{a1},std::istream_iterator<std::complex<double>>{});
      ia=std::vector<int>(std::istream_iterator<int>{ia1},std::istream_iterator<int>{});
      ja=std::vector<int>(std::istream_iterator<int>{ja1},std::istream_iterator<int>{});
      b=std::vector<std::complex<double>>(std::istream_iterator<std::complex<double>>{b1},std::istream_iterator<std::complex<double>>{});
      x.resize(b.size());
      iparm.at(40)=1905;
      iparm.at(41)=4821;
    }
    void* pt[64]={0};
    int maxfct{1},mnum{1},msglvl{0},error,phase{11},mtype{6},n{4822},idum,nrhs{1924};
    double ddum;  
    auto comm(MPI::COMM_WORLD.Dup());
    auto fcomm(MPI_Comm_c2f(comm));
    cluster_sparse_solver(pt,&maxfct, &mnum, &mtype, &phase,&n, a.data(), ia.data(), ja.data(), &idum, &nrhs, iparm.data(), &msglvl, &ddum, &ddum, &fcomm, &error );
    phase=22;
    cluster_sparse_solver(pt,&maxfct, &mnum, &mtype, &phase,&n, a.data(), ia.data(), ja.data(), &idum, &nrhs, iparm.data(), &msglvl, &ddum, &ddum, &fcomm, &error );
    phase=33;
    cluster_sparse_solver(pt,&maxfct, &mnum, &mtype, &phase,&n, a.data(), ia.data(), ja.data(), &idum, &nrhs, iparm.data(), &msglvl, b.data(), x.data(), &fcomm, &error );
    /*!MPI::COMM_WORLD.Get_rank())
    {
      std::ofstream x0{"x0"};
      std::copy(x.cbegin(),x.cend(),std::ostream_iterator<std::complex<double>>{x0," "});
      x0<<std::endl;
    }
    else
    {
      std::ofstream x1{"x1"};
      std::copy(x.cbegin(),x.cend(),std::ostream_iterator<std::complex<double>>{x1," "});
      x1<<std::endl;
    }*/
    phase=-1;
    cluster_sparse_solver(pt,&maxfct, &mnum, &mtype, &phase,&n, &ddum, ia.data(), ja.data(), &idum, &nrhs, iparm.data(), &msglvl, &ddum, &ddum, &fcomm, &error );
    comm.Free();
    if(MPI::COMM_WORLD.Get_rank()==0) std::cout<<counter<<std::endl;
  }
  MPI::Finalize();
}
