// File: /workspace/github_cpp_makefile_star2_O2/matteotiziano[P]simple-wavelet/main.cpp
// Function: main
int main(int argc, const char *argv[]) {

  // Read arguments from command line
  if(argc < 3) {
    std::cout << "usage: " << std::string(argv[0]) << " num_rows num_cols num_levels" << std::endl;
    return 1;
  }

  // TODO: handle invalid inputs

  // Size of the matrix
  const size_t num_rows = static_cast<size_t>(std::stoi(argv[1]));
  const size_t num_cols = static_cast<size_t>(std::stoi(argv[2]));
  // Number of decomposition levels
  const size_t num_levels = static_cast<size_t>(std::stoi(argv[3]));

  // Initialise a random 2D matrix using seed equal to 0
  // Note: use `matrix.Rand();` without argument to generate
  // different values at each execution
  Matrix<double> matrix(num_rows, num_cols);
  matrix.Rand(0);

  // Filters definition of Discrete Haar transform
  // https://en.wikipedia.org/wiki/Haar_wavelet#Haar_transform
  const double inv_sqrt2 = 1.0 / std::sqrt(2.0);
  const std::vector<double> Lo_D = {inv_sqrt2, inv_sqrt2};
  const std::vector<double> Hi_D = {-inv_sqrt2, inv_sqrt2};
  const std::vector<double> Lo_R = {inv_sqrt2, inv_sqrt2};
  const std::vector<double> Hi_R = {inv_sqrt2, -inv_sqrt2};

  // Instantiate a Wavelet object with Haar filters
  const Wavelet<double> haar(Lo_D, Hi_D, Lo_R, Hi_R);


  // Example of 1D decomposition and reconstruction using the first column of
  // the above matrix as input
  const std::vector<double> vector = matrix.GetColumn(0);
  const Decomposition1D<double> dec1D = haar.Wavedec(vector, num_levels);
  const std::vector<double> vector_rec = haar.Waverec(dec1D, vector.size());
  const double norm1D = Norm(vector - vector_rec);

  // Example of 2D decomposition and reconstruction
  const Decomposition2D<double> dec2D = haar.Wavedec(matrix, num_levels);
  const Matrix<double> matrix_rec = haar.Waverec(dec2D, matrix.Size());
  const double norm2D = Norm((matrix - matrix_rec).GetData());

  std::cout << "Error (l2-norm) of 1D reconstruction: " << norm1D << std::endl;
  std::cout << "Error (l2-norm) of 2D reconstruction: " << norm2D << std::endl;

  return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x200, %rsp            # imm = 0x200
movq %rsi, %rbx
cmpl $0x2, %edi
jg 0x24e1
movq 0xab1e(%rip), %rdi      # 0xcfa8
leaq 0x5baf(%rip), %rsi      # 0x8040
callq 0x21c0
movq %rax, %r14
movq (%rbx), %rsi
leaq 0x70(%rsp), %rdi
leaq 0x48(%rsp), %rdx
callq 0x29e8
leaq 0x70(%rsp), %rsi
movq %r14, %rdi
callq 0x21a0
leaq 0x5b89(%rip), %rsi      # 0x8048
movq %rax, %rdi
callq 0x21c0
movq %rax, %rdi
callq 0x20d0
leaq 0x70(%rsp), %rdi
callq 0x20c0
pushq $0x1
popq %rax
jmp 0x2883
movq 0x8(%rbx), %rsi
leaq 0x70(%rsp), %rdi
leaq 0x48(%rsp), %rdx
callq 0x29e8
leaq 0x70(%rsp), %rdi
pushq $0xa
popq %rdx
xorl %esi, %esi
callq 0x2a23
movl %eax, %ebp
leaq 0x70(%rsp), %rdi
callq 0x20c0
movq 0x10(%rbx), %rsi
leaq 0x70(%rsp), %rdi
leaq 0x48(%rsp), %rdx
callq 0x29e8
leaq 0x70(%rsp), %rdi
pushq $0xa
popq %rdx
xorl %esi, %esi
callq 0x2a23
movl %eax, %r14d
leaq 0x70(%rsp), %rdi
callq 0x20c0
movq 0x18(%rbx), %rsi
leaq 0x70(%rsp), %rdi
leaq 0x48(%rsp), %rdx
callq 0x29e8
leaq 0x70(%rsp), %rdi
pushq $0xa
popq %rdx
xorl %esi, %esi
callq 0x2a23
movl %eax, %ebx
movslq %ebp, %r15
movslq %r14d, %r14
leaq 0x70(%rsp), %rdi
callq 0x20c0
leaq 0x48(%rsp), %r12
xorps %xmm0, %xmm0
movq %r12, %rdi
movq %r15, %rsi
movq %r14, %rdx
callq 0x5968
movq %r12, %rdi
xorl %esi, %esi
callq 0x6202
movaps 0x5a77(%rip), %xmm0     # 0x8010
leaq 0x70(%rsp), %rsi
movaps %xmm0, (%rsi)
leaq 0x198(%rsp), %rdi
pushq $0x2
popq %rdx
leaq 0x8(%rsp), %rcx
callq 0x2a40
movaps 0x5a63(%rip), %xmm0     # 0x8020
leaq 0x70(%rsp), %rsi
movaps %xmm0, (%rsi)
leaq 0x180(%rsp), %rdi
pushq $0x2
popq %rdx
leaq 0x8(%rsp), %rcx
callq 0x2a40
leaq 0x70(%rsp), %rsi
movaps 0x5a2a(%rip), %xmm0     # 0x8010
movaps %xmm0, (%rsi)
leaq 0x168(%rsp), %rdi
pushq $0x2
popq %rdx
leaq 0x8(%rsp), %rcx
callq 0x2a40
movaps 0x5a2b(%rip), %xmm0     # 0x8030
leaq 0x70(%rsp), %rsi
movaps %xmm0, (%rsi)
leaq 0x150(%rsp), %rdi
pushq $0x2
popq %rdx
leaq 0x8(%rsp), %rcx
callq 0x2a40
leaq 0x70(%rsp), %rdi
leaq 0x198(%rsp), %rsi
leaq 0x180(%rsp), %rdx
leaq 0x168(%rsp), %rcx
leaq 0x150(%rsp), %r8
callq 0x3482
leaq 0x30(%rsp), %rdi
leaq 0x48(%rsp), %rsi
xorl %edx, %edx
callq 0x5fa6
movslq %ebx, %rbx
leaq 0x138(%rsp), %rdi
leaq 0x70(%rsp), %rsi
leaq 0x30(%rsp), %rdx
movq %rbx, %rcx
callq 0x3560
movq 0x38(%rsp), %rcx
subq 0x30(%rsp), %rcx
sarq $0x3, %rcx
leaq 0x120(%rsp), %rdi
leaq 0x70(%rsp), %rsi
leaq 0x138(%rsp), %rdx
callq 0x373e
leaq 0x108(%rsp), %rdi
leaq 0x30(%rsp), %rsi
callq 0x2b30
leaq 0x8(%rsp), %rdi
leaq 0x108(%rsp), %rsi
leaq 0x120(%rsp), %rdx
callq 0x2a95
leaq 0x8(%rsp), %rdi
callq 0x2a76
movsd %xmm0, 0xe8(%rsp)
leaq 0x8(%rsp), %rdi
callq 0x2d52
leaq 0x108(%rsp), %rdi
callq 0x2d52
leaq 0xf0(%rsp), %rdi
leaq 0x70(%rsp), %rsi
leaq 0x48(%rsp), %rdx
movq %rbx, %rcx
callq 0x3b58
leaq 0x48(%rsp), %rdi
callq 0x5a9e
leaq 0x1b0(%rsp), %rcx
movq %rax, (%rcx)
movq %rdx, 0x8(%rcx)
leaq 0x8(%rsp), %rdi
leaq 0x70(%rsp), %rsi
leaq 0xf0(%rsp), %rdx
callq 0x3d9e
leaq 0x1d8(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x2b7e
leaq 0x1b0(%rsp), %rdi
leaq 0x48(%rsp), %rsi
leaq 0x1d8(%rsp), %rdx
callq 0x68d8
leaq 0x1b0(%rsp), %rdi
callq 0x6018
movq %rax, %rdi
callq 0x2a76
movsd %xmm0, 0xe0(%rsp)
leaq 0x1b0(%rsp), %rdi
callq 0x5a8a
leaq 0x1d8(%rsp), %rdi
callq 0x5a8a
movq 0xa7fb(%rip), %rdi      # 0xcfa8
leaq 0x58b2(%rip), %rsi      # 0x8066
callq 0x21c0
movq %rax, %rdi
movsd 0xe8(%rsp), %xmm0
callq 0x2250
movq %rax, %rdi
callq 0x20d0
movq 0xa7cf(%rip), %rdi      # 0xcfa8
leaq 0x58ad(%rip), %rsi      # 0x808d
callq 0x21c0
movq %rax, %rdi
movsd 0xe0(%rsp), %xmm0
callq 0x2250
movq %rax, %rdi
callq 0x20d0
leaq 0x8(%rsp), %rdi
callq 0x5a8a
leaq 0xf0(%rsp), %rdi
callq 0x329c
leaq 0x120(%rsp), %rdi
callq 0x2d52
leaq 0x138(%rsp), %rdi
callq 0x300a
leaq 0x30(%rsp), %rdi
callq 0x2d52
leaq 0x70(%rsp), %rdi
callq 0x3538
leaq 0x150(%rsp), %rdi
callq 0x2d52
leaq 0x168(%rsp), %rdi
callq 0x2d52
leaq 0x180(%rsp), %rdi
callq 0x2d52
leaq 0x198(%rsp), %rdi
callq 0x2d52
leaq 0x48(%rsp), %rdi
callq 0x5a8a
xorl %eax, %eax
addq $0x200, %rsp            # imm = 0x200
popq %rbx
popq %r12
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
jmp 0x2934
jmp 0x295a
jmp 0x28c6
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0x2d52
jmp 0x28b4
movq %rax, %rbx
leaq 0x108(%rsp), %rdi
callq 0x2d52
jmp 0x2974
movq %rax, %rbx
jmp 0x2974
movq %rax, %rbx
jmp 0x2981
movq %rax, %rbx
jmp 0x298e
movq %rax, %rbx
jmp 0x2998
movq %rax, %rbx
jmp 0x29a2
movq %rax, %rbx
jmp 0x29af
movq %rax, %rbx
jmp 0x29bc
movq %rax, %rbx
jmp 0x29c9
jmp 0x2908
movq %rax, %rbx
jmp 0x29d6
jmp 0x2948
jmp 0x291c
jmp 0x2948
jmp 0x291c
jmp 0x2948
jmp 0x291c
movq %rax, %rbx
jmp 0x29e0
movq %rax, %rbx
leaq 0x1b0(%rsp), %rdi
callq 0x5a8a
leaq 0x1d8(%rsp), %rdi
callq 0x5a8a
jmp 0x295d
movq %rax, %rbx
jmp 0x2967
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x20c0
jmp 0x29e0
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0x5a8a
leaq 0xf0(%rsp), %rdi
callq 0x329c
leaq 0x120(%rsp), %rdi
callq 0x2d52
leaq 0x138(%rsp), %rdi
callq 0x300a
leaq 0x30(%rsp), %rdi
callq 0x2d52
leaq 0x70(%rsp), %rdi
callq 0x3538
leaq 0x150(%rsp), %rdi
callq 0x2d52
leaq 0x168(%rsp), %rdi
callq 0x2d52
leaq 0x180(%rsp), %rdi
callq 0x2d52
leaq 0x198(%rsp), %rdi
callq 0x2d52
leaq 0x48(%rsp), %rdi
callq 0x5a8a
movq %rbx, %rdi
callq 0x22c0