github.com/cowsed/Parser@v0.0.0-20211216032244-48b10019d380/parser_test.go (about) 1 package parser 2 3 import ( 4 "fmt" 5 "math" 6 "testing" 7 ) 8 9 func TestCompile(t *testing.T) { 10 expr := "2+2-5" 11 e, err := ParseExpression(expr) 12 if err != nil { 13 fmt.Println("error") 14 t.Errorf(err.Error()) 15 } 16 if e == nil { 17 t.Errorf("Unknown parse error") 18 } 19 expComp := CompileExpression(e) 20 res := expComp(map[string]float64{}) 21 if res != float64(2+2-5) { 22 t.Errorf("Had %s, expected result: %g. Actual result: %g", expr, float64(2+2-5), res) 23 } 24 } 25 func TestCompile2(t *testing.T) { 26 expr := "2+2*a" 27 e, err := ParseExpression(expr) 28 if err != nil { 29 fmt.Println("error") 30 t.Errorf(err.Error()) 31 } 32 if e == nil { 33 t.Errorf("Unknown parse error") 34 } 35 expComp := CompileExpression(e) 36 res := expComp(map[string]float64{"a": 3}) 37 if res != float64(2+2*3) { 38 t.Errorf("Had %s, expected result: %g. Actual result: %g", expr, float64(2+2*3), res) 39 } 40 } 41 func TestCompile3(t *testing.T) { 42 expr := "a+2*a" 43 e, err := ParseExpression(expr) 44 if err != nil { 45 fmt.Println("error") 46 t.Errorf(err.Error()) 47 } 48 if e == nil { 49 t.Errorf("Unknown parse error") 50 } 51 expComp := CompileExpression(e) 52 res := expComp(map[string]float64{"a": 3}) 53 if res != float64(3+2*3) { 54 t.Errorf("Had %s, expected result: %g. Actual result: %g", expr, float64(3+2*3), res) 55 } 56 } 57 58 func TestCompile5(t *testing.T) { 59 expr := "sin(x*y/b)*y+cos(a*x-y)" 60 e, err := ParseExpression(expr) 61 if err != nil { 62 fmt.Println("error") 63 t.Errorf(err.Error()) 64 } 65 if e == nil { 66 t.Errorf("Unknown parse error") 67 } 68 fmt.Println("Evaluated E: ", e.Evaluate(map[string]float64{"a": 0.65343, "b": 0.7345345, "x": 0.1, "y": 0.1})) 69 expComp := CompileExpression(e) 70 res := expComp(map[string]float64{"a": 0.65343, "b": 0.7345345, "x": 0.1, "y": 0.1}) 71 if res != float64(math.Sin(.1*.1/0.7345345)*.1+math.Cos(0.65343*.1-.1)) { 72 t.Errorf("Had %s, expected result: %g. Actual result: %g", expr, float64(math.Sin(.1*.1/0.7345345)*.1+math.Cos(0.65343*.1-.1)), res) 73 } 74 } 75 76 func TestCompile6(t *testing.T) { 77 expr := "sin(y/b)" //Something about this expression is cringe 78 e, err := ParseExpression(expr) 79 if err != nil { 80 fmt.Println("error") 81 t.Errorf(err.Error()) 82 } 83 if e == nil { 84 t.Errorf("Unknown parse error") 85 } 86 fmt.Println(e.String()) 87 fmt.Println("Evaluated E: ", e.Evaluate(map[string]float64{"a": 0.65343, "b": 0.7345345, "x": 0.1, "y": 0.1})) 88 expComp := CompileExpression(e) 89 res := expComp(map[string]float64{"a": 0.65343, "b": 0.7345345, "x": 0.1, "y": 0.1}) 90 if res != float64(math.Sin(.1/0.7345345)) { 91 t.Errorf("Had %s, expected result: %g. Actual result: %g", expr, float64(math.Sin(.1/0.7345345)), res) 92 } 93 } 94 95 func TestCompile7(t *testing.T) { 96 expr := "cos(a*x-y)" 97 e, err := ParseExpression(expr) 98 if err != nil { 99 fmt.Println("error") 100 t.Errorf(err.Error()) 101 } 102 if e == nil { 103 t.Errorf("Unknown parse error") 104 } 105 fmt.Println("Evaluated E: ", e.Evaluate(map[string]float64{"a": 0.65343, "b": 0.7345345, "x": 0.1, "y": 0.1})) 106 expComp := CompileExpression(e) 107 res := expComp(map[string]float64{"a": 0.65343, "b": 0.7345345, "x": 0.1, "y": 0.1}) 108 if res != float64(math.Cos(0.65343*.1-.1)) { 109 t.Errorf("Had %s, expected result: %g. Actual result: %g", expr, float64(math.Cos(0.65343*.1-.1)), res) 110 } 111 } 112 113 func TestParse(t *testing.T) { 114 expr := "2+2-3" 115 e, err := ParseExpression(expr) 116 if err != nil { 117 fmt.Println("error") 118 t.Errorf(err.Error()) 119 } 120 if e == nil { 121 t.Errorf("Unknown parse error") 122 } 123 fmt.Println(e.String()) 124 res := e.Evaluate(map[string]float64{}) 125 if res != float64(2+2-3) { 126 t.Errorf("Had %s, expected result: %g. Actual result: %g", expr, float64(2+2-3), res) 127 } 128 } 129 130 func TestParse2(t *testing.T) { 131 expr := "2+2-3*4/2" 132 e, err := ParseExpression(expr) 133 if err != nil { 134 fmt.Println("error") 135 t.Errorf(err.Error()) 136 } 137 if e == nil { 138 t.Errorf("Unknown parse error") 139 } 140 fmt.Println(e.String()) 141 res := e.Evaluate(map[string]float64{}) 142 if res != float64(2+2-3*4/2) { 143 t.Errorf("Had %s parsed to %s, expected result: %g. Actual result: %g", expr, e.String(), float64(2+2-3*4/2), res) 144 } 145 } 146 func TestParse3(t *testing.T) { 147 expr := "3^4" 148 e, err := ParseExpression(expr) 149 if err != nil { 150 fmt.Println("error") 151 t.Errorf(err.Error()) 152 } 153 if e == nil { 154 t.Errorf("Unknown parse error") 155 } 156 fmt.Println(e.String()) 157 res := e.Evaluate(map[string]float64{}) 158 if res != float64(math.Pow(3, 4)) { 159 t.Errorf("Had %s parsed to %s, expected result: %g. Actual result: %g", expr, e.String(), math.Pow(3, 4), res) 160 } 161 } 162 163 func TestParse4(t *testing.T) { 164 expr := "a+x^2" 165 e, err := ParseExpression(expr) 166 if err != nil { 167 fmt.Println("error") 168 t.Errorf(err.Error()) 169 } 170 if e == nil { 171 t.Errorf("Unknown parse error") 172 } 173 fmt.Println(e.String()) 174 res := e.Evaluate(map[string]float64{"x": 3, "a": 2}) 175 if res != float64(2+(3*3)) { 176 t.Errorf("Had %s parsed to %s, expected result: %g. Actual result: %g", expr, e.String(), float64(2+(3*3)), res) 177 } 178 } 179 func TestParse5(t *testing.T) { 180 expr := "a*3+1/2+a+x^(a+2)+1" 181 e, err := ParseExpression(expr) 182 if err != nil { 183 fmt.Println("error") 184 t.Errorf(err.Error()) 185 } 186 if e == nil { 187 t.Errorf("parse error") 188 } 189 fmt.Println("Latex", e.Latex()) 190 res := e.Evaluate(map[string]float64{"x": 3, "a": 2}) 191 if res != float64(2*3+1.0/2.0+2+math.Pow(3, 2+2)+1) { 192 t.Errorf("Had %s parsed to %s, expected result: %g. Actual result: %g", expr, e.String(), float64(2*3+1.0/2.0+2+math.Pow(3, 2+2)+1), res) 193 } 194 } 195 196 func TestParse6(t *testing.T) { 197 expr := "2+3*sin(x)" 198 e, err := ParseExpression(expr) 199 if err != nil { 200 fmt.Println("error") 201 t.Errorf(err.Error()) 202 } 203 if e == nil { 204 t.Errorf("parse error") 205 } 206 fmt.Println("Latex", e.Latex()) 207 fmt.Println("String", e.String()) 208 209 res := e.Evaluate(map[string]float64{"x": 0}) 210 if res != float64(2+3*math.Sin(0)) { 211 t.Errorf("Had %s parsed to %s, expected result: %g. Actual result: %g", expr, e.String(), float64(2+3*math.Sin(0)), res) 212 } 213 } 214 215 type QnA struct { 216 q string 217 a float64 218 } 219 220 func TestEvaluateN(t *testing.T) { 221 tests := []QnA{ 222 {"2+2", 4}, 223 {"2*3", 6}, 224 {"3-2", 1}, 225 {"3*2+cos(0)", 7}, 226 {"3+cos(0)", 4}, 227 {"3+sin(0)", 3}, 228 229 {"3/2", 1.5}, 230 {"3^2", 9}, 231 {"(9-x^2)^.5", 5}, 232 } 233 for i := range tests { 234 e, err := ParseExpression(tests[i].q) 235 if err != nil { 236 t.Error(err) 237 } 238 if e.Evaluate(map[string]float64{"x": -2}) != tests[i].a { 239 t.Errorf("%s should = %g but evaluated to %g. Parsed to %s", tests[i].q, tests[i].a, e.Evaluate(map[string]float64{"x": -2}), e.Simplify().String()) 240 } 241 } 242 } 243 244 type IntegrateQnA struct { 245 exp string 246 wrt string 247 from, to float64 248 expected float64 249 numBuckets int 250 } 251 252 func TestIntegrateN(t *testing.T) { 253 epsilon := 0.001 254 tests := []IntegrateQnA{ 255 {"2", "x", 0, 4, 8, 1}, 256 {"x", "x", 0, 4, 8, 1}, 257 {"x^2", "x", 0, 4, 64.0 / 3.0, 10000}, 258 {"sin(x)", "x", 0, 4, 1.6536, 100}, 259 //https://tutorial.math.lamar.edu/classes/calcii/surfacearea.aspx 260 {"2*3.14159*((9-x^2)^.5)*(3/((9-x^2)^.5)", "x", -2, 2, 24 * math.Pi, 100}, 261 } 262 //* 263 for i := range tests { 264 e, err := ParseExpression(tests[i].exp) 265 if err != nil { 266 t.Error(err) 267 } 268 fmt.Println("Finished parsing", e.String()) 269 270 test := tests[i] 271 res := IntegrateV(e, map[string]float64{}, test.wrt, test.from, test.to, test.numBuckets) 272 if math.Abs(res-test.expected) > epsilon || math.IsNaN(res) { 273 fmt.Println(res-test.expected, epsilon) 274 t.Errorf("%s from %g to %g wrt %s should = %g but was %g. Parsed to %s", test.exp, test.from, test.to, test.wrt, test.expected, res, e.String()) 275 } 276 } 277 } 278 279 func TestParseToPostfix(t *testing.T) { 280 expr := "3*4+2" 281 tokens, err := tokenize(expr) 282 if err != nil { 283 t.Errorf(err.Error()) 284 } 285 pf, err := makePostFix(tokens) 286 if err != nil { 287 t.Errorf(err.Error()) 288 } 289 fmt.Println(pf) 290 wanted := []Token{ 291 { 292 Type: NumberType, 293 Value: "3", 294 }, 295 { 296 Type: NumberType, 297 Value: "4", 298 }, 299 { 300 Type: OperatorType, 301 Value: "*", 302 }, 303 { 304 Type: NumberType, 305 Value: "2", 306 }, 307 { 308 Type: OperatorType, 309 Value: "+", 310 }, 311 } 312 for i := 0; i < len(pf); i++ { 313 if pf[i] != wanted[i] { 314 t.Errorf("Wanted %v, got %v at index %d", wanted[i], pf[i], i) 315 } 316 } 317 318 } 319 320 func TestPostfix(t *testing.T) { 321 tokens := []Token{ 322 { 323 Type: NumberType, 324 Value: "2", 325 }, 326 { 327 Type: OperatorType, 328 Value: "+", 329 }, 330 { 331 Type: NumberType, 332 Value: "2", 333 }, 334 } 335 pf, err := makePostFix(tokens) 336 if err != nil { 337 t.Errorf(err.Error()) 338 } 339 wanted := []Token{ 340 { 341 Type: NumberType, 342 Value: "2", 343 }, 344 { 345 Type: NumberType, 346 Value: "2", 347 }, 348 { 349 Type: OperatorType, 350 Value: "+", 351 }, 352 } 353 fmt.Println("Infix", tokens) 354 fmt.Println("Postfix", pf) 355 for i := 0; i < len(pf); i++ { 356 if pf[i] != wanted[i] { 357 t.Errorf("Wanted %v, got %v at index %d", wanted[i], pf[i], i) 358 } 359 } 360 } 361 362 func TestStack(t *testing.T) { 363 s := NewTokenStack() 364 s.Push(Token{ 365 Type: NumberType, 366 Value: "2", 367 }) 368 s.Push(Token{ 369 Type: NumberType, 370 Value: "2", 371 }) 372 s.Push(Token{ 373 Type: OperatorType, 374 Value: "+", 375 }) 376 377 a, _ := s.Pop() 378 b, _ := s.Pop() 379 c, _ := s.Pop() 380 fmt.Println(a, b, c, "outputs") 381 d, err := s.Pop() 382 if err != nil { 383 fmt.Println(d) 384 } else { 385 fmt.Println("popped off the end") 386 } 387 } 388 389 func TestTokenize(t *testing.T) { 390 got, err := tokenize("aa*x^2-bx+c") 391 fmt.Println(got, err) 392 } 393 394 func TestTokenize2(t *testing.T) { 395 ts, err := tokenize("2+3*cos(3)") 396 if err != nil { 397 t.Errorf(err.Error()) 398 } 399 fmt.Println(ts) 400 } 401 402 func TestSimplify1(t *testing.T) { 403 e, err := ParseExpression("0*ln(x)") 404 if err != nil { 405 t.Error(err) 406 } 407 if e.Simplify().String() != "0" { 408 t.Errorf("Wanted %s, got %s", "0", e.Simplify().String()) 409 } 410 } 411 func TestSimplify2(t *testing.T) { 412 e, err := ParseExpression("2+0*ln(x)") 413 if err != nil { 414 t.Error(err) 415 } 416 fmt.Printf("e: %v\n", e) 417 if e.Simplify().String() != "2" { 418 t.Errorf("Wanted %s, got %s", "2", e.Simplify().String()) 419 } 420 } 421 func TestSimplify3(t *testing.T) { 422 423 e, err := ParseExpression("2*x*x") 424 if err != nil { 425 t.Error(err) 426 } 427 fmt.Printf("e: %v\n", e) 428 fmt.Printf("e.Simplify(): %v\n", e.Simplify()) 429 s := e.Simplify() 430 if e.Simplify().String() != "(2 * (x ^ 2))" { 431 t.Errorf("Wanted %s, got %s", "(2 * (x ^ 2))", e.Simplify().String()) 432 } 433 fmt.Println("WOWW", s) 434 } 435 436 func TestSimplify4(t *testing.T) { 437 438 e, err := ParseExpression("2*x*b*b*x") 439 if err != nil { 440 t.Error(err) 441 } 442 fmt.Printf("e: %v\n", e) 443 if e.Simplify().String() != "(2 * ((x ^ 2) * (b ^ 2)))" { 444 t.Errorf("Wanted %s, got %s", " (2 * ((x ^ 2) * (b ^ 2)))", e.Simplify().String()) 445 } 446 } 447 func TestSimplify5(t *testing.T) { 448 449 e, err := ParseExpression("(x+1)*(x+1)") 450 if err != nil { 451 t.Error(err) 452 } 453 fmt.Printf("e: %v\n", e) 454 if e.Simplify().Simplify().String() != "((x + 1) ^ 2)" { 455 t.Errorf("Wanted %s, got %s", "((x + 1) ^ 2))", e.Simplify().Simplify().String()) 456 } 457 } 458 459 func TestSimplifyN(t *testing.T) { 460 tests := [][2]string{ 461 {"2+2", "4"}, 462 {"(x+1) * (x+1)", "((x + 1) ^ 2)"}, 463 {"x*x*x*x", "(x ^ 4)"}, 464 {"2/2", "1"}, 465 {"0/x", "0"}, 466 {"0/2", "0"}, 467 {"x*0*2", "0"}, 468 {"2*(2/1)", "4"}, 469 {"(2*2)/1", "4"}, 470 {"(2*2)/(3*3)", fmt.Sprint(4.0 / 9.0)}, 471 472 {"3^(x+2+3)", "(3 ^ (x + 5))"}, 473 474 {"x/x", "1"}, 475 {"x/x*x", "x"}, 476 {"x*x*x/x", "(x ^ 2)"}, 477 {"x/x*x/x", "1"}, 478 } 479 //{"x/x", "1"}, 480 481 for i := range tests { 482 e, err := ParseExpression(tests[i][0]) 483 if err != nil { 484 t.Error(err) 485 } 486 //fmt.Printf("%s Simplifies to %s\n", tests[i][0], tests[i][1]) 487 if e.Simplify().String() != tests[i][1] { 488 t.Errorf("%s should simplify to %s but simplified to %s", tests[i][0], tests[i][1], e.Simplify().String()) 489 } 490 } 491 } 492 493 func TestCountMuls(t *testing.T) { 494 e, _ := ParseExpression("x+x/x") 495 fmt.Println("Expression,", e) 496 n, d := ListMuls(e, true) 497 fmt.Println(n, d) 498 fmt.Printf("SimplifyFraction(n, d): %v\n", SimplifyFraction(n, d)) 499 } 500 501 func TestDerivative1(t *testing.T) { 502 e, err := ParseExpression("x^2") 503 if err != nil { 504 t.Errorf(err.Error()) 505 } 506 derivative := e.Derive("x") 507 //derivative = derivative.Simplify() 508 res := derivative.Evaluate(map[string]float64{"x": 4}) 509 fmt.Println(res) 510 fmt.Println("Derivative", derivative.String()) 511 fmt.Printf("Wanted %s=%g. got %s = %g", "2 * x", 8.0, derivative.String(), res) 512 513 if res != 8 { 514 t.Errorf("Wanted %s=%g. got %s = %g", "2 * x", 8.0, derivative.String(), res) 515 } 516 } 517 518 func TestDerivative2(t *testing.T) { 519 e, err := ParseExpression("x^3") 520 if err != nil { 521 t.Errorf(err.Error()) 522 } 523 derivative := e.Derive("x") 524 res := derivative.Evaluate(map[string]float64{"x": 4}) 525 fmt.Println(res) 526 fmt.Println(derivative.String()) 527 if res != 16*3 { 528 t.Errorf("Wanted %s=%g. got %s=%g", "3 * x ^ 2", 48.0, derivative.String(), res) 529 } 530 } 531 532 type DerivQnA struct { 533 e string 534 testNum, ans float64 535 } 536 537 func TestDerivativeN(t *testing.T) { 538 tests := []DerivQnA{{ 539 e: "2*x^2", 540 testNum: 1, 541 ans: 4, 542 }, 543 { 544 e: "9-x", 545 testNum: 1, 546 ans: -1, 547 }, 548 { 549 e: "(9-x)^2", 550 testNum: 9, 551 ans: 0, 552 }, 553 } 554 for i := range tests { 555 e, err := ParseExpression(tests[i].e) 556 if err != nil { 557 t.Error(err) 558 } 559 test := tests[i] 560 d := e.Derive("x") 561 res := d.Evaluate(map[string]float64{"x": tests[i].testNum}) 562 if res != tests[i].ans { 563 t.Errorf("Expected (%g,%g). got (%g,%g). Derivative is %s", test.testNum, test.ans, test.testNum, res, d.String()) 564 } 565 } 566 } 567 568 // ================ Benchmarks ================ 569 570 var result float64 //https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go compiler optimization sections 571 572 func BenchmarkExpressionEvaluate(b *testing.B) { 573 //Parse the expression 574 expr := "2+2*5+3*5+2*5+3*72" 575 e, _ := ParseExpression(expr) 576 var r float64 577 // evaluate the expression N times 578 for n := 0; n < b.N; n++ { 579 r = e.Evaluate(map[string]float64{}) 580 } 581 result = r 582 } 583 584 func BenchmarkExpressionCompiled(b *testing.B) { 585 //Parse the expression 586 expr := "2+2*5+3*5+2*5+3*72" 587 e, _ := ParseExpression(expr) 588 f := CompileExpression(e) 589 590 var r float64 591 // evaluate the expression N times 592 for n := 0; n < b.N; n++ { 593 r = f(map[string]float64{}) 594 } 595 result = r 596 } 597 func BenchmarkExpressionNative(b *testing.B) { 598 //Parse the expression 599 //expr := "2+2*5+3*5+2*5+3*72" 600 e := func(a, b, c, d float64) float64 { return a + a*c + c*c + a*c + b*d } 601 var r float64 602 // evaluate the expression N times 603 for n := 0; n < b.N; n++ { 604 r = e(2, 3, 5, 72) 605 } 606 result = r 607 } 608 609 func BenchmarkExpressionJIT(b *testing.B) { 610 ////Parse the expression 611 //expr := "2+2+3+4" 612 //e, _ := ParseExpression(expr) 613 //f := JitCompileExpression(e) 614 //var r float64 615 //// evaluate the expression N times 616 //for n := 0; n < b.N; n++ { 617 // r = f(map[string]float64{}) 618 //} 619 //result = r 620 } 621 622 //Segmentation and or nil pointer dereference 623 //something to do with way executablePrintFunc is made? 624 //Maybe with way it is copied over 625 //Maybe the way it is compiled but i doubt that a bit 626 627 func TestExpressionJIT(t *testing.T) { 628 mathFunction2 := []uint8{ 629 //Setup stuff 630 0x48, 0x83, 0xec, 0x18, 0x48, 0x89, 0x6c, 0x24, 0x10, 0x48, 0x8d, 0x6c, 0x24, 0x10, 0x48, 0x89, 631 0x44, 0x24, 0x20, 0x48, 0x85, 0xdb, 0x76, 0x43, 632 633 //data[3]+data[0]+data[1] 634 0xf2, 0x0f, 0x10, 0x00, //MOVESD 635 636 //Returning stuff 637 0x48, 0x8b, 0x6c, 0x24, 0x10, 638 0x48, 0x83, 0xc4, 0x18, 0x90, 0xc3, 0xb8, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0xd9, 0xe8, 639 } 640 data := []float64{1, 2, 3, -8008, -8008} 641 642 f := MakeMathFunc(mathFunction2) 643 644 res := f(data) 645 fmt.Println(res) 646 //Parse the expression 647 //expr := "2+2+3+4" 648 //e, err := ParseExpression(expr) 649 //fmt.Println(e.String()) 650 //if err != nil { 651 // t.Errorf(err.Error()) 652 // return 653 //} 654 //f := JitCompileExpression(e) 655 //var r = f(map[string]float64{"a": 1}) 656 //if r != float64(2+2+3+4) { 657 // t.Errorf("Had 2+2+3+4. Wanted %g, got %g", float64(2+2+3+4), r) 658 //} 659 }