Spaces:
Running
Running
# Define a serialization format for the symbolic equations: | |
mutable struct Node | |
#Holds operators, variables, constants in a tree | |
degree::Integer #0 for constant/variable, 1 for cos/sin, 2 for +/* etc. | |
val::Union{Float32, Integer} #Either const value, or enumerates variable | |
constant::Bool #false if variable | |
op::Integer #enumerates operator (separately for degree=1,2) | |
l::Union{Node, Nothing} | |
r::Union{Node, Nothing} | |
Node(val::Float32) = new(0, val, true, 1, nothing, nothing) | |
Node(val::Integer) = new(0, val, false, 1, nothing, nothing) | |
Node(op::Integer, l::Node) = new(1, 0.0f0, false, op, l, nothing) | |
Node(op::Integer, l::Union{Float32, Integer}) = new(1, 0.0f0, false, op, Node(l), nothing) | |
Node(op::Integer, l::Node, r::Node) = new(2, 0.0f0, false, op, l, r) | |
#Allow to pass the leaf value without additional node call: | |
Node(op::Integer, l::Union{Float32, Integer}, r::Node) = new(2, 0.0f0, false, op, Node(l), r) | |
Node(op::Integer, l::Node, r::Union{Float32, Integer}) = new(2, 0.0f0, false, op, l, Node(r)) | |
Node(op::Integer, l::Union{Float32, Integer}, r::Union{Float32, Integer}) = new(2, 0.0f0, false, op, Node(l), Node(r)) | |
end | |
# Copy an equation (faster than deepcopy) | |
function copyNode(tree::Node)::Node | |
if tree.degree == 0 | |
return Node(tree.val) | |
elseif tree.degree == 1 | |
return Node(tree.op, copyNode(tree.l)) | |
else | |
return Node(tree.op, copyNode(tree.l), copyNode(tree.r)) | |
end | |
end | |
# Count the operators, constants, variables in an equation | |
function countNodes(tree::Node)::Integer | |
if tree.degree == 0 | |
return 1 | |
elseif tree.degree == 1 | |
return 1 + countNodes(tree.l) | |
else | |
return 1 + countNodes(tree.l) + countNodes(tree.r) | |
end | |
end | |
# Count the max depth of a tree | |
function countDepth(tree::Node)::Integer | |
if tree.degree == 0 | |
return 1 | |
elseif tree.degree == 1 | |
return 1 + countDepth(tree.l) | |
else | |
return 1 + max(countDepth(tree.l), countDepth(tree.r)) | |
end | |
end | |
# Convert an equation to a string | |
function stringTree(tree::Node)::String | |
if tree.degree == 0 | |
if tree.constant | |
return string(tree.val) | |
else | |
if useVarMap | |
return varMap[tree.val] | |
else | |
return "x$(tree.val - 1)" | |
end | |
end | |
elseif tree.degree == 1 | |
return "$(unaops[tree.op])($(stringTree(tree.l)))" | |
else | |
return "$(binops[tree.op])($(stringTree(tree.l)), $(stringTree(tree.r)))" | |
end | |
end | |
# Print an equation | |
function printTree(tree::Node) | |
println(stringTree(tree)) | |
end | |
# Return a random node from the tree | |
function randomNode(tree::Node)::Node | |
if tree.degree == 0 | |
return tree | |
end | |
a = countNodes(tree) | |
b = 0 | |
c = 0 | |
if tree.degree >= 1 | |
b = countNodes(tree.l) | |
end | |
if tree.degree == 2 | |
c = countNodes(tree.r) | |
end | |
i = rand(1:1+b+c) | |
if i <= b | |
return randomNode(tree.l) | |
elseif i == b + 1 | |
return tree | |
end | |
return randomNode(tree.r) | |
end | |
# Count the number of unary operators in the equation | |
function countUnaryOperators(tree::Node)::Integer | |
if tree.degree == 0 | |
return 0 | |
elseif tree.degree == 1 | |
return 1 + countUnaryOperators(tree.l) | |
else | |
return 0 + countUnaryOperators(tree.l) + countUnaryOperators(tree.r) | |
end | |
end | |
# Count the number of binary operators in the equation | |
function countBinaryOperators(tree::Node)::Integer | |
if tree.degree == 0 | |
return 0 | |
elseif tree.degree == 1 | |
return 0 + countBinaryOperators(tree.l) | |
else | |
return 1 + countBinaryOperators(tree.l) + countBinaryOperators(tree.r) | |
end | |
end | |
# Count the number of operators in the equation | |
function countOperators(tree::Node)::Integer | |
return countUnaryOperators(tree) + countBinaryOperators(tree) | |
end | |
# Count the number of constants in an equation | |
function countConstants(tree::Node)::Integer | |
if tree.degree == 0 | |
return convert(Integer, tree.constant) | |
elseif tree.degree == 1 | |
return 0 + countConstants(tree.l) | |
else | |
return 0 + countConstants(tree.l) + countConstants(tree.r) | |
end | |
end | |
# Get all the constants from a tree | |
function getConstants(tree::Node)::Array{Float32, 1} | |
if tree.degree == 0 | |
if tree.constant | |
return [tree.val] | |
else | |
return Float32[] | |
end | |
elseif tree.degree == 1 | |
return getConstants(tree.l) | |
else | |
both = [getConstants(tree.l), getConstants(tree.r)] | |
return [constant for subtree in both for constant in subtree] | |
end | |
end | |
# Set all the constants inside a tree | |
function setConstants(tree::Node, constants::Array{Float32, 1}) | |
if tree.degree == 0 | |
if tree.constant | |
tree.val = constants[1] | |
end | |
elseif tree.degree == 1 | |
setConstants(tree.l, constants) | |
else | |
numberLeft = countConstants(tree.l) | |
setConstants(tree.l, constants) | |
setConstants(tree.r, constants[numberLeft+1:end]) | |
end | |
end |