layed groundwork for implementing interpretation
Some checks failed
CI / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} (x64, ubuntu-latest, 1.10) (push) Has been cancelled
CI / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} (x64, ubuntu-latest, 1.6) (push) Has been cancelled
CI / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} (x64, ubuntu-latest, pre) (push) Has been cancelled
Some checks failed
CI / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} (x64, ubuntu-latest, 1.10) (push) Has been cancelled
CI / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} (x64, ubuntu-latest, 1.6) (push) Has been cancelled
CI / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} (x64, ubuntu-latest, pre) (push) Has been cancelled
This commit is contained in:
parent
e1097202ab
commit
c871487a55
|
@ -2,16 +2,16 @@ module ExpressionProcessing
|
||||||
|
|
||||||
export expr_to_postfix
|
export expr_to_postfix
|
||||||
export PostfixType
|
export PostfixType
|
||||||
export Operator, Add, Subtract, Multiply, Divide, Power, Abs, Log, Exp, Sqrt
|
export Operator, ADD, SUBTRACT, MULTIPLY, DIVIDE, POWER, ABS, LOG, EXP, SQRT
|
||||||
export ElementType, FLOAT64, OPERATOR, INT64
|
export ElementType, EMPTY, FLOAT64, OPERATOR, INT64
|
||||||
export ExpressionElement
|
export ExpressionElement
|
||||||
|
|
||||||
@enum Operator::Int64 Add=1 Subtract=2 Multiply=3 Divide=4 Power=5 Abs=6 Log=7 Exp=8 Sqrt=9
|
@enum Operator::Int64 ADD=1 SUBTRACT=2 MULTIPLY=3 DIVIDE=4 POWER=5 ABS=6 LOG=7 EXP=8 SQRT=9
|
||||||
@enum ElementType FLOAT64=1 OPERATOR=2 INT64=3
|
@enum ElementType EMPTY=0 FLOAT64=1 OPERATOR=2 INT64=3
|
||||||
|
|
||||||
struct ExpressionElement
|
struct ExpressionElement
|
||||||
Type::ElementType
|
Type::ElementType
|
||||||
value::Int64 # Reinterpret the stored value to type "ElementType" when using it
|
Value::Int64 # Reinterpret the stored value to type "ElementType" when using it
|
||||||
end
|
end
|
||||||
|
|
||||||
const PostfixType = Vector{ExpressionElement}
|
const PostfixType = Vector{ExpressionElement}
|
||||||
|
@ -45,23 +45,23 @@ end
|
||||||
|
|
||||||
function get_operator(op::Symbol)::Operator
|
function get_operator(op::Symbol)::Operator
|
||||||
if op == :+
|
if op == :+
|
||||||
return Add
|
return ADD
|
||||||
elseif op == :-
|
elseif op == :-
|
||||||
return Subtract
|
return SUBTRACT
|
||||||
elseif op == :*
|
elseif op == :*
|
||||||
return Multiply
|
return MULTIPLY
|
||||||
elseif op == :/
|
elseif op == :/
|
||||||
return Divide
|
return DIVIDE
|
||||||
elseif op == :^
|
elseif op == :^
|
||||||
return Power
|
return POWER
|
||||||
elseif op == :abs
|
elseif op == :abs
|
||||||
return Abs
|
return ABS
|
||||||
elseif op == :log
|
elseif op == :log
|
||||||
return Log
|
return LOG
|
||||||
elseif op == :exp
|
elseif op == :exp
|
||||||
return Exp
|
return EXP
|
||||||
elseif op == :sqrt
|
elseif op == :sqrt
|
||||||
return Sqrt
|
return SQRT
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -80,13 +80,13 @@ function convert_var_to_int(var::Symbol)::Int
|
||||||
end
|
end
|
||||||
|
|
||||||
function convert_to_ExpressionElement(element)::ExpressionElement
|
function convert_to_ExpressionElement(element)::ExpressionElement
|
||||||
value = reinterpret(Int64, element)
|
Value = reinterpret(Int64, element)
|
||||||
if element isa Float64
|
if element isa Float64
|
||||||
return ExpressionElement(FLOAT64, value)
|
return ExpressionElement(FLOAT64, Value)
|
||||||
elseif element isa Int64
|
elseif element isa Int64
|
||||||
return ExpressionElement(INT64, value)
|
return ExpressionElement(INT64, Value)
|
||||||
elseif element isa Operator
|
elseif element isa Operator
|
||||||
return ExpressionElement(OPERATOR, value)
|
return ExpressionElement(OPERATOR, Value)
|
||||||
else
|
else
|
||||||
error("Element was of type '$(typeof(element))', which is not supported.")
|
error("Element was of type '$(typeof(element))', which is not supported.")
|
||||||
end
|
end
|
||||||
|
@ -100,17 +100,17 @@ end
|
||||||
|
|
||||||
const SymbolTable64 = Dict{Tuple{Expr, Symbol},Float64}
|
const SymbolTable64 = Dict{Tuple{Expr, Symbol},Float64}
|
||||||
|
|
||||||
"Replaces all the variables and parameters of the given expression with their corresponding value stored in the symtable
|
"Replaces all the variables and parameters of the given expression with their corresponding Value stored in the symtable
|
||||||
# Arguments
|
# Arguments
|
||||||
- `symtable::SymbolTable64`: Contains the values of all variables for each expression
|
- `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
|
- `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)
|
function replace_variables!(ex::Expr, symtable::SymbolTable64, originalExpr::Expr)
|
||||||
for i in 1:length(ex.args)
|
for i in 1:length(ex.args)
|
||||||
arg = ex.args[i]
|
arg = ex.args[i]
|
||||||
if typeof(arg) === Expr
|
if typeof(arg) === Expr
|
||||||
replace_variables!(arg, symtable, originalExpr)
|
replace_variables!(arg, symtable, originalExpr)
|
||||||
elseif haskey(symtable, (originalExpr,arg)) # We found a variable/parameter and can replace it with the actual value
|
elseif haskey(symtable, (originalExpr,arg)) # We found a variable/parameter and can replace it with the actual Value
|
||||||
ex.args[i] = symtable[(originalExpr,arg)]
|
ex.args[i] = symtable[(originalExpr,arg)]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,59 +12,93 @@ export interpret
|
||||||
"
|
"
|
||||||
function interpret(expressions::Vector{ExpressionProcessing.PostfixType}, variables::Matrix{Float64}, parameters::Vector{Vector{Float64}})
|
function interpret(expressions::Vector{ExpressionProcessing.PostfixType}, variables::Matrix{Float64}, parameters::Vector{Vector{Float64}})
|
||||||
# TODO:
|
# TODO:
|
||||||
# create CUDA array and fill it with the variables and parameters
|
|
||||||
# create CUDA array for calculation results
|
# create CUDA array for calculation results
|
||||||
variableRows = size(variables, 1)
|
variableRows = size(variables, 1)
|
||||||
cudaVars = CuArray(variables)
|
cudaVars = CuArray(variables)
|
||||||
|
cudaParams = create_cuda_array(parameters, NaN64)
|
||||||
|
cudaExprs = create_cuda_array(expressions, ExpressionElement(EMPTY, 0))
|
||||||
|
cudaStepsize = CuArray([get_max_inner_length(expressions), get_max_inner_length(parameters)]) # put into seperate cuArray, as this is static and would be inefficient to send seperatly to every kernel
|
||||||
|
|
||||||
paramRows = get_max_parameter_rows(parameters)
|
# Start kernel for each expression to ensure that no warp is working on different expressions
|
||||||
p1aramCols = length(parameters)
|
|
||||||
cudaParams = CuArray{Float64}(undef, p1aramCols, paramRows) # length(parameters) == number of expressions
|
|
||||||
# TODO: Fill cudaParams
|
|
||||||
|
|
||||||
# TODO: Move CuArray(expression[i]) outside the loop for a more efficient transfer to GPU but leave kernel signature as is
|
|
||||||
for i in eachindex(expressions)
|
for i in eachindex(expressions)
|
||||||
cudaExpr = CuArray(expressions[i])
|
kernel = @cuda launch=false interpret_expression(cudaExprs, cudaVars, cudaParams, cudaStepsize, i)
|
||||||
kernel = @cuda launch=false interpret_expression(cudaExpr, cudaVars, cudaParams, i)
|
|
||||||
config = launch_configuration(kernel.fun)
|
config = launch_configuration(kernel.fun)
|
||||||
threads = min(variableRows, config.threads)
|
threads = min(variableRows, config.threads)
|
||||||
blocks = cld(variableRows, threads)
|
blocks = cld(variableRows, threads)
|
||||||
|
|
||||||
kernel(cudaExpr, cudaVars, cudaParams, i; threads, blocks)
|
kernel(cudaExprs, cudaVars, cudaParams, cudaStepsize, i; threads, blocks)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function interpret_expression(expression, variables, parameters, exprIndex::Int)
|
function interpret_expression(expressions::CuDeviceArray{ExpressionElement}, variables::CuDeviceArray{Float64}, parameters::CuDeviceArray{Float64}, stepsize::CuDeviceArray{Int}, exprIndex::Int)
|
||||||
|
firstExprIndex = (exprIndex - 1 * stepsize[1]) + 1 # Inclusive
|
||||||
|
lastExprIndex = firstExprIndex + stepsize[1] # Exclusive
|
||||||
|
firstParamIndex = (exprIndex - 1 * stepsize[2]) + 1 # Inclusive
|
||||||
|
# lastParamIndex = firstParamIndex + stepsize[2] # Exclusive (probably not needed)
|
||||||
|
|
||||||
|
for i in firstExprIndex:lastExprIndex
|
||||||
# TODO Implement interpreter
|
# TODO Implement interpreter
|
||||||
|
# - start at firstExprIndex and interpret until the first ExpressionElement is "Empty" or we reached lastExprIndex
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
"Retrieves the number of entries for the largest inner vector"
|
"Retrieves the number of entries for the largest inner vector"
|
||||||
function get_max_parameter_rows(params::Vector{Vector{T}})::Int where T
|
function get_max_inner_length(vec::Vector{Vector{T}})::Int where T
|
||||||
maxLength = 0
|
maxLength = 0
|
||||||
for i in eachindex(params)
|
@inbounds for i in eachindex(vec)
|
||||||
if length(params) > maxLength
|
if length(vec[i]) > maxLength
|
||||||
maxLength = length(params)
|
maxLength = length(vec[i])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return maxLength
|
return maxLength
|
||||||
end
|
end
|
||||||
|
|
||||||
|
"Returns a CuArray filed with the data provided. The inner vectors do not have to have the same length. All missing elements will be the value ```invalidElement```"
|
||||||
|
function create_cuda_array(data::Vector{Vector{T}}, invalidElement::T)::CuArray{T} where T
|
||||||
|
dataCols = get_max_inner_length(data)
|
||||||
|
dataRows = length(data)
|
||||||
|
dataMat = convert_to_matrix(data, invalidElement)
|
||||||
|
cudaArr = CuArray{T}(undef, dataCols, dataRows) # length(parameters) == number of expressions
|
||||||
|
copyto!(cudaArr, dataMat)
|
||||||
|
|
||||||
|
return cudaArr
|
||||||
|
end
|
||||||
|
|
||||||
|
"Converts a vector of vectors into a matrix. The inner vectors do not need to have the same length.
|
||||||
|
|
||||||
|
All entries that cannot be filled have ```invalidElement``` as their value
|
||||||
|
"
|
||||||
|
function convert_to_matrix(vec::Vector{Vector{T}}, invalidElement::T)::Matrix{T} where T
|
||||||
|
vecCols = get_max_inner_length(vec)
|
||||||
|
vecRows = length(vec)
|
||||||
|
vecMat = fill(invalidElement, vecCols, vecRows)
|
||||||
|
|
||||||
|
for i in eachindex(vec)
|
||||||
|
vecMat[:,i] = copyto!(vecMat[:,i], vec[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
return vecMat
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
@deprecate InterpretExplicit!(op::Operator, x, y) interpret_expression(expression, variables, parameters, exprIndex::Int)
|
|
||||||
|
# @deprecate InterpretExplicit!(op::Operator, x, y) interpret_expression(expression, variables, parameters, exprIndex::Int)
|
||||||
# Kernel
|
# Kernel
|
||||||
function InterpretExplicit!(op::Operator, x, y)
|
function InterpretExplicit!(op::Operator, x, y)
|
||||||
index = (blockIdx().x - 1) * blockDim().x + threadIdx().x
|
index = (blockIdx().x - 1) * blockDim().x + threadIdx().x
|
||||||
stride = gridDim().x * blockDim().x
|
stride = gridDim().x * blockDim().x
|
||||||
|
|
||||||
if op == Add
|
if op == ADD
|
||||||
# @cuprintln("Performing Addition") # Will only be displayed when the GPU is synchronized
|
# @cuprintln("Performing Addition") # Will only be displayed when the GPU is synchronized
|
||||||
for i = index:stride:length(y)
|
for i = index:stride:length(y)
|
||||||
@inbounds y[i] += x[i]
|
@inbounds y[i] += x[i]
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
elseif op == Subtract
|
elseif op == SUBTRACT
|
||||||
# @cuprintln("Performing Subtraction") # Will only be displayed when the GPU is synchronized
|
# @cuprintln("Performing Subtraction") # Will only be displayed when the GPU is synchronized
|
||||||
for i = index:stride:length(y)
|
for i = index:stride:length(y)
|
||||||
@inbounds y[i] -= x[i]
|
@inbounds y[i] -= x[i]
|
||||||
|
|
|
@ -14,18 +14,18 @@ parameters[1][1] = 5
|
||||||
@testset "Test conversion expression element" begin
|
@testset "Test conversion expression element" begin
|
||||||
reference1 = ExpressionElement(FLOAT64, reinterpret(Int64, 1.0))
|
reference1 = ExpressionElement(FLOAT64, reinterpret(Int64, 1.0))
|
||||||
reference2 = ExpressionElement(INT64, reinterpret(Int64, 1))
|
reference2 = ExpressionElement(INT64, reinterpret(Int64, 1))
|
||||||
reference3 = ExpressionElement(OPERATOR, reinterpret(Int64, Add))
|
reference3 = ExpressionElement(OPERATOR, reinterpret(Int64, ADD))
|
||||||
|
|
||||||
@test isequal(reference1, ExpressionProcessing.convert_to_ExpressionElement(1.0))
|
@test isequal(reference1, ExpressionProcessing.convert_to_ExpressionElement(1.0))
|
||||||
@test isequal(reference2, ExpressionProcessing.convert_to_ExpressionElement(1))
|
@test isequal(reference2, ExpressionProcessing.convert_to_ExpressionElement(1))
|
||||||
@test isequal(reference3, ExpressionProcessing.convert_to_ExpressionElement(Add))
|
@test isequal(reference3, ExpressionProcessing.convert_to_ExpressionElement(ADD))
|
||||||
end
|
end
|
||||||
|
|
||||||
@testset "Test conversion to postfix" begin
|
@testset "Test conversion to postfix" begin
|
||||||
reference = PostfixType()
|
reference = PostfixType()
|
||||||
|
|
||||||
append!(reference, [ExpressionProcessing.convert_to_ExpressionElement(1), ExpressionProcessing.convert_to_ExpressionElement(1.0), ExpressionProcessing.convert_to_ExpressionElement(2), ExpressionProcessing.convert_to_ExpressionElement(Multiply),
|
append!(reference, [ExpressionProcessing.convert_to_ExpressionElement(1), ExpressionProcessing.convert_to_ExpressionElement(1.0), ExpressionProcessing.convert_to_ExpressionElement(2), ExpressionProcessing.convert_to_ExpressionElement(MULTIPLY),
|
||||||
ExpressionProcessing.convert_to_ExpressionElement(Add), ExpressionProcessing.convert_to_ExpressionElement(-1), ExpressionProcessing.convert_to_ExpressionElement(Add)])
|
ExpressionProcessing.convert_to_ExpressionElement(ADD), ExpressionProcessing.convert_to_ExpressionElement(-1), ExpressionProcessing.convert_to_ExpressionElement(ADD)])
|
||||||
postfix = expr_to_postfix(expressions[1])
|
postfix = expr_to_postfix(expressions[1])
|
||||||
|
|
||||||
@test isequal(reference, postfix)
|
@test isequal(reference, postfix)
|
||||||
|
|
|
@ -1,21 +1,42 @@
|
||||||
|
using CUDA
|
||||||
using .ExpressionProcessing
|
using .ExpressionProcessing
|
||||||
using .Interpreter
|
using .Interpreter
|
||||||
|
|
||||||
expressions = Vector{Expr}(undef, 1)
|
expressions = Vector{Expr}(undef, 2)
|
||||||
variables = Matrix{Float64}(undef, 1,2)
|
variables = Matrix{Float64}(undef, 2,2)
|
||||||
parameters = Vector{Vector{Float64}}(undef, 1)
|
parameters = Vector{Vector{Float64}}(undef, 2)
|
||||||
|
|
||||||
# Resulting value should be 10
|
# Resulting value should be 10
|
||||||
expressions[1] = :(x1 + 1 * x2 + p1)
|
expressions[1] = :(x1 + 1 * x2 + p1)
|
||||||
variables[1,1] = 2
|
expressions[2] = :(5 + x1 + 1 * x2 + p1 + p2)
|
||||||
variables[1,2] = 3
|
variables[1,1] = 2.0
|
||||||
|
variables[1,2] = 3.0
|
||||||
|
variables[2,1] = 2.0
|
||||||
|
variables[2,2] = 3.0
|
||||||
parameters[1] = Vector{Float64}(undef, 1)
|
parameters[1] = Vector{Float64}(undef, 1)
|
||||||
parameters[1][1] = 5
|
parameters[2] = Vector{Float64}(undef, 2)
|
||||||
|
parameters[1][1] = 5.0
|
||||||
|
parameters[2][1] = 5.0
|
||||||
|
parameters[2][2] = 0.0
|
||||||
|
|
||||||
@testset "Test interpretation" begin
|
@testset "Test interpretation" begin
|
||||||
postfixExpr = expr_to_postfix(expressions[1])
|
postfixExpr = expr_to_postfix(expressions[1])
|
||||||
postfixExprs = Vector{PostfixType}(undef, 1)
|
postfixExprs = Vector([postfixExpr])
|
||||||
postfixExprs[1] = postfixExpr
|
push!(postfixExprs, expr_to_postfix(expressions[2]))
|
||||||
|
|
||||||
Interpret(postfixExprs, variables, parameters)
|
CUDA.@sync interpret(postfixExprs, variables, parameters)
|
||||||
|
end
|
||||||
|
|
||||||
|
@testset "Test conversion to matrix" begin
|
||||||
|
reference = Matrix{Float64}(undef, 2, 2)
|
||||||
|
reference[1,1] = 5.0
|
||||||
|
reference[2,1] = NaN64
|
||||||
|
reference[1,2] = 5.0
|
||||||
|
reference[2,2] = 0.0
|
||||||
|
# fill!(reference, [[], [5.0, 0.0]])
|
||||||
|
# reference = Matrix([5.0, NaN],
|
||||||
|
# [5.0, 0.0])
|
||||||
|
result = Interpreter.convert_to_matrix(parameters, NaN64)
|
||||||
|
|
||||||
|
@test isequal(result, reference)
|
||||||
end
|
end
|
Loading…
Reference in New Issue
Block a user