void pade_interpolator::pade_interpolate(const imaginary_domain_data &data, real_domain_data &real){
  
  int N_real=real.N_real();
  int N_imag=data.N_imag();
  
  //extract Matsubara frequencies, Matsubara data, and real frequencies
  pade_complex_vector_type real_frequencies(N_real);
  pade_complex_vector_type matsubara_frequencies(N_imag);
  pade_complex_vector_type matsubara_values(N_imag);
  for(int i=0;i<N_real;++i){
    real_frequencies[i]=pade_complex_type(real.freq()[i], 0);
  }
  for(int i=0;i<N_imag;++i){
    matsubara_frequencies[i]=pade_complex_type(0.,data.freq()[i]);
    matsubara_values     [i]=pade_complex_type(data.val()[i].real(), data.val()[i].imag());
  }
  
  pade_complex_vector_type alpha_sx(N_imag);
  pade_complex_vector_type phi_mu_nu(N_imag);
  double norm=data.norm();
  
  
  ////DEBUG
  int N=21;
  pade_complex_vector_type input_x(N), input_y(N);
  for(int i=0;i<N;++i){ input_x[i]=0.1*i; input_y[i]=pade_complex_type(sin(0.1*i)); }
  pade_complex_vector_type pmn(N);
  pade_mu_=20;
  pade_nu_=0;
  for(pade_complex_type x=pade_complex_type(-2.); x.real()<pade_complex_type(-1.999).real(); x=x+pade_complex_type(0.2)){
    //pade_complex_type x=3.001;
    pade_complex_vector_type asx(N); for(int i=0;i<N;++i) asx[i]=x-input_x[i];
    //for(int i=0;i<N;++i){ std::cout<<input_x[i]<<" "<<input_y[i]<<" "<<asx[i]<<std::endl;}
    pade_complex_type z=pade_scheme(pmn, input_x, input_y, asx, x);
    std::cout<<x.real()<<" "<<z.real()<<" "<<z.imag()<<std::endl;
  }
  exit(0);
  ////DEBUG
  
  
  
  //interpolate 'alpha', the distance from each point to x
#pragma omp parallel for default(none) shared(real,std::cerr) firstprivate(N_imag,N_real,real_frequencies,alpha_sx,matsubara_frequencies,matsubara_values,phi_mu_nu, norm)
  for(int i=0;i<N_real;++i){
    pade_complex_type x=real_frequencies[i];
    std::pair<bool, int> v=init_alpha(N_imag, alpha_sx,matsubara_frequencies, x);
    if(v.first){ //tried to evaluate on a point where we know the function
      real.val()[i]=to_simple_precision(matsubara_values[v.second]);
      continue;
    }
    
    //run neville scheme
#pragma omp critical
    std::cerr<<"computing pade for i: "<<i<<std::endl;
    real.val()[i]=to_simple_precision(pade_scheme(phi_mu_nu, matsubara_frequencies, matsubara_values, alpha_sx, x))*norm;
  }
}
int 
LOCA::Epetra::AugmentedOp::ApplyInverse(const Epetra_MultiVector& Input, 
					Epetra_MultiVector& Result) const
{

  // Get number of vectors
  int n = Input.NumVectors();

  // Check num vectors is correct
  if (importedInput == NULL || n != importedInput->NumVectors())
    globalData->locaErrorCheck->throwError(
				 "LOCA::Epetra::AugmentedOp::ApplyInverse()"
				 "Must call init() before ApplyInverse()!");

  // Import parameter components
  importedInput->Import(Input, *extendedImporter, Insert);

  // get views
  double **input_view;
  double **result_view;
  importedInput->ExtractView(&input_view);
  Result.ExtractView(&result_view);

  // get views of paramter components
  // this is done by setting the pointer for each column to start at
  // underlyingLength
  double **input_view_y = new double*[n];
  for (int i=0; i<n; i++)
    input_view_y[i] = input_view[i]+underlyingLength;

  // break input, result into components
  Epetra_MultiVector input_x(View, underlyingMap, input_view, n);
  Epetra_MultiVector input_y(View, localMap, input_view_y, n);
  Epetra_MultiVector result_x(View, underlyingMap, result_view, n);

  // copy input_y into result_y
  result_y->Scale(1.0, input_y);

  // Temporary epetra vectors
  Epetra_MultiVector tmp2(c);
  tmp->PutScalar(0.0);
 
  // Solve J*result_x = input_x 
  jacOperator->ApplyInverse(input_x, result_x);

  if (useTranspose) {

    // Solve J*tmp = b
    jacOperator->ApplyInverse(*b, *tmp);

    // Compute input_y - a^T*result_x
    result_y->Multiply('T', 'N', -1.0, *a, result_x, 1.0);

    // Compute c - a^T*tmp
    tmp2.Multiply('T', 'N', -1.0, *a, *tmp, 1.0);

  }
  else {

    // Solve J*tmp = a
    jacOperator->ApplyInverse(*a, *tmp);

    // Compute input_y - b^T*result_x
    result_y->Multiply('T', 'N', -1.0, *b, result_x, 1.0);

    // Compute c - b^T*tmp1
    tmp2.Multiply('T', 'N', -1.0, *b, *tmp, 1.0);

  }

  // Solve (c - z^T*tmp1)^-1 * (input_y - z^T*result_x)  where z = a or b
  int *ipiv = new int[numConstraints];
  int info;
  double *result_y_view; 
  int result_y_lda;
  result_y->ExtractView(&result_y_view, &result_y_lda);
  double *tmp2_view;
  int tmp2_lda;
  tmp2.ExtractView(&tmp2_view, &tmp2_lda);
  dlapack.GESV(numConstraints, n, tmp2_view, tmp2_lda, ipiv, result_y_view, 
	       result_y_lda, &info);
  delete [] ipiv;
  if (info != 0) {
    globalData->locaErrorCheck->throwError(
				 "LOCA::Epetra::AugmentedOp::ApplyInverse()"
				 "Solve of dense matrix failed!");
  }
  
  // Compute result_x = result_x - tmp*result_y
  result_x.Multiply('N', 'N', -1.0, *tmp, *result_y, 1.0);

  // Set parameter component
  if (haveParamComponent)
    for (int j=0; j<n; j++)
      for (int i=0; i<numConstraints; i++)
	result_view[j][underlyingLength+i] = (*result_y)[j][i];

  delete [] input_view_y;

  return 0;
}
int 
LOCA::Epetra::AugmentedOp::Apply(const Epetra_MultiVector& Input, 
				 Epetra_MultiVector& Result) const
{

  // Get number of vectors
  int n = Input.NumVectors();

  // Check num vectors is correct
  if (importedInput == NULL || n != importedInput->NumVectors())
    globalData->locaErrorCheck->throwError("LOCA::Epetra::AugmentedOp::Apply()"
					   "Must call init() before Apply()!");

  // Import parameter components
  importedInput->Import(Input, *extendedImporter, Insert);

  // get views
  double **input_view;
  double **result_view;
  importedInput->ExtractView(&input_view);
  Result.ExtractView(&result_view);

  // get views of paramter components
  // this is done by setting the pointer for each column to start at
  // underlyingLength
  double **input_view_y = new double*[n];
  for (int i=0; i<n; i++)
    input_view_y[i] = input_view[i]+underlyingLength;

  // break input, result into components
  Epetra_MultiVector input_x(View, underlyingMap, input_view, n);
  Epetra_MultiVector input_y(View, localMap, input_view_y, n);
  Epetra_MultiVector result_x(View, underlyingMap, result_view, n);

  // Compute J*input_x
  jacOperator->Apply(input_x, result_x);

  if (useTranspose) {
    
    // Compute J^T*input_x + b*input_y
    result_x.Multiply('N', 'N', 1.0, *b, input_y, 1.0);

    // Compute a^T*input_x + c^T*input_y
    result_y->Multiply('T', 'N', 1.0, *a, input_x, 0.0);
    result_y->Multiply('T', 'N', 1.0, c, input_y, 1.0);

  }
  else {
    
    // Compute J*input_x + a*input_y
    result_x.Multiply('N', 'N', 1.0, *a, input_y, 1.0);

    // Compute b^T*input_x + c*input_y
    result_y->Multiply('T', 'N', 1.0, *b, input_x, 0.0);
    result_y->Multiply('N', 'N', 1.0, c, input_y, 1.0);

  }

  // Set parameter component
  if (haveParamComponent)
    for (int j=0; j<n; j++)
      for (int i=0; i<numConstraints; i++)
	result_view[j][underlyingLength+i] = (*result_y)[j][i];

   delete [] input_view_y;

  return 0;
}