From 26741adec7ff1db3cc77e3eb87691809bd7532a0 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 11 Jul 2024 15:44:22 +0200 Subject: [PATCH] added tests but need to do rewrites. focus on GPU execution for now --- package/Project.toml | 3 ++ package/src/ExpressionExecutorCuda.jl | 62 +++++------------------ package/src/ExpressionProcessing.jl | 71 +++++++++++++++++++++++++++ package/test/ExpressionProcessing.jl | 31 ++++++++++++ package/test/Project.toml | 2 + package/test/runtests.jl | 2 +- 6 files changed, 119 insertions(+), 52 deletions(-) create mode 100644 package/src/ExpressionProcessing.jl create mode 100644 package/test/ExpressionProcessing.jl create mode 100644 package/test/Project.toml diff --git a/package/Project.toml b/package/Project.toml index 62c5ec1..eef623f 100644 --- a/package/Project.toml +++ b/package/Project.toml @@ -3,6 +3,9 @@ uuid = "5b8ee377-1e19-4ba5-a85c-78c7d1694bfe" authors = ["Daniel Wiplinger"] version = "1.0.0-DEV" +[deps] +CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + [compat] julia = "1.6.7" diff --git a/package/src/ExpressionExecutorCuda.jl b/package/src/ExpressionExecutorCuda.jl index e9635df..4c68111 100644 --- a/package/src/ExpressionExecutorCuda.jl +++ b/package/src/ExpressionExecutorCuda.jl @@ -1,11 +1,12 @@ module ExpressionExecutorCuda include("Interpreter.jl") +include("ExpressionProcessing.jl") export interpret_gpu export evaluate_gpu export test -const SymbolTable64 = Dict{Tuple{Expr, Symbol},Float64} +# const SymbolTable64 = Dict{Tuple{Expr, Symbol},Float64} # # Some assertions: # Variables and parameters start their naming with "1" meaning the first variable/parameter has to be "x1/p1" and not "x0/p0" @@ -40,60 +41,18 @@ end - It replaces every variable with the according value stored in X and p. - It transforms the expressions into postfix form and returns them. " -function preprocess_expressions!(exprs::Vector{Expr}, X::Matrix{Float64}, p::Vector{Vector{Float64}})::Vector{String} - symtable = construct_symtable(exprs, X, p) - postfixExpressions = +function preprocess_expressions!(exprs::Vector{Expr}, X::Matrix{Float64}, p::Vector{Vector{Float64}})::Array{String} + symtable = ExpressionProcessing.construct_symtable(exprs, X, p) + postfixExpressions = Array{String,1}() # Test if multi threading provides a speedup and if it does, roughly determin the size at which it is beneficial. for i in eachindex(exprs) - replace_variables!(exprs[i], symtable) + expr = deepcopy(exprs[i]) + ExpressionProcessing.replace_variables!(exprs[i], symtable, expr) + push!(postfixExpressions, ExpressionProcessing.expr_to_postfix(exprs[i])) end - return expr_to_postfix() -end - -function expr_to_postfix()::Array{String} - # TODO -end - -# Probaly move the below function into another module - -"Replaces all the variables and parameters of the given expression with their corresponding value stored in the symtable" -function replace_variables!(ex::Expr, symtable::SymbolTable64) - for i in 1:length(ex.args) - arg = ex.args[i] - if typeof(arg) === Expr - replace_variables!(ex, symtable) - elseif haskey(symtable, (ex,arg)) # We found a variable/parameter and can replace it with the actual value - ex.args[i] = symtable[(ex,arg)] - end - end -end - -function construct_symtable(expressions::Vector{Expr}, mat::Matrix{Float64}, params::Vector{Vector{Float64}})::SymbolTable64 - symtable = SymbolTable64() - - for i in eachindex(expressions) - expr = expressions[i] - values = mat[:,i] - parameters = params[i] - - fill_symtable!(expr, symtable, values, "x") - fill_symtable!(expr, symtable, parameters, "p") - end - - return symtable -end - -function fill_symtable!(expr::Expr, symtable::SymbolTable64, values::Vector{Float64}, symbolPrefix::String) - varIndex = 1 - for j in eachindex(values) - val = values[j] - sym = Symbol(symbolPrefix, varIndex) - - symtable[expr,sym] = val - varIndex += 1 - end + return postfixExpressions end end @@ -102,7 +61,8 @@ end # Flow # input: Vector expr == expressions contains eg. 4 expressions -# Matrix X == |expr| columns, n rows. n == number of variabls x1..xn; n is the same for all expressions +# Matrix X == |expr| columns, n rows. n == number of variabls x1..xn; n is the same for all expressions --- WRONG +# Matrix X == k columns, n rows. k == number of variables in the expressions (every expression must have the same number of variables); n == number of different values for xk where k is the column # VectorVector p == vector size |expr| containing vector size m. m == number of parameters per expression. p can be different for each expression # # The following can be done on the CPU diff --git a/package/src/ExpressionProcessing.jl b/package/src/ExpressionProcessing.jl new file mode 100644 index 0000000..a7c8cf1 --- /dev/null +++ b/package/src/ExpressionProcessing.jl @@ -0,0 +1,71 @@ +module ExpressionProcessing + +export construct_symtable +export replace_variables! +export expr_to_postfix +export SymbolTable64 + +const SymbolTable64 = Dict{Tuple{Expr, Symbol},Float64} + +# Maybe switch from Array{String} to Array{Union{Float64, String}}? +function expr_to_postfix(expr::Expr)::Array{String} + postfix = Array{String,1}() + operator = String(expr.args[1]) + + push!(postfix, expr.args[2], expr.args[3], operator) + for i in 4:length(expr.args) + arg = expr.args[i] + if typeof(arg) === Expr + push!(postfix, expr_to_postfix(ex)) + else + push!(postfix, string(arg), operator) + end + end +end + +"Replaces all the variables and parameters of the given expression with their corresponding value stored in the symtable +# Arguments + - `symtable::SymbolTable64`: Contains the values of all variables for each expression + - `originalExpr::Expr`: Contains a deep copy of the original expression. It is used to link the expression and variables to their according value stored in the symtable +" +function replace_variables!(ex::Expr, symtable::SymbolTable64, originalExpr::Expr) + for i in 1:length(ex.args) + arg = ex.args[i] + if typeof(arg) === Expr + replace_variables!(arg, symtable, originalExpr) + elseif haskey(symtable, (originalExpr,arg)) # We found a variable/parameter and can replace it with the actual value + println("Replacing") + ex.args[i] = symtable[(originalExpr,arg)] + end + end +end + +# TODO: Completly rewrite this function because I misunderstood it. Not every column is linked to an expression. therefore all other functions need to be reworked as well. Probably can't replace the variables in julia anymore, look into this. (see ExpressionExecutorCuda.jl for more info) +# Before rewriting, proceed with just creating a postfix notation and sending the variable matrix as well as the parameter "matrix" to the GPU to perform first calculations +function construct_symtable(expressions::Vector{Expr}, mat::Matrix{Float64}, params::Vector{Vector{Float64}})::SymbolTable64 + symtable = SymbolTable64() + + for i in eachindex(expressions) + expr = expressions[i] + values = mat[i,:] + parameters = params[i] + + fill_symtable!(expr, symtable, values, "x") + fill_symtable!(expr, symtable, parameters, "p") + end + + return symtable +end + +function fill_symtable!(expr::Expr, symtable::SymbolTable64, values::Vector{Float64}, symbolPrefix::String) + varIndex = 1 + for j in eachindex(values) + val = values[j] + sym = Symbol(symbolPrefix, varIndex) + + symtable[expr,sym] = val + varIndex += 1 + end +end + +end diff --git a/package/test/ExpressionProcessing.jl b/package/test/ExpressionProcessing.jl new file mode 100644 index 0000000..e44a3cd --- /dev/null +++ b/package/test/ExpressionProcessing.jl @@ -0,0 +1,31 @@ +expressions = Vector{Expr}(undef, 1) +variables = Matrix{Float64}(undef, 1,2) +parameters = Vector{Vector{Float64}}(undef, 1) + +# Resulting value should be 10 +expressions[1] = :(x1 + 1 * x2 + p1) +variables[1,1] = 2 +variables[1,2] = 3 +parameters[1] = Vector{Float64}(undef, 1) +parameters[1][1] = 5 + +@testset "Test symtable construction" begin + symtable = ExpressionExecutorCuda.ExpressionProcessing.construct_symtable(expressions, variables, parameters) + @test haskey(symtable, (expressions[1], :x1)) + @test haskey(symtable, (expressions[1], :x2)) + @test haskey(symtable, (expressions[1], :p1)) + + @test symtable[(expressions[1], :x1)] ≈ 2.0 atol=0.01 + @test symtable[(expressions[1], :x2)] ≈ 3.0 atol=0.01 + @test symtable[(expressions[1], :p1)] ≈ 5.0 atol=0.01 +end + +@testset "Test variable replacement in expression" begin + symtable = ExpressionExecutorCuda.ExpressionProcessing.construct_symtable(expressions, variables, parameters) + println(keys(symtable)) + exprCopy = deepcopy(expressions[1]) + ExpressionExecutorCuda.ExpressionProcessing.replace_variables!(exprCopy, symtable, expressions[1]) + + dump(exprCopy) + @test eval(exprCopy) == 10 # If it can be evaluated, it means all variables have been replaced, as there are no globally defined variables +end \ No newline at end of file diff --git a/package/test/Project.toml b/package/test/Project.toml new file mode 100644 index 0000000..0c36332 --- /dev/null +++ b/package/test/Project.toml @@ -0,0 +1,2 @@ +[deps] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/package/test/runtests.jl b/package/test/runtests.jl index 01de97f..7699656 100644 --- a/package/test/runtests.jl +++ b/package/test/runtests.jl @@ -2,5 +2,5 @@ using ExpressionExecutorCuda using Test @testset "ExpressionExecutorCuda.jl" begin - # Write your tests here. + include("ExpressionProcessing.jl") end