Add files with expressions, parser, Nikuradse dataset and a new test case.
This commit is contained in:
parent
6ab826cc42
commit
293c5f13a4
|
@ -5,12 +5,16 @@ version = "1.0.0-DEV"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
|
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
|
||||||
|
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
|
||||||
|
GZip = "92fee26a-97fe-5a0c-ad85-20a5f3185b63"
|
||||||
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
|
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
|
||||||
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
|
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
|
||||||
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||||
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
|
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
|
||||||
|
|
||||||
[compat]
|
[compat]
|
||||||
|
DelimitedFiles = "1.9.1"
|
||||||
|
GZip = "0.6.2"
|
||||||
LinearAlgebra = "1.11.0"
|
LinearAlgebra = "1.11.0"
|
||||||
Printf = "1.11.0"
|
Printf = "1.11.0"
|
||||||
Random = "1.11.0"
|
Random = "1.11.0"
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
using LinearAlgebra
|
using LinearAlgebra
|
||||||
using BenchmarkTools
|
using BenchmarkTools
|
||||||
|
using DelimitedFiles
|
||||||
|
using GZip
|
||||||
|
|
||||||
|
include("parser.jl") # to parse expressions from a file
|
||||||
|
|
||||||
function test_cpu_interpreter(nrows; parallel = false)
|
function test_cpu_interpreter(nrows; parallel = false)
|
||||||
exprs = [
|
exprs = [
|
||||||
|
@ -45,3 +49,27 @@ end
|
||||||
@test test_cpu_interpreter(1000, parallel=true) # start julia -t 6 for six threads
|
@test test_cpu_interpreter(1000, parallel=true) # start julia -t 6 for six threads
|
||||||
@test test_cpu_interpreter(10000)
|
@test test_cpu_interpreter(10000)
|
||||||
@test test_cpu_interpreter(10000, parallel=true)
|
@test test_cpu_interpreter(10000, parallel=true)
|
||||||
|
|
||||||
|
|
||||||
|
function test_cpu_interpreter_nikuradse()
|
||||||
|
data,varnames = readdlm("data/nikuradse_1.csv", ',', header=true);
|
||||||
|
X = convert(Matrix{Float32}, data)
|
||||||
|
|
||||||
|
exprs = Expr[]
|
||||||
|
parameters = Vector{Vector{Float32}}()
|
||||||
|
varnames = ["x$i" for i in 1:10]
|
||||||
|
paramnames = ["p$i" for i in 1:20]
|
||||||
|
# data/esr_nvar2_len10.txt.gz_9.txt.gz has ~250_000 exprs
|
||||||
|
# data/esr_nvar2_len10.txt.gz_10.txt.gz has ~800_000 exrps
|
||||||
|
GZip.open("data/esr_nvar2_len10.txt.gz_9.txt.gz") do io
|
||||||
|
for line in eachline(io)
|
||||||
|
expr, p = parse_infix(line, varnames, paramnames)
|
||||||
|
|
||||||
|
push!(exprs, expr)
|
||||||
|
push!(parameters, randn(Float32, length(p)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
interpret_cpu(exprs, X, parameters) # TODO: sufficient to do up to 10 repetitions per expression,
|
||||||
|
end
|
BIN
package/test/data/esr_nvar2_len10.txt.gz_1.txt.gz
Normal file
BIN
package/test/data/esr_nvar2_len10.txt.gz_1.txt.gz
Normal file
Binary file not shown.
BIN
package/test/data/esr_nvar2_len10.txt.gz_10.txt.gz
Normal file
BIN
package/test/data/esr_nvar2_len10.txt.gz_10.txt.gz
Normal file
Binary file not shown.
BIN
package/test/data/esr_nvar2_len10.txt.gz_2.txt.gz
Normal file
BIN
package/test/data/esr_nvar2_len10.txt.gz_2.txt.gz
Normal file
Binary file not shown.
BIN
package/test/data/esr_nvar2_len10.txt.gz_3.txt.gz
Normal file
BIN
package/test/data/esr_nvar2_len10.txt.gz_3.txt.gz
Normal file
Binary file not shown.
BIN
package/test/data/esr_nvar2_len10.txt.gz_4.txt.gz
Normal file
BIN
package/test/data/esr_nvar2_len10.txt.gz_4.txt.gz
Normal file
Binary file not shown.
BIN
package/test/data/esr_nvar2_len10.txt.gz_5.txt.gz
Normal file
BIN
package/test/data/esr_nvar2_len10.txt.gz_5.txt.gz
Normal file
Binary file not shown.
BIN
package/test/data/esr_nvar2_len10.txt.gz_6.txt.gz
Normal file
BIN
package/test/data/esr_nvar2_len10.txt.gz_6.txt.gz
Normal file
Binary file not shown.
BIN
package/test/data/esr_nvar2_len10.txt.gz_7.txt.gz
Normal file
BIN
package/test/data/esr_nvar2_len10.txt.gz_7.txt.gz
Normal file
Binary file not shown.
BIN
package/test/data/esr_nvar2_len10.txt.gz_8.txt.gz
Normal file
BIN
package/test/data/esr_nvar2_len10.txt.gz_8.txt.gz
Normal file
Binary file not shown.
BIN
package/test/data/esr_nvar2_len10.txt.gz_9.txt.gz
Normal file
BIN
package/test/data/esr_nvar2_len10.txt.gz_9.txt.gz
Normal file
Binary file not shown.
363
package/test/data/nikuradse_1.csv
Normal file
363
package/test/data/nikuradse_1.csv
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
r_k,log_Re,target
|
||||||
|
507,4.114,0.456
|
||||||
|
507,4.23,0.438
|
||||||
|
507,4.322,0.417
|
||||||
|
507,4.362,0.407
|
||||||
|
507,4.362,0.403
|
||||||
|
507,4.462,0.381
|
||||||
|
507,4.491,0.38
|
||||||
|
507,4.532,0.366
|
||||||
|
507,4.568,0.365
|
||||||
|
507,4.591,0.356
|
||||||
|
507,4.623,0.347
|
||||||
|
507,4.672,0.333
|
||||||
|
507,4.69,0.324
|
||||||
|
507,4.716,0.32
|
||||||
|
507,4.763,0.307
|
||||||
|
507,4.806,0.303
|
||||||
|
507,4.851,0.292
|
||||||
|
507,4.898,0.286
|
||||||
|
507,4.94,0.278
|
||||||
|
507,4.973,0.274
|
||||||
|
507,5.009,0.274
|
||||||
|
507,5.025,0.272
|
||||||
|
507,5.049,0.27
|
||||||
|
507,5.1,0.262
|
||||||
|
507,5.143,0.26
|
||||||
|
507,5.199,0.255
|
||||||
|
507,5.236,0.253
|
||||||
|
507,5.27,0.255
|
||||||
|
507,5.281,0.253
|
||||||
|
507,5.303,0.25
|
||||||
|
507,5.326,0.252
|
||||||
|
507,5.377,0.255
|
||||||
|
507,5.43,0.253
|
||||||
|
507,5.493,0.258
|
||||||
|
507,5.534,0.26
|
||||||
|
507,5.574,0.262
|
||||||
|
507,5.608,0.29
|
||||||
|
507,5.63,0.272
|
||||||
|
507,5.668,0.272
|
||||||
|
507,5.709,0.272
|
||||||
|
507,5.756,0.278
|
||||||
|
507,5.792,0.279
|
||||||
|
507,5.833,0.283
|
||||||
|
507,5.94,0.286
|
||||||
|
507,5.965,0.288
|
||||||
|
507,5.929,0.289
|
||||||
|
507,5.954,0.288
|
||||||
|
507,5.987,0.286
|
||||||
|
252,4.21,0.4506
|
||||||
|
252,4.279,0.4349
|
||||||
|
252,4.465,0.3808
|
||||||
|
252,4.507,0.3636
|
||||||
|
252,4.549,0.3579
|
||||||
|
252,4.597,0.3562
|
||||||
|
252,4.644,0.3434
|
||||||
|
252,4.778,0.3257
|
||||||
|
252,4.82,0.3282
|
||||||
|
252,4.916,0.3222
|
||||||
|
252,4.987,0.3197
|
||||||
|
252,5.057,0.321
|
||||||
|
252,5.1,0.3228
|
||||||
|
252,5.173,0.3197
|
||||||
|
252,5.21,0.3276
|
||||||
|
252,5.283,0.3322
|
||||||
|
252,5.366,0.3416
|
||||||
|
252,5.494,0.3504
|
||||||
|
252,5.58,0.3562
|
||||||
|
252,5.623,0.3602
|
||||||
|
252,5.702,0.3636
|
||||||
|
252,4.708,0.3371
|
||||||
|
252,5.305,0.3328
|
||||||
|
252,5.544,0.3562
|
||||||
|
252,5.787,0.3661
|
||||||
|
252,4.748,0.3335
|
||||||
|
252,4.869,0.3228
|
||||||
|
252,4.954,0.321
|
||||||
|
252,5.134,0.321
|
||||||
|
252,5.255,0.3294
|
||||||
|
252,5.415,0.3434
|
||||||
|
252,5.58,0.3551
|
||||||
|
252,5.748,0.3608
|
||||||
|
252,5.845,0.3666
|
||||||
|
252,5.881,0.3688
|
||||||
|
252,5.924,0.3727
|
||||||
|
252,5.967,0.3705
|
||||||
|
252,5.991,0.3716
|
||||||
|
60,3.653,0.593
|
||||||
|
60,3.7,0.577
|
||||||
|
60,3.74,0.571
|
||||||
|
60,3.785,0.56
|
||||||
|
60,3.851,0.544
|
||||||
|
60,3.869,0.531
|
||||||
|
60,3.909,0.512
|
||||||
|
60,3.949,0.512
|
||||||
|
60,3.996,0.507
|
||||||
|
60,4.057,0.494
|
||||||
|
60,4.09,0.49
|
||||||
|
60,4.161,0.494
|
||||||
|
60,4.236,0.487
|
||||||
|
60,4.29,0.487
|
||||||
|
60,4.391,0.481
|
||||||
|
60,4.412,0.489
|
||||||
|
60,4.512,0.49
|
||||||
|
60,4.54,0.487
|
||||||
|
60,4.553,0.498
|
||||||
|
60,4.58,0.493
|
||||||
|
60,4.609,0.507
|
||||||
|
60,4.654,0.504
|
||||||
|
60,4.665,0.507
|
||||||
|
60,4.699,0.509
|
||||||
|
60,4.74,0.517
|
||||||
|
60,4.769,0.52
|
||||||
|
60,4.813,0.528
|
||||||
|
60,4.849,0.526
|
||||||
|
60,4.93,0.543
|
||||||
|
60,4.954,0.534
|
||||||
|
60,5.034,0.543
|
||||||
|
60,5.155,0.543
|
||||||
|
60,5.083,0.545
|
||||||
|
60,5.185,0.55
|
||||||
|
60,5.231,0.537
|
||||||
|
60,4.875,0.535
|
||||||
|
60,4.924,0.534
|
||||||
|
60,4.954,0.542
|
||||||
|
60,5.052,0.535
|
||||||
|
60,5.033,0.54
|
||||||
|
60,5.13,0.545
|
||||||
|
60,5.17,0.55
|
||||||
|
60,5.196,0.547
|
||||||
|
60,5.23,0.568
|
||||||
|
60,5.258,0.551
|
||||||
|
60,5.283,0.555
|
||||||
|
60,5.312,0.551
|
||||||
|
60,5.35,0.555
|
||||||
|
60,5.408,0.55
|
||||||
|
60,5.47,0.555
|
||||||
|
60,5.497,0.543
|
||||||
|
60,5.515,0.551
|
||||||
|
60,5.549,0.55
|
||||||
|
60,5.554,0.558
|
||||||
|
60,5.575,0.551
|
||||||
|
60,5.6,0.55
|
||||||
|
60,5.621,0.56
|
||||||
|
60,5.625,0.543
|
||||||
|
60,5.641,0.543
|
||||||
|
60,5.655,0.55
|
||||||
|
60,5.659,0.551
|
||||||
|
60,5.668,0.56
|
||||||
|
60,5.691,0.553
|
||||||
|
60,5.714,0.551
|
||||||
|
60,5.748,0.558
|
||||||
|
60,5.757,0.55
|
||||||
|
60,5.789,0.551
|
||||||
|
60,5.836,0.547
|
||||||
|
60,5.865,0.555
|
||||||
|
60,5.914,0.553
|
||||||
|
60,5.916,0.55
|
||||||
|
60,5.945,0.551
|
||||||
|
60,5.962,0.555
|
||||||
|
15,3.77,0.696
|
||||||
|
15,3.82,0.699
|
||||||
|
15,3.855,0.707
|
||||||
|
15,3.905,0.712
|
||||||
|
15,3.955,0.717
|
||||||
|
15,4,0.73
|
||||||
|
15,4.041,0.734
|
||||||
|
15,4.076,0.736
|
||||||
|
15,4.079,0.744
|
||||||
|
15,4.114,0.751
|
||||||
|
15,4.133,0.74
|
||||||
|
15,4.179,0.744
|
||||||
|
15,4.196,0.754
|
||||||
|
15,4.27,0.76
|
||||||
|
15,4.29,0.756
|
||||||
|
15,4.314,0.769
|
||||||
|
15,4.34,0.763
|
||||||
|
15,4.366,0.778
|
||||||
|
15,4.386,0.772
|
||||||
|
15,4.41,0.772
|
||||||
|
15,4.425,0.782
|
||||||
|
15,4.466,0.785
|
||||||
|
15,4.52,0.78
|
||||||
|
15,4.59,0.781
|
||||||
|
15,4.63,0.777
|
||||||
|
15,4.725,0.78
|
||||||
|
15,4.811,0.781
|
||||||
|
15,4.865,0.777
|
||||||
|
15,4.885,0.776
|
||||||
|
15,4.965,0.779
|
||||||
|
15,5,0.781
|
||||||
|
15,5.042,0.78
|
||||||
|
15,5.098,0.781
|
||||||
|
15,5.155,0.778
|
||||||
|
15,5.179,0.781
|
||||||
|
15,5.285,0.779
|
||||||
|
15,4.44,0.775
|
||||||
|
15,4.5,0.777
|
||||||
|
15,4.54,0.778
|
||||||
|
15,4.596,0.78
|
||||||
|
15,4.685,0.781
|
||||||
|
15,4.722,0.777
|
||||||
|
15,4.845,0.775
|
||||||
|
15,4.869,0.778
|
||||||
|
15,4.929,0.78
|
||||||
|
15,4.949,0.779
|
||||||
|
15,5.002,0.777
|
||||||
|
15,5.005,0.775
|
||||||
|
15,5.097,0.778
|
||||||
|
15,5.139,0.783
|
||||||
|
15,5.156,0.784
|
||||||
|
15,5.22,0.777
|
||||||
|
15,5.236,0.78
|
||||||
|
15,5.31,0.778
|
||||||
|
15,5.36,0.775
|
||||||
|
15,5.41,0.78
|
||||||
|
15,5.446,0.78
|
||||||
|
15,5.455,0.777
|
||||||
|
15,5.515,0.781
|
||||||
|
15,5.567,0.778
|
||||||
|
15,5.613,0.78
|
||||||
|
15,5.69,0.784
|
||||||
|
15,5.834,0.781
|
||||||
|
15,5.882,0.777
|
||||||
|
15,5.959,0.778
|
||||||
|
15,6.008,0.78
|
||||||
|
15,5.793,0.78
|
||||||
|
15,5.857,0.777
|
||||||
|
15,5.93,0.778
|
||||||
|
15,5.987,0.78
|
||||||
|
126,3.63,0.594
|
||||||
|
126,3.675,0.588
|
||||||
|
126,3.715,0.576
|
||||||
|
126,3.76,0.566
|
||||||
|
126,3.81,0.552
|
||||||
|
126,3.833,0.564
|
||||||
|
126,3.895,0.532
|
||||||
|
126,3.925,0.515
|
||||||
|
126,3.95,0.503
|
||||||
|
126,3.965,0.498
|
||||||
|
126,4.015,0.491
|
||||||
|
126,4.111,0.471
|
||||||
|
126,4.196,0.451
|
||||||
|
126,4.265,0.435
|
||||||
|
126,4.33,0.424
|
||||||
|
126,4.386,0.415
|
||||||
|
126,4.425,0.412
|
||||||
|
126,4.47,0.4
|
||||||
|
126,4.496,0.396
|
||||||
|
126,4.511,0.4
|
||||||
|
126,4.55,0.393
|
||||||
|
126,4.62,0.392
|
||||||
|
126,4.697,0.391
|
||||||
|
126,4.76,0.4
|
||||||
|
126,4.82,0.403
|
||||||
|
126,4.91,0.408
|
||||||
|
126,4.985,0.414
|
||||||
|
126,5.057,0.422
|
||||||
|
126,5.121,0.424
|
||||||
|
126,5.164,0.43
|
||||||
|
126,5.591,0.45
|
||||||
|
126,5.616,0.453
|
||||||
|
126,5.655,0.447
|
||||||
|
126,5.675,0.45
|
||||||
|
126,5.708,0.445
|
||||||
|
126,5.736,0.452
|
||||||
|
126,5.756,0.445
|
||||||
|
126,5.775,0.445
|
||||||
|
126,5.798,0.45
|
||||||
|
126,5.831,0.45
|
||||||
|
126,5.835,0.446
|
||||||
|
126,5.874,0.45
|
||||||
|
126,5.894,0.447
|
||||||
|
126,5.935,0.45
|
||||||
|
126,5.961,0.444
|
||||||
|
126,5.97,0.449
|
||||||
|
126,5.987,0.447
|
||||||
|
126,4.95,0.43
|
||||||
|
126,5.049,0.432
|
||||||
|
126,5.021,0.415
|
||||||
|
126,5.1,0.422
|
||||||
|
126,5.13,0.422
|
||||||
|
126,5.179,0.43
|
||||||
|
126,5.196,0.43
|
||||||
|
126,5.225,0.435
|
||||||
|
126,5.225,0.43
|
||||||
|
126,5.25,0.436
|
||||||
|
126,5.274,0.438
|
||||||
|
126,5.29,0.438
|
||||||
|
126,5.31,0.436
|
||||||
|
126,5.33,0.439
|
||||||
|
126,5.35,0.439
|
||||||
|
126,5.366,0.444
|
||||||
|
126,5.393,0.444
|
||||||
|
126,5.423,0.446
|
||||||
|
126,5.432,0.447
|
||||||
|
126,5.455,0.45
|
||||||
|
126,5.476,0.452
|
||||||
|
126,5.501,0.447
|
||||||
|
126,5.525,0.447
|
||||||
|
126,5.56,0.45
|
||||||
|
30.6,3.672,0.592
|
||||||
|
30.6,3.708,0.59
|
||||||
|
30.6,3.748,0.592
|
||||||
|
30.6,3.763,0.597
|
||||||
|
30.6,3.785,0.583
|
||||||
|
30.6,3.826,0.585
|
||||||
|
30.6,3.869,0.596
|
||||||
|
30.6,3.881,0.578
|
||||||
|
30.6,3.929,0.578
|
||||||
|
30.6,3.935,0.583
|
||||||
|
30.6,3.978,0.578
|
||||||
|
30.6,4.009,0.585
|
||||||
|
30.6,4.049,0.583
|
||||||
|
30.6,4.079,0.592
|
||||||
|
30.6,4.124,0.59
|
||||||
|
30.6,4.13,0.599
|
||||||
|
30.6,4.19,0.599
|
||||||
|
30.6,4.27,0.609
|
||||||
|
30.6,4.29,0.618
|
||||||
|
30.6,4.309,0.612
|
||||||
|
30.6,4.584,0.639
|
||||||
|
30.6,4.653,0.644
|
||||||
|
30.6,4.799,0.647
|
||||||
|
30.6,4.9,0.656
|
||||||
|
30.6,4.965,0.656
|
||||||
|
30.6,5.029,0.652
|
||||||
|
30.6,5.068,0.65
|
||||||
|
30.6,5.134,0.65
|
||||||
|
30.6,5.176,0.65
|
||||||
|
30.6,4.425,0.637
|
||||||
|
30.6,4.44,0.63
|
||||||
|
30.6,4.56,0.637
|
||||||
|
30.6,4.636,0.647
|
||||||
|
30.6,4.74,0.654
|
||||||
|
30.6,4.83,0.654
|
||||||
|
30.6,4.855,0.661
|
||||||
|
30.6,4.99,0.657
|
||||||
|
30.6,5.1,0.652
|
||||||
|
30.6,5.24,0.657
|
||||||
|
30.6,5.275,0.657
|
||||||
|
30.6,5.323,0.647
|
||||||
|
30.6,5.473,0.657
|
||||||
|
30.6,5.655,0.652
|
||||||
|
30.6,4.934,0.656
|
||||||
|
30.6,5.068,0.657
|
||||||
|
30.6,5.17,0.659
|
||||||
|
30.6,5.223,0.656
|
||||||
|
30.6,5.255,0.652
|
||||||
|
30.6,5.342,0.657
|
||||||
|
30.6,5.344,0.657
|
||||||
|
30.6,5.394,0.659
|
||||||
|
30.6,5.428,0.659
|
||||||
|
30.6,5.444,0.661
|
||||||
|
30.6,5.516,0.657
|
||||||
|
30.6,5.541,0.659
|
||||||
|
30.6,5.559,0.657
|
||||||
|
30.6,5.776,0.659
|
||||||
|
30.6,5.81,0.659
|
||||||
|
30.6,5.863,0.657
|
||||||
|
30.6,5.916,0.659
|
||||||
|
30.6,5.962,0.65
|
||||||
|
30.6,6,0.659
|
|
294
package/test/parser.jl
Normal file
294
package/test/parser.jl
Normal file
|
@ -0,0 +1,294 @@
|
||||||
|
## Parser for (ESR) expressions in infix format
|
||||||
|
|
||||||
|
mutable struct Parser
|
||||||
|
const str::AbstractString # string to be parsed
|
||||||
|
pos::Int64 # current position in string
|
||||||
|
sy::Union{AbstractString,Nothing} # current lookahead symbol
|
||||||
|
const pSy::Symbol
|
||||||
|
const xSy::Symbol
|
||||||
|
const varnames::Vector{<:AbstractString}
|
||||||
|
const paramnames::Vector{<:AbstractString}
|
||||||
|
const coeff::Vector{Float64}
|
||||||
|
const numbers_as_parameters::Bool
|
||||||
|
const integers_as_constants::Bool # TODO rename and implement as rationals_as_constants
|
||||||
|
|
||||||
|
# The kwparam numbers_as_parameters allows to include coefficient values directly in the expression and the values are parsed as parameters
|
||||||
|
# In this mode the suffix 'f' allows to mark constants. E.g. 3 * x ^ 2f would create the parameterized expression a0*x^2 with 2 a constant value.
|
||||||
|
function Parser(str::AbstractString, varnames::Vector{<:AbstractString}, paramnames::Vector{<:AbstractString}; numbers_as_parameters=false, integers_as_constants=false)
|
||||||
|
if numbers_as_parameters && length(paramnames) > 0
|
||||||
|
error("the parser does not support paramnames when numbers_as_parameters=true")
|
||||||
|
end
|
||||||
|
if !numbers_as_parameters && integers_as_constants
|
||||||
|
error("Set numbers_as_parameters=true to parse integers_as_constants")
|
||||||
|
end
|
||||||
|
|
||||||
|
p = new(lowercase(str), 1, nothing, :p, :x, varnames, paramnames, Vector{Float64}(), numbers_as_parameters, integers_as_constants)
|
||||||
|
next_symbol!(p)
|
||||||
|
return p;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# recursive descent parser
|
||||||
|
# scanner is also defined in this file
|
||||||
|
|
||||||
|
# LL(1) grammar:
|
||||||
|
# G(Expr):
|
||||||
|
# Expr = Term { ('+' | '-') Term }
|
||||||
|
# Term = Fact { ('*' | '/') Fact }
|
||||||
|
# Fact = { '+' | '-' }
|
||||||
|
# (ident | number | parameter
|
||||||
|
# | '(' Expr ')'
|
||||||
|
# | ident ParamList // function call
|
||||||
|
# ) [ ('**' | '^') Fact ]
|
||||||
|
# ParamList = '(' Expr { ',' Expr } ')'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# scanner
|
||||||
|
|
||||||
|
|
||||||
|
function parse_infix(exprStr::AbstractString, varnames::Vector{<:AbstractString}, paramnames::Vector{<:AbstractString};
|
||||||
|
numbers_as_parameters = false, integers_as_constants = false)::Tuple{Expr, Vector{Float64}}
|
||||||
|
parser = Parser(exprStr, varnames, paramnames;
|
||||||
|
numbers_as_parameters = numbers_as_parameters, integers_as_constants = integers_as_constants)
|
||||||
|
body = parse_expr!(parser)
|
||||||
|
expr = Expr(:->, Expr(:tuple, :x, :p), body) # :((x,p) -> $body)
|
||||||
|
(expr, parser.coeff)
|
||||||
|
end
|
||||||
|
|
||||||
|
function parse_expr!(p::Parser)
|
||||||
|
t1 = parse_term!(p)
|
||||||
|
while p.sy == "+" || p.sy == "-"
|
||||||
|
if p.sy == "+"
|
||||||
|
next_symbol!(p)
|
||||||
|
t2 = parse_term!(p)
|
||||||
|
t1 = :($t1 + $t2) # add_simpl(t1, t2)
|
||||||
|
else
|
||||||
|
next_symbol!(p)
|
||||||
|
t2 = parse_term!(p)
|
||||||
|
t1 = :($t1 - $t2) # sub_simpl(t1, t2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return t1
|
||||||
|
end
|
||||||
|
|
||||||
|
function parse_term!(p::Parser)
|
||||||
|
f1 = parse_factor!(p)
|
||||||
|
while p.sy == "*" || p.sy == "/"
|
||||||
|
if p.sy == "*"
|
||||||
|
next_symbol!(p)
|
||||||
|
f2 = parse_factor!(p)
|
||||||
|
f1 = :($f1 * $f2) # mul_simpl(f1, f2)
|
||||||
|
else
|
||||||
|
next_symbol!(p)
|
||||||
|
f2 = parse_factor!(p)
|
||||||
|
f1 = :($f1 / $f2) # div_simpl(f1, f2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return f1
|
||||||
|
end
|
||||||
|
|
||||||
|
# Fact = { '+' | '-' }
|
||||||
|
# (constant | parameter
|
||||||
|
# | '(' Expr ')'
|
||||||
|
# | ident [ ParamList ] variable or function call
|
||||||
|
# ) [ ('**' | '^') Fact ]
|
||||||
|
# ParamList = '(' Expr { ',' Expr } ')'
|
||||||
|
|
||||||
|
function parse_factor!(p::Parser)
|
||||||
|
sign = 1.0
|
||||||
|
|
||||||
|
while p.sy == "+" || p.sy == "-"
|
||||||
|
if p.sy == "-"
|
||||||
|
sign = sign * -1.0
|
||||||
|
end
|
||||||
|
next_symbol!(p)
|
||||||
|
end
|
||||||
|
|
||||||
|
factor = 1.0
|
||||||
|
|
||||||
|
if isident(p.sy)
|
||||||
|
ident = p.sy
|
||||||
|
next_symbol!(p)
|
||||||
|
if p.sy == "("
|
||||||
|
parameters = parse_paramlist!(p)
|
||||||
|
|
||||||
|
if ident == "sqr"
|
||||||
|
# convert sqr(x) call to x**2 (so that we don't have to update the interpreters)
|
||||||
|
factor = Expr(:call, func_symbol("pow"), parameters..., 2.0)
|
||||||
|
else
|
||||||
|
factor = Expr(:call, func_symbol(ident), parameters...)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
idx = findfirst(p -> p==ident, p.varnames)
|
||||||
|
if !isnothing(idx)
|
||||||
|
factor = Expr(:ref, p.xSy, idx)
|
||||||
|
elseif !p.numbers_as_parameters # only if paramnames are given
|
||||||
|
idx = findfirst(p -> p==ident, p.paramnames)
|
||||||
|
|
||||||
|
# replace parameter variables with access to coefficient vector (initialized to zero)
|
||||||
|
if !isnothing(idx)
|
||||||
|
factor = Expr(:ref, p.pSy, idx)
|
||||||
|
push!(p.coeff, 0.0)
|
||||||
|
else
|
||||||
|
error("undefined symbol $ident")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("undefined variable $ident")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif isnumber(p.sy)
|
||||||
|
if p.numbers_as_parameters
|
||||||
|
numStr = p.sy
|
||||||
|
val = parse(Float64, numStr)
|
||||||
|
next_symbol!(p)
|
||||||
|
if p.sy == "f"
|
||||||
|
# constant
|
||||||
|
factor = sign * val # numbers are parsed without sign (if we parsed a sign above then we can include this in the constant here)
|
||||||
|
sign = 1.0
|
||||||
|
next_symbol!(p)
|
||||||
|
elseif p.integers_as_constants && isinteger(val)
|
||||||
|
# integers are parsed as constants
|
||||||
|
factor = sign * val # numbers are parsed without sign (if we parsed a sign above then we can include this in the constant here)
|
||||||
|
sign = 1.0
|
||||||
|
else
|
||||||
|
# parameter
|
||||||
|
factor = new_param!(p, sign * val)
|
||||||
|
sign = 1.0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# otherwise all numbers are parsed as constants
|
||||||
|
numStr = p.sy
|
||||||
|
next_symbol!(p)
|
||||||
|
|
||||||
|
if p.sy == "//"
|
||||||
|
num = parse(Int64, numStr)
|
||||||
|
next_symbol!(p)
|
||||||
|
denom = parse(Int64, p.sy)
|
||||||
|
val = num // denom
|
||||||
|
next_symbol!(p)
|
||||||
|
else
|
||||||
|
val = parse(Float64, numStr)
|
||||||
|
end
|
||||||
|
|
||||||
|
factor = sign * val
|
||||||
|
sign = 1.0
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif p.sy == "("
|
||||||
|
next_symbol!(p)
|
||||||
|
factor = parse_expr!(p)
|
||||||
|
expect_and_next!(p, ")")
|
||||||
|
|
||||||
|
else
|
||||||
|
error("cannot parse expression")
|
||||||
|
end
|
||||||
|
|
||||||
|
if p.sy == "**" || p.sy == "^"
|
||||||
|
next_symbol!(p)
|
||||||
|
exponent = parse_factor!(p)
|
||||||
|
factor = :($factor ^ $exponent) # pow_simpl(factor, exponent)
|
||||||
|
end
|
||||||
|
|
||||||
|
if sign == -1
|
||||||
|
neg_simpl(factor)
|
||||||
|
else
|
||||||
|
factor
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function parse_paramlist!(p::Parser)::Vector
|
||||||
|
parameters = Vector()
|
||||||
|
expect_and_next!(p, "(")
|
||||||
|
push!(parameters, parse_expr!(p))
|
||||||
|
while p.sy == ","
|
||||||
|
next_symbol!(p)
|
||||||
|
push!(parameters, parse_expr!(p))
|
||||||
|
end
|
||||||
|
expect_and_next!(p, ")")
|
||||||
|
return parameters
|
||||||
|
end
|
||||||
|
|
||||||
|
function expect_and_next!(p::Parser, expectedSy::AbstractString)
|
||||||
|
if p.sy != expectedSy
|
||||||
|
error("expected: $(expectedSy) at column $(p.pos)")
|
||||||
|
else
|
||||||
|
next_symbol!(p)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function new_param!(p::Parser, val::Float64)::Expr
|
||||||
|
push!(p.coeff, val)
|
||||||
|
return Expr(:ref, p.pSy, length(p.coeff))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function isident(s::AbstractString)::Bool
|
||||||
|
return s != "nan" && s != "inf" && !isnothing(match(r"^[_a-zA-Z][_a-zA-Z0-9]*$", s))
|
||||||
|
end
|
||||||
|
|
||||||
|
function isnumber(s::AbstractString)::Bool
|
||||||
|
return !isnothing(tryparse(Float64, s))
|
||||||
|
end
|
||||||
|
|
||||||
|
function variable_index(p::Parser, str::AbstractString)
|
||||||
|
return findfirst(s->s==str, p.varNames)
|
||||||
|
end
|
||||||
|
|
||||||
|
function func_symbol(id::AbstractString)
|
||||||
|
if id == "pow"
|
||||||
|
return :^;
|
||||||
|
else
|
||||||
|
return Symbol(id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function next_symbol!(p::Parser)
|
||||||
|
s = p.str
|
||||||
|
pos = p.pos
|
||||||
|
# skip whitespace
|
||||||
|
while pos <= length(s) && isspace(s[pos])
|
||||||
|
pos += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if pos > length(s)
|
||||||
|
p.sy = nothing
|
||||||
|
p.pos = pos
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if isdigit(s[pos]) # numbers
|
||||||
|
m = match(r"(\d+([.]\d*)?([eE][+-]?\d+)?|[.]\d+([eE][+-]?\d+)?)", s, pos) # match floating point number
|
||||||
|
pos += length(m[1]) # get the whole match
|
||||||
|
p.sy = m[1]
|
||||||
|
elseif isletter(s[pos]) # identifiers
|
||||||
|
idStr = string(s[pos])
|
||||||
|
pos += 1
|
||||||
|
while pos <= length(s) && (isdigit(s[pos]) || isletter(s[pos]) || s[pos] == '_')
|
||||||
|
idStr = idStr * s[pos]
|
||||||
|
pos += 1
|
||||||
|
end
|
||||||
|
p.sy = idStr
|
||||||
|
elseif s[pos] == '*'
|
||||||
|
pos += 1
|
||||||
|
p.sy = "*"
|
||||||
|
if s[pos] == '*'
|
||||||
|
p.sy = "**"
|
||||||
|
pos += 1
|
||||||
|
end
|
||||||
|
elseif s[pos] == '/'
|
||||||
|
pos += 1
|
||||||
|
p.sy = "/"
|
||||||
|
if s[pos] == '/'
|
||||||
|
p.sy = "//"
|
||||||
|
pos += 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
p.sy = string(s[pos]) # single character symbol
|
||||||
|
pos += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
p.pos = pos
|
||||||
|
# println((p.sy, pos)) # for debugging
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user