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 PostfixType
|
||||
export Operator, Add, Subtract, Multiply, Divide, Power, Abs, Log, Exp, Sqrt
|
||||
export ElementType, FLOAT64, OPERATOR, INT64
|
||||
export Operator, ADD, SUBTRACT, MULTIPLY, DIVIDE, POWER, ABS, LOG, EXP, SQRT
|
||||
export ElementType, EMPTY, FLOAT64, OPERATOR, INT64
|
||||
export ExpressionElement
|
||||
|
||||
@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 Operator::Int64 ADD=1 SUBTRACT=2 MULTIPLY=3 DIVIDE=4 POWER=5 ABS=6 LOG=7 EXP=8 SQRT=9
|
||||
@enum ElementType EMPTY=0 FLOAT64=1 OPERATOR=2 INT64=3
|
||||
|
||||
struct ExpressionElement
|
||||
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
|
||||
|
||||
const PostfixType = Vector{ExpressionElement}
|
||||
|
@ -45,23 +45,23 @@ end
|
|||
|
||||
function get_operator(op::Symbol)::Operator
|
||||
if op == :+
|
||||
return Add
|
||||
return ADD
|
||||
elseif op == :-
|
||||
return Subtract
|
||||
return SUBTRACT
|
||||
elseif op == :*
|
||||
return Multiply
|
||||
return MULTIPLY
|
||||
elseif op == :/
|
||||
return Divide
|
||||
return DIVIDE
|
||||
elseif op == :^
|
||||
return Power
|
||||
return POWER
|
||||
elseif op == :abs
|
||||
return Abs
|
||||
return ABS
|
||||
elseif op == :log
|
||||
return Log
|
||||
return LOG
|
||||
elseif op == :exp
|
||||
return Exp
|
||||
return EXP
|
||||
elseif op == :sqrt
|
||||
return Sqrt
|
||||
return SQRT
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -80,13 +80,13 @@ function convert_var_to_int(var::Symbol)::Int
|
|||
end
|
||||
|
||||
function convert_to_ExpressionElement(element)::ExpressionElement
|
||||
value = reinterpret(Int64, element)
|
||||
Value = reinterpret(Int64, element)
|
||||
if element isa Float64
|
||||
return ExpressionElement(FLOAT64, value)
|
||||
return ExpressionElement(FLOAT64, Value)
|
||||
elseif element isa Int64
|
||||
return ExpressionElement(INT64, value)
|
||||
return ExpressionElement(INT64, Value)
|
||||
elseif element isa Operator
|
||||
return ExpressionElement(OPERATOR, value)
|
||||
return ExpressionElement(OPERATOR, Value)
|
||||
else
|
||||
error("Element was of type '$(typeof(element))', which is not supported.")
|
||||
end
|
||||
|
@ -100,17 +100,17 @@ end
|
|||
|
||||
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
|
||||
- `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)
|
||||
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
|
||||
elseif haskey(symtable, (originalExpr,arg)) # We found a variable/parameter and can replace it with the actual Value
|
||||
ex.args[i] = symtable[(originalExpr,arg)]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,59 +12,93 @@ export interpret
|
|||
"
|
||||
function interpret(expressions::Vector{ExpressionProcessing.PostfixType}, variables::Matrix{Float64}, parameters::Vector{Vector{Float64}})
|
||||
# TODO:
|
||||
# create CUDA array and fill it with the variables and parameters
|
||||
# create CUDA array for calculation results
|
||||
variableRows = size(variables, 1)
|
||||
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)
|
||||
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
|
||||
# Start kernel for each expression to ensure that no warp is working on different expressions
|
||||
for i in eachindex(expressions)
|
||||
cudaExpr = CuArray(expressions[i])
|
||||
kernel = @cuda launch=false interpret_expression(cudaExpr, cudaVars, cudaParams, i)
|
||||
kernel = @cuda launch=false interpret_expression(cudaExprs, cudaVars, cudaParams, cudaStepsize, i)
|
||||
config = launch_configuration(kernel.fun)
|
||||
threads = min(variableRows, config.threads)
|
||||
blocks = cld(variableRows, threads)
|
||||
|
||||
kernel(cudaExpr, cudaVars, cudaParams, i; threads, blocks)
|
||||
kernel(cudaExprs, cudaVars, cudaParams, cudaStepsize, i; threads, blocks)
|
||||
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
|
||||
# - start at firstExprIndex and interpret until the first ExpressionElement is "Empty" or we reached lastExprIndex
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
"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
|
||||
for i in eachindex(params)
|
||||
if length(params) > maxLength
|
||||
maxLength = length(params)
|
||||
@inbounds for i in eachindex(vec)
|
||||
if length(vec[i]) > maxLength
|
||||
maxLength = length(vec[i])
|
||||
end
|
||||
end
|
||||
|
||||
return maxLength
|
||||
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
|
||||
function InterpretExplicit!(op::Operator, x, y)
|
||||
index = (blockIdx().x - 1) * blockDim().x + threadIdx().x
|
||||
stride = gridDim().x * blockDim().x
|
||||
|
||||
if op == Add
|
||||
if op == ADD
|
||||
# @cuprintln("Performing Addition") # Will only be displayed when the GPU is synchronized
|
||||
for i = index:stride:length(y)
|
||||
@inbounds y[i] += x[i]
|
||||
end
|
||||
return
|
||||
elseif op == Subtract
|
||||
elseif op == SUBTRACT
|
||||
# @cuprintln("Performing Subtraction") # Will only be displayed when the GPU is synchronized
|
||||
for i = index:stride:length(y)
|
||||
@inbounds y[i] -= x[i]
|
||||
|
|
|
@ -14,18 +14,18 @@ parameters[1][1] = 5
|
|||
@testset "Test conversion expression element" begin
|
||||
reference1 = ExpressionElement(FLOAT64, reinterpret(Int64, 1.0))
|
||||
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(reference2, ExpressionProcessing.convert_to_ExpressionElement(1))
|
||||
@test isequal(reference3, ExpressionProcessing.convert_to_ExpressionElement(Add))
|
||||
@test isequal(reference3, ExpressionProcessing.convert_to_ExpressionElement(ADD))
|
||||
end
|
||||
|
||||
@testset "Test conversion to postfix" begin
|
||||
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),
|
||||
ExpressionProcessing.convert_to_ExpressionElement(Add), ExpressionProcessing.convert_to_ExpressionElement(-1), ExpressionProcessing.convert_to_ExpressionElement(Add)])
|
||||
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)])
|
||||
postfix = expr_to_postfix(expressions[1])
|
||||
|
||||
@test isequal(reference, postfix)
|
||||
|
|
|
@ -1,21 +1,42 @@
|
|||
using CUDA
|
||||
using .ExpressionProcessing
|
||||
using .Interpreter
|
||||
|
||||
expressions = Vector{Expr}(undef, 1)
|
||||
variables = Matrix{Float64}(undef, 1,2)
|
||||
parameters = Vector{Vector{Float64}}(undef, 1)
|
||||
expressions = Vector{Expr}(undef, 2)
|
||||
variables = Matrix{Float64}(undef, 2,2)
|
||||
parameters = Vector{Vector{Float64}}(undef, 2)
|
||||
|
||||
# Resulting value should be 10
|
||||
expressions[1] = :(x1 + 1 * x2 + p1)
|
||||
variables[1,1] = 2
|
||||
variables[1,2] = 3
|
||||
expressions[2] = :(5 + x1 + 1 * x2 + p1 + p2)
|
||||
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][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
|
||||
postfixExpr = expr_to_postfix(expressions[1])
|
||||
postfixExprs = Vector{PostfixType}(undef, 1)
|
||||
postfixExprs[1] = postfixExpr
|
||||
postfixExprs = Vector([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
|
Loading…
Reference in New Issue
Block a user