// File: 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:
subq $0xcb8, %rsp            # imm = 0xCB8
leaq 0xc97(%rsp), %rdi
movq %rdi, 0x30(%rsp)
callq 0x111650
movq 0x30(%rsp), %rdx
leaq 0x330d10(%rip), %rsi    # 0x449545
leaq 0xc98(%rsp), %rdi
callq 0x118750
jmp 0x118844
leaq 0xc97(%rsp), %rdi
callq 0x111770
movaps 0x335ca8(%rip), %xmm0   # 0x44e500
movaps %xmm0, 0xc70(%rsp)
movaps 0x335c89(%rip), %xmm0   # 0x44e4f0
movaps %xmm0, 0xc60(%rsp)
movaps 0x335c6a(%rip), %xmm0   # 0x44e4e0
movaps %xmm0, 0xc50(%rsp)
movaps 0x335c4b(%rip), %xmm0   # 0x44e4d0
movaps %xmm0, 0xc40(%rsp)
movaps 0x335c2c(%rip), %xmm0   # 0x44e4c0
movaps %xmm0, 0xc30(%rsp)
movaps 0x335cad(%rip), %xmm0   # 0x44e550
movaps %xmm0, 0xc20(%rsp)
movaps 0x335c8e(%rip), %xmm0   # 0x44e540
movaps %xmm0, 0xc10(%rsp)
movaps 0x335c6f(%rip), %xmm0   # 0x44e530
movaps %xmm0, 0xc00(%rsp)
movaps 0x335c50(%rip), %xmm0   # 0x44e520
movaps %xmm0, 0xbf0(%rsp)
movaps 0x335c31(%rip), %xmm0   # 0x44e510
movaps %xmm0, 0xbe0(%rsp)
movq $0x0, 0xbd8(%rsp)
movq $0x0, 0xbd0(%rsp)
movq $0x0, 0xbc8(%rsp)
leaq 0xbc0(%rsp), %rdi
movl $0x1, %esi
callq 0x1191d0
jmp 0x11891f
leaq 0xb9f(%rsp), %rdi
movq %rdi, 0x28(%rsp)
callq 0x111650
movq 0x28(%rsp), %rdx
leaq 0x330ff9(%rip), %rsi    # 0x449936
leaq 0xba0(%rsp), %rdi
callq 0x118750
jmp 0x11894c
leaq 0xbc0(%rsp), %rdi
leaq 0xba0(%rsp), %rsi
leaq 0xbd8(%rsp), %rdx
xorl %ecx, %ecx
callq 0x119210
jmp 0x11896d
leaq 0xba0(%rsp), %rdi
callq 0x111788
leaq 0xb9f(%rsp), %rdi
callq 0x111770
leaq 0xb77(%rsp), %rdi
movq %rdi, 0x20(%rsp)
callq 0x111650
movq 0x20(%rsp), %rdx
leaq 0x330f97(%rip), %rsi    # 0x44993c
leaq 0xb78(%rsp), %rdi
callq 0x118750
jmp 0x1189b4
leaq 0xbc0(%rsp), %rdi
leaq 0xb78(%rsp), %rsi
leaq 0xbd0(%rsp), %rdx
xorl %ecx, %ecx
callq 0x119210
jmp 0x1189d5
leaq 0xb78(%rsp), %rdi
callq 0x111788
leaq 0xb77(%rsp), %rdi
callq 0x111770
leaq 0xb4f(%rsp), %rdi
movq %rdi, 0x18(%rsp)
callq 0x111650
movq 0x18(%rsp), %rdx
leaq 0x330f34(%rip), %rsi    # 0x449941
leaq 0xb50(%rsp), %rdi
callq 0x118750
jmp 0x118a1c
leaq 0xbc0(%rsp), %rdi
leaq 0xb50(%rsp), %rsi
leaq 0xbc8(%rsp), %rdx
xorl %ecx, %ecx
callq 0x119210
jmp 0x118a3d
leaq 0xb50(%rsp), %rdi
callq 0x111788
leaq 0xb4f(%rsp), %rdi
callq 0x111770
leaq 0xb27(%rsp), %rdi
movq %rdi, 0x10(%rsp)
callq 0x111650
movq 0x10(%rsp), %rdx
leaq 0x330a28(%rip), %rsi    # 0x44949d
leaq 0xb28(%rsp), %rdi
callq 0x118750
jmp 0x118a84
leaq 0xbc0(%rsp), %rdi
leaq 0xb28(%rsp), %rsi
leaq 0xc30(%rsp), %rdx
callq 0x1192c0
jmp 0x118aa3
leaq 0xb28(%rsp), %rdi
callq 0x111788
leaq 0xb27(%rsp), %rdi
callq 0x111770
leaq 0xaff(%rsp), %rdi
movq %rdi, 0x8(%rsp)
callq 0x111650
movq 0x8(%rsp), %rdx
leaq 0x330e6b(%rip), %rsi    # 0x449946
leaq 0xb00(%rsp), %rdi
callq 0x118750
jmp 0x118aea
leaq 0xbc0(%rsp), %rdi
leaq 0xb00(%rsp), %rsi
leaq 0xbe0(%rsp), %rdx
callq 0x1192c0
jmp 0x118b09
leaq 0xb00(%rsp), %rdi
callq 0x111788
leaq 0xaff(%rsp), %rdi
callq 0x111770
leaq 0xad8(%rsp), %rdi
callq 0x119360
jmp 0x118b32
leaq 0xad8(%rsp), %rdi
leaq 0xbc0(%rsp), %rsi
callq 0x119410
jmp 0x118b49
leaq 0x60(%rsp), %rdi
movl $0x7f, %esi
callq 0x1194c0
jmp 0x118b5a
leaq 0x1b0(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x1195f0
jmp 0x118b6e
leaq 0x60(%rsp), %rdi
callq 0x119e20
leaq 0x1b0(%rsp), %rdi
leaq 0xc98(%rsp), %rsi
leaq 0xad8(%rsp), %rdx
callq 0x119e90
movb %al, 0x7(%rsp)
jmp 0x118b9b
movb 0x7(%rsp), %al
testb $0x1, %al
jne 0x118e2e
jmp 0x118ba9
leaq 0x40(%rsp), %rdi
leaq 0x1b0(%rsp), %rsi
callq 0x11a720
jmp 0x118bbd
leaq 0x40(%rsp), %rdi
callq 0x1110f0
movq %rax, %rsi
leaq 0x330d77(%rip), %rdi    # 0x449948
xorl %eax, %eax
callq 0x111080
jmp 0x118bda
leaq 0x40(%rsp), %rdi
callq 0x111788
movl $0x1, 0x3c(%rsp)
jmp 0x118eb2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xc97(%rsp), %rdi
callq 0x111770
jmp 0x118f22
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118f15
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118c67
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xba0(%rsp), %rdi
callq 0x111788
leaq 0xb9f(%rsp), %rdi
callq 0x111770
jmp 0x118f08
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118cb0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xb78(%rsp), %rdi
callq 0x111788
leaq 0xb77(%rsp), %rdi
callq 0x111770
jmp 0x118f08
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118cf9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xb50(%rsp), %rdi
callq 0x111788
leaq 0xb4f(%rsp), %rdi
callq 0x111770
jmp 0x118f08
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118d42
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xb28(%rsp), %rdi
callq 0x111788
leaq 0xb27(%rsp), %rdi
callq 0x111770
jmp 0x118f08
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118d8b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xb00(%rsp), %rdi
callq 0x111788
leaq 0xaff(%rsp), %rdi
callq 0x111770
jmp 0x118f08
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118f08
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118efb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0x60(%rsp), %rdi
callq 0x119e20
jmp 0x118efb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118eee
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0x40(%rsp), %rdi
callq 0x111788
jmp 0x118eee
leaq 0xad8(%rsp), %rdi
callq 0x11a7e0
jmp 0x118e3d
movsd 0xbd8(%rsp), %xmm0
leaq 0x330b06(%rip), %rdi    # 0x449953
movb $0x1, %al
callq 0x111080
jmp 0x118e56
movsd 0xbd0(%rsp), %xmm0
leaq 0x330afd(%rip), %rdi    # 0x449963
movb $0x1, %al
callq 0x111080
jmp 0x118e6f
movsd 0xbc8(%rsp), %xmm0
leaq 0x330af4(%rip), %rdi    # 0x449973
movb $0x1, %al
callq 0x111080
jmp 0x118e88
movsd 0xbd0(%rsp), %xmm0
movsd 0xbd8(%rsp), %xmm1
leaq 0x330ae2(%rip), %rdi    # 0x449983
movb $0x2, %al
callq 0x111080
jmp 0x118eaa
movl $0x0, 0x3c(%rsp)
leaq 0x1b0(%rsp), %rdi
callq 0x11a800
leaq 0xad8(%rsp), %rdi
callq 0x11aa00
leaq 0xbc0(%rsp), %rdi
callq 0x11aa40
leaq 0xc98(%rsp), %rdi
callq 0x111788
addq $0xcb8, %rsp            # imm = 0xCB8
retq
leaq 0x1b0(%rsp), %rdi
callq 0x11a800
leaq 0xad8(%rsp), %rdi
callq 0x11aa00
leaq 0xbc0(%rsp), %rdi
callq 0x11aa40
leaq 0xc98(%rsp), %rdi
callq 0x111788
movq 0xc88(%rsp), %rdi
callq 0x111450
nop