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

   const std::string linear_least_squares_program =
      " if (x[] == y[])                                        "
      " {                                                      "
      "    var mean_x := avg(x);                               "
      "    var mean_y := avg(y);                               "
      "                                                        "
      "    beta  := sum((x - mean_x) * (y - mean_y)) /         "
      "             sum((x - mean_x)^2);                       "
      "                                                        "
      "    alpha := mean_y - beta * mean_x;                    "
      "                                                        "
      "    rmse  := sqrt(sum((beta * x + alpha - y)^2) / y[]); "
      " }                                                      "
      " else                                                   "
      " {                                                      "
      "    alpha := null;                                      "
      "    beta  := null;                                      "
      "    rmse  := null;                                      "
      " }                                                      ";

   T x[] = { T(1.0), T(2.0), T(3.0), T(4.0), T(5.0), T(6.0), T(7.0), T(8.0), T(9.0), T(10) };
   T y[] = { T(8.7), T(6.8), T(6.0), T(5.6), T(3.8), T(3.0), T(2.4), T(1.7), T(0.4), T(-1) };

   T alpha = T(0);
   T beta  = T(0);
   T rmse  = T(0);

   symbol_table_t symbol_table;
   symbol_table.add_variable("alpha", alpha);
   symbol_table.add_variable("beta" , beta );
   symbol_table.add_variable("rmse" , rmse );
   symbol_table.add_vector  ("x"    , x    );
   symbol_table.add_vector  ("y"    , y    );

   expression_t expression;
   expression.register_symbol_table(symbol_table);

   parser_t parser;
   if (!parser.compile(linear_least_squares_program,expression))
   {
      printf("error: %s\n",parser.error().c_str());
      return;
   }

   expression.value();

   printf("alpha: %15.12f\n", alpha);
   printf("beta:  %15.12f\n", beta );
   printf("rmse:  %15.12f\n", rmse );
   printf("y = %15.12fx + %15.12f\n", beta, alpha);
}

// Assembly:
pushq %rbx
subq $0xb80, %rsp            # imm = 0xB80
leaq 0x12ae03(%rip), %rsi    # 0x23b105
leaq 0x40(%rsp), %rdi
leaq 0x258(%rsp), %rdx
callq 0x1102b8
leaq 0x12fd45(%rip), %rsi    # 0x240060
pushq $0xa
popq %rax
leaq 0x200(%rsp), %rdi
movq %rax, %rcx
rep  movsq (%rsi), %es:(%rdi)
leaq 0x12fd7d(%rip), %rsi    # 0x2400b0
leaq 0x1b0(%rsp), %rdi
movq %rax, %rcx
rep  movsq (%rsi), %es:(%rdi)
andq $0x0, 0x10(%rsp)
andq $0x0, 0x8(%rsp)
andq $0x0, 0x18(%rsp)
movq %rsp, %rdi
pushq $0x1
popq %rsi
callq 0x1106d0
leaq 0x12b191(%rip), %rsi    # 0x23b4f6
leaq 0x258(%rsp), %rdi
leaq 0x60(%rsp), %rdx
callq 0x1102b8
movq %rsp, %rdi
leaq 0x258(%rsp), %rsi
leaq 0x10(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1106f4
leaq 0x258(%rsp), %rdi
callq 0x10e5b8
leaq 0x12b15a(%rip), %rsi    # 0x23b4fc
leaq 0x258(%rsp), %rdi
leaq 0x60(%rsp), %rdx
callq 0x1102b8
movq %rsp, %rdi
leaq 0x258(%rsp), %rsi
leaq 0x8(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1106f4
leaq 0x258(%rsp), %rdi
callq 0x10e5b8
leaq 0x12b122(%rip), %rsi    # 0x23b501
leaq 0x258(%rsp), %rdi
leaq 0x60(%rsp), %rdx
callq 0x1102b8
movq %rsp, %rdi
leaq 0x258(%rsp), %rsi
leaq 0x18(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1106f4
leaq 0x258(%rsp), %rdi
callq 0x10e5b8
leaq 0x12ac41(%rip), %rsi    # 0x23b05d
leaq 0x258(%rsp), %rdi
leaq 0x60(%rsp), %rdx
callq 0x1102b8
movq %rsp, %rdi
leaq 0x258(%rsp), %rsi
leaq 0x200(%rsp), %rdx
callq 0x110760
leaq 0x258(%rsp), %rdi
callq 0x10e5b8
leaq 0x12b1dc(%rip), %rsi    # 0x23b636
leaq 0x258(%rsp), %rdi
leaq 0x60(%rsp), %rdx
callq 0x1102b8
movq %rsp, %rdi
leaq 0x258(%rsp), %rsi
leaq 0x1b0(%rsp), %rdx
callq 0x110760
leaq 0x258(%rsp), %rdi
callq 0x10e5b8
leaq 0x20(%rsp), %rdi
callq 0x1107c2
leaq 0x20(%rsp), %rdi
movq %rsp, %rsi
callq 0x110822
leaq 0x60(%rsp), %rdi
pushq $0x7f
popq %rsi
callq 0x11087e
leaq 0x258(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x11098e
leaq 0x60(%rsp), %rdi
callq 0x110fa6
leaq 0x258(%rsp), %rdi
leaq 0x40(%rsp), %rsi
leaq 0x20(%rsp), %rdx
callq 0x110fee
testb %al, %al
je 0x110553
movq 0x20(%rsp), %rax
movq 0x8(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
movsd 0x10(%rsp), %xmm0
leaq 0x12b009(%rip), %rdi    # 0x23b511
movb $0x1, %al
callq 0x10e060
movsd 0x8(%rsp), %xmm0
leaq 0x12b005(%rip), %rdi    # 0x23b521
movb $0x1, %al
callq 0x10e060
movsd 0x18(%rsp), %xmm0
leaq 0x12b001(%rip), %rdi    # 0x23b531
movb $0x1, %al
callq 0x10e060
movsd 0x8(%rsp), %xmm0
movsd 0x10(%rsp), %xmm1
leaq 0x12aff7(%rip), %rdi    # 0x23b541
movb $0x2, %al
callq 0x10e060
jmp 0x110583
leaq 0x60(%rsp), %rdi
leaq 0x258(%rsp), %rsi
callq 0x111470
leaq 0x60(%rsp), %rbx
movq (%rbx), %rsi
leaq 0x12af92(%rip), %rdi    # 0x23b506
xorl %eax, %eax
callq 0x10e060
movq %rbx, %rdi
callq 0x10e5b8
leaq 0x258(%rsp), %rdi
callq 0x1114c4
leaq 0x20(%rsp), %rdi
callq 0x1115fe
movq %rsp, %rdi
callq 0x111614
leaq 0x40(%rsp), %rdi
callq 0x10e5b8
addq $0xb80, %rsp            # imm = 0xB80
popq %rbx
retq
jmp 0x1105fb
movq %rax, %rbx
leaq 0x60(%rsp), %rdi
callq 0x110fa6
jmp 0x11060b
jmp 0x1105c8
movq %rax, %rbx
jmp 0x11060b
jmp 0x1105f1
jmp 0x1105df
jmp 0x1105f1
jmp 0x1105df
jmp 0x1105f1
jmp 0x1105df
jmp 0x1105f1
jmp 0x1105df
jmp 0x1105f1
movq %rax, %rbx
leaq 0x258(%rsp), %rdi
callq 0x10e5b8
jmp 0x110615
movq %rax, %rbx
jmp 0x110615
movq %rax, %rbx
jmp 0x11061d
movq %rax, %rbx
leaq 0x258(%rsp), %rdi
callq 0x1114c4
leaq 0x20(%rsp), %rdi
callq 0x1115fe
movq %rsp, %rdi
callq 0x111614
leaq 0x40(%rsp), %rdi
callq 0x10e5b8
movq %rbx, %rdi
callq 0x10e310