/*
 * Invert a toeplitz matrix. Input is the first column of the matrix and also
 * is the output.
 * IMP - size must be a power of two.
 */
void serial_matrix_inversion(size_t size, const fftw_complex *input, fftw_complex *result) {

    if(size < 1) return;

    //base case
    result[0] = 1 / input[0];
    if(size < 2) return;
    result[1] = - result[0] * input[1] * result[0];


    unsigned int current_size = 2;

    while(current_size < size) {

        fftw_complex *reversed_input = alloc_reverse_from_vec(current_size * 2 - 1, input);

        fftw_complex *temporary = alloc_complex(current_size);


        //first convolution
        toeplitz_mult(current_size, reversed_input, result, temporary);


        fftw_complex *reversed_inverted_pad = alloc_complex(current_size * 2 - 1);
        zero_memory(current_size * 2 - 1, reversed_inverted_pad);

        memcpy(reversed_inverted_pad + (current_size-1), result,
               current_size * sizeof(fftw_complex));

        reverse_vec(current_size * 2 - 1, reversed_inverted_pad);


        //second convolution
        reverse_vec(current_size, temporary);
        toeplitz_mult(current_size, reversed_inverted_pad, temporary, reversed_input);

        //complement sign
        for(int i=0; i < current_size; i++)
            reversed_input[i] = - reversed_input[i];

        reverse_vec(current_size, reversed_input);

        //finally copy in result vec
        memcpy(result + current_size, reversed_input, current_size * sizeof(fftw_complex));


        fftw_free(temporary);
        fftw_free(reversed_input);
        fftw_free(reversed_inverted_pad);
        current_size *= 2;
    }
}
static void nufft_apply_normal(const void* _data, complex float* dst, const complex float* src)
{
	const struct nufft_data* data = _data;

	if (data->conf.toeplitz) {

		toeplitz_mult(data, dst, src);

	} else {

		complex float* tmp_ksp = md_alloc(data->N + 3, data->ksp_dims, CFL_SIZE);
		nufft_apply((const void*)data, tmp_ksp, src);
		nufft_apply_adjoint((const void*)data, dst, tmp_ksp);
		md_free(tmp_ksp);
	}
}