// File: ArashPartow[P]exprtk/exprtk_simple_example_13.cpp
// Function: void savitzky_golay_filter<double>()
void savitzky_golay_filter()
{
   typedef exprtk::symbol_table<T> symbol_table_t;
   typedef exprtk::expression<T>   expression_t;
   typedef exprtk::parser<T>       parser_t;

   const std::string sgfilter_program =
      " var weight[9] :=                                            "
      "     {                                                       "
      "        -21, 14,  39,                                        "
      "         54, 59,  54,                                        "
      "         39, 14, -21                                         "
      "     };                                                      "
      "                                                             "
      " if (v_in[] >= weight[])                                     "
      " {                                                           "
      "    const var lower_bound := trunc(weight[] / 2);            "
      "    const var upper_bound := v_in[] - lower_bound;           "
      "                                                             "
      "    v_out := 0;                                              "
      "                                                             "
      "    for (var i := lower_bound; i < upper_bound; i += 1)      "
      "    {                                                        "
      "       for (var j := -lower_bound; j <= lower_bound; j += 1) "
      "       {                                                     "
      "          v_out[i] += weight[j + lower_bound] * v_in[i + j]; "
      "       };                                                    "
      "    };                                                       "
      "                                                             "
      "    v_out /= sum(weight);                                    "
      " }                                                           ";

   const std::size_t n = 1024;

   std::vector<T> v_in;
   std::vector<T> v_out;

   const T pi = T(3.141592653589793238462643383279502);

   srand(static_cast<unsigned int>(time(0)));

   // Generate a signal with noise.
   for (T t = T(-5); t <= T(+5); t += T(10.0 / n))
   {
      const T noise = T(0.5 * (rand() / (RAND_MAX + 1.0) - 0.5));
      v_in.push_back(sin(2.0 * pi * t) + noise);
   }

   v_out.resize(v_in.size());

   symbol_table_t symbol_table;
   symbol_table.add_vector("v_in" , v_in );
   symbol_table.add_vector("v_out", v_out);

   expression_t expression;
   expression.register_symbol_table(symbol_table);

   parser_t parser;
   parser.compile(sgfilter_program,expression);

   expression.value();

   for (std::size_t i = 0; i < v_out.size(); ++i)
   {
      printf("%10.6f\t%10.6f\n", v_in[i], v_out[i]);
   }
}

// Assembly:
subq $0xbb8, %rsp            # imm = 0xBB8
leaq 0xb97(%rsp), %rdi
movq %rdi, 0x28(%rsp)
callq 0x111650
movq 0x28(%rsp), %rdx
leaq 0x330d10(%rip), %rsi    # 0x449565
leaq 0xb98(%rsp), %rdi
callq 0x118770
jmp 0x118864
leaq 0xb97(%rsp), %rdi
callq 0x111790
movq $0x400, 0xb78(%rsp) # imm = 0x400
leaq 0xb60(%rsp), %rdi
callq 0x119010
leaq 0xb48(%rsp), %rdi
callq 0x119010
movsd 0x32b771(%rip), %xmm0   # 0x444010
movsd %xmm0, 0xb40(%rsp)
xorl %eax, %eax
movl %eax, %edi
callq 0x1114a0
movl %eax, %edi
callq 0x111740
movsd 0x32b748(%rip), %xmm0   # 0x444008
movsd %xmm0, 0xb38(%rsp)
movsd 0x32b747(%rip), %xmm0   # 0x444018
ucomisd 0xb38(%rsp), %xmm0
jb 0x1189b5
callq 0x111670
cvtsi2sd %eax, %xmm0
movsd 0x32b72f(%rip), %xmm1   # 0x444020
mulsd %xmm1, %xmm0
movsd 0x32b72b(%rip), %xmm1   # 0x444028
subsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
movsd %xmm0, 0xb30(%rsp)
movsd 0xb38(%rsp), %xmm0
movsd 0x32b711(%rip), %xmm1   # 0x444030
mulsd %xmm1, %xmm0
callq 0x111290
movsd 0xb30(%rsp), %xmm1
addsd %xmm1, %xmm0
movsd %xmm0, 0xb28(%rsp)
leaq 0xb60(%rsp), %rdi
leaq 0xb28(%rsp), %rsi
callq 0x119020
jmp 0x118955
jmp 0x118957
movsd 0x32b6d9(%rip), %xmm0   # 0x444038
addsd 0xb38(%rsp), %xmm0
movsd %xmm0, 0xb38(%rsp)
jmp 0x1188c9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xb88(%rsp)
movl %eax, 0xb84(%rsp)
leaq 0xb97(%rsp), %rdi
callq 0x111790
jmp 0x118d63
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xb88(%rsp)
movl %eax, 0xb84(%rsp)
jmp 0x118d3c
leaq 0xb60(%rsp), %rdi
callq 0x1190f0
movq %rax, %rsi
leaq 0xb48(%rsp), %rdi
callq 0x119050
jmp 0x1189d4
leaq 0xb20(%rsp), %rdi
movl $0x1, %esi
callq 0x119110
jmp 0x1189e8
leaq 0xaff(%rsp), %rdi
movq %rdi, 0x20(%rsp)
callq 0x111650
movq 0x20(%rsp), %rdx
leaq 0x331118(%rip), %rsi    # 0x449b1e
leaq 0xb00(%rsp), %rdi
callq 0x118770
jmp 0x118a15
leaq 0xb20(%rsp), %rdi
leaq 0xb00(%rsp), %rsi
leaq 0xb60(%rsp), %rdx
callq 0x119150
jmp 0x118a34
leaq 0xb00(%rsp), %rdi
callq 0x1117a8
leaq 0xaff(%rsp), %rdi
callq 0x111790
leaq 0xad7(%rsp), %rdi
movq %rdi, 0x18(%rsp)
callq 0x111650
movq 0x18(%rsp), %rdx
leaq 0x3310b7(%rip), %rsi    # 0x449b23
leaq 0xad8(%rsp), %rdi
callq 0x118770
jmp 0x118a7b
leaq 0xb20(%rsp), %rdi
leaq 0xad8(%rsp), %rsi
leaq 0xb48(%rsp), %rdx
callq 0x119150
jmp 0x118a9a
leaq 0xad8(%rsp), %rdi
callq 0x1117a8
leaq 0xad7(%rsp), %rdi
callq 0x111790
leaq 0xab0(%rsp), %rdi
callq 0x119210
jmp 0x118ac3
leaq 0xab0(%rsp), %rdi
leaq 0xb20(%rsp), %rsi
callq 0x1192c0
jmp 0x118ada
leaq 0x38(%rsp), %rdi
movl $0x7f, %esi
callq 0x119370
jmp 0x118aeb
leaq 0x188(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x1194a0
jmp 0x118aff
leaq 0x38(%rsp), %rdi
callq 0x119cd0
leaq 0x188(%rsp), %rdi
leaq 0xb98(%rsp), %rsi
leaq 0xab0(%rsp), %rdx
callq 0x119d40
jmp 0x118b28
leaq 0xab0(%rsp), %rdi
callq 0x11a5d0
jmp 0x118b37
movq $0x0, 0x30(%rsp)
movq 0x30(%rsp), %rax
movq %rax, 0x10(%rsp)
leaq 0xb48(%rsp), %rdi
callq 0x1190f0
movq %rax, %rcx
movq 0x10(%rsp), %rax
cmpq %rcx, %rax
jae 0x118ccc
movq 0x30(%rsp), %rsi
leaq 0xb60(%rsp), %rdi
callq 0x11a5f0
movsd (%rax), %xmm0
movsd %xmm0, 0x8(%rsp)
movq 0x30(%rsp), %rsi
leaq 0xb48(%rsp), %rdi
callq 0x11a5f0
movsd 0x8(%rsp), %xmm0
movsd (%rax), %xmm1
leaq 0x330f82(%rip), %rdi    # 0x449b29
movb $0x2, %al
callq 0x111080
jmp 0x118bb0
jmp 0x118bb2
movq 0x30(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x30(%rsp)
jmp 0x118b40
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xb88(%rsp)
movl %eax, 0xb84(%rsp)
jmp 0x118bfc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xb88(%rsp)
movl %eax, 0xb84(%rsp)
leaq 0xb00(%rsp), %rdi
callq 0x1117a8
leaq 0xaff(%rsp), %rdi
callq 0x111790
jmp 0x118d2f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xb88(%rsp)
movl %eax, 0xb84(%rsp)
jmp 0x118c45
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xb88(%rsp)
movl %eax, 0xb84(%rsp)
leaq 0xad8(%rsp), %rdi
callq 0x1117a8
leaq 0xad7(%rsp), %rdi
callq 0x111790
jmp 0x118d2f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xb88(%rsp)
movl %eax, 0xb84(%rsp)
jmp 0x118d2f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xb88(%rsp)
movl %eax, 0xb84(%rsp)
jmp 0x118d22
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xb88(%rsp)
movl %eax, 0xb84(%rsp)
leaq 0x38(%rsp), %rdi
callq 0x119cd0
jmp 0x118d22
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xb88(%rsp)
movl %eax, 0xb84(%rsp)
leaq 0x188(%rsp), %rdi
callq 0x11a610
jmp 0x118d22
leaq 0x188(%rsp), %rdi
callq 0x11a610
leaq 0xab0(%rsp), %rdi
callq 0x11a810
leaq 0xb20(%rsp), %rdi
callq 0x11a850
leaq 0xb48(%rsp), %rdi
callq 0x11a8d0
leaq 0xb60(%rsp), %rdi
callq 0x11a8d0
leaq 0xb98(%rsp), %rdi
callq 0x1117a8
addq $0xbb8, %rsp            # imm = 0xBB8
retq
leaq 0xab0(%rsp), %rdi
callq 0x11a810
leaq 0xb20(%rsp), %rdi
callq 0x11a850
leaq 0xb48(%rsp), %rdi
callq 0x11a8d0
leaq 0xb60(%rsp), %rdi
callq 0x11a8d0
leaq 0xb98(%rsp), %rdi
callq 0x1117a8
movq 0xb88(%rsp), %rdi
callq 0x111440