// File: /workspace/github_cpp_makefile_star2_O2/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:
pushq %r14
pushq %rbx
subq $0xb08, %rsp            # imm = 0xB08
leaq 0x12aded(%rip), %rsi    # 0x23b121
leaq 0x70(%rsp), %rdi
leaq 0x1e0(%rsp), %rbx
movq %rbx, %rdx
callq 0x1102e8
xorps %xmm0, %xmm0
leaq 0x30(%rsp), %r14
movaps %xmm0, (%r14)
andq $0x0, 0x10(%r14)
movaps %xmm0, 0x10(%rsp)
andq $0x0, 0x20(%rsp)
xorl %edi, %edi
callq 0x10e360
movl %eax, %edi
callq 0x10e590
movsd 0x125c8d(%rip), %xmm0   # 0x236008
movsd 0x125c8d(%rip), %xmm1   # 0x236010
ucomisd %xmm0, %xmm1
jb 0x1103f3
movsd %xmm0, 0x8(%rsp)
callq 0x10e4e0
cvtsi2sd %eax, %xmm0
mulsd 0x125c78(%rip), %xmm0   # 0x236018
addsd 0x125c78(%rip), %xmm0   # 0x236020
mulsd 0x125c78(%rip), %xmm0   # 0x236028
movsd %xmm0, 0x48(%rsp)
movsd 0x8(%rsp), %xmm0
mulsd 0x125c6c(%rip), %xmm0   # 0x236030
callq 0x10e1a0
addsd 0x48(%rsp), %xmm0
movsd %xmm0, 0x1e0(%rsp)
movq %r14, %rdi
movq %rbx, %rsi
callq 0x1115b2
movsd 0x8(%rsp), %xmm0
addsd 0x125c47(%rip), %xmm0   # 0x236038
jmp 0x11037b
movq 0x38(%rsp), %rsi
subq 0x30(%rsp), %rsi
sarq $0x3, %rsi
leaq 0x10(%rsp), %rdi
callq 0x1106b2
movq %rsp, %rdi
pushq $0x1
popq %rsi
callq 0x1106e4
leaq 0x12b2bd(%rip), %rsi    # 0x23b6da
leaq 0x1e0(%rsp), %rdi
leaq 0x90(%rsp), %rdx
callq 0x1102e8
movq %rsp, %rdi
leaq 0x1e0(%rsp), %rsi
leaq 0x30(%rsp), %rdx
callq 0x110708
leaq 0x1e0(%rsp), %rdi
callq 0x10e5e8
leaq 0x12b284(%rip), %rsi    # 0x23b6df
leaq 0x1e0(%rsp), %rdi
leaq 0x90(%rsp), %rdx
callq 0x1102e8
movq %rsp, %rdi
leaq 0x1e0(%rsp), %rsi
leaq 0x10(%rsp), %rdx
callq 0x110708
leaq 0x1e0(%rsp), %rdi
callq 0x10e5e8
leaq 0x50(%rsp), %rdi
callq 0x110772
leaq 0x50(%rsp), %rdi
movq %rsp, %rsi
callq 0x1107d2
leaq 0x90(%rsp), %rdi
pushq $0x7f
popq %rsi
callq 0x11082e
leaq 0x1e0(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x11093e
leaq 0x90(%rsp), %rdi
callq 0x110f56
leaq 0x1e0(%rsp), %rdi
leaq 0x70(%rsp), %rsi
leaq 0x50(%rsp), %rdx
callq 0x110f9e
movq 0x50(%rsp), %rax
movq 0x8(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
xorl %r14d, %r14d
leaq 0x12b1da(%rip), %rbx    # 0x23b6e5
movq 0x10(%rsp), %rax
movq 0x18(%rsp), %rcx
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rcx, %r14
jae 0x110541
movq 0x30(%rsp), %rcx
movsd (%rcx,%r14,8), %xmm0
movsd (%rax,%r14,8), %xmm1
movq %rbx, %rdi
movb $0x2, %al
callq 0x10e060
incq %r14
jmp 0x11050b
leaq 0x1e0(%rsp), %rdi
callq 0x111420
leaq 0x50(%rsp), %rdi
callq 0x11155a
movq %rsp, %rdi
callq 0x111570
leaq 0x10(%rsp), %rdi
callq 0x235574
leaq 0x30(%rsp), %rdi
callq 0x235574
leaq 0x70(%rsp), %rdi
callq 0x10e5e8
addq $0xb08, %rsp            # imm = 0xB08
popq %rbx
popq %r14
retq
movq %rax, %rbx
leaq 0x90(%rsp), %rdi
callq 0x110f56
jmp 0x1105d3
jmp 0x11059d
movq %rax, %rbx
jmp 0x1105d3
jmp 0x1105ba
jmp 0x1105a8
jmp 0x1105ba
movq %rax, %rbx
leaq 0x1e0(%rsp), %rdi
callq 0x10e5e8
jmp 0x1105dd
movq %rax, %rbx
jmp 0x1105dd
jmp 0x1105e7
jmp 0x1105e7
movq %rax, %rbx
leaq 0x1e0(%rsp), %rdi
callq 0x111420
leaq 0x50(%rsp), %rdi
callq 0x11155a
movq %rsp, %rdi
callq 0x111570
jmp 0x1105ea
movq %rax, %rbx
leaq 0x10(%rsp), %rdi
callq 0x235574
leaq 0x30(%rsp), %rdi
callq 0x235574
leaq 0x70(%rsp), %rdi
callq 0x10e5e8
movq %rbx, %rdi
callq 0x10e310