Spaces:
Sleeping
Sleeping
# Randomly convert an operator into another one (binary->binary; | |
# unary->unary) | |
function mutateOperator(tree::Node)::Node | |
if countOperators(tree) == 0 | |
return tree | |
end | |
node = randomNode(tree) | |
while node.degree == 0 | |
node = randomNode(tree) | |
end | |
if node.degree == 1 | |
node.op = rand(1:length(unaops)) | |
else | |
node.op = rand(1:length(binops)) | |
end | |
return tree | |
end | |
# Randomly perturb a constant | |
function mutateConstant( | |
tree::Node, T::Float32, | |
probNegate::Float32=0.01f0)::Node | |
# T is between 0 and 1. | |
if countConstants(tree) == 0 | |
return tree | |
end | |
node = randomNode(tree) | |
while node.degree != 0 || node.constant == false | |
node = randomNode(tree) | |
end | |
bottom = 0.1f0 | |
maxChange = perturbationFactor * T + 1.0f0 + bottom | |
factor = maxChange^Float32(rand()) | |
makeConstBigger = rand() > 0.5 | |
if makeConstBigger | |
node.val *= factor | |
else | |
node.val /= factor | |
end | |
if rand() > probNegate | |
node.val *= -1 | |
end | |
return tree | |
end | |
# Add a random unary/binary operation to the end of a tree | |
function appendRandomOp(tree::Node)::Node | |
node = randomNode(tree) | |
while node.degree != 0 | |
node = randomNode(tree) | |
end | |
choice = rand() | |
makeNewBinOp = choice < nbin/nops | |
if rand() > 0.5 | |
left = Float32(randn()) | |
else | |
left = rand(1:nvar) | |
end | |
if rand() > 0.5 | |
right = Float32(randn()) | |
else | |
right = rand(1:nvar) | |
end | |
if makeNewBinOp | |
newnode = Node( | |
rand(1:length(binops)), | |
left, | |
right | |
) | |
else | |
newnode = Node( | |
rand(1:length(unaops)), | |
left | |
) | |
end | |
node.l = newnode.l | |
node.r = newnode.r | |
node.op = newnode.op | |
node.degree = newnode.degree | |
node.val = newnode.val | |
node.constant = newnode.constant | |
return tree | |
end | |
# Insert random node | |
function insertRandomOp(tree::Node)::Node | |
node = randomNode(tree) | |
choice = rand() | |
makeNewBinOp = choice < nbin/nops | |
left = copyNode(node) | |
if makeNewBinOp | |
right = randomConstantNode() | |
newnode = Node( | |
rand(1:length(binops)), | |
left, | |
right | |
) | |
else | |
newnode = Node( | |
rand(1:length(unaops)), | |
left | |
) | |
end | |
node.l = newnode.l | |
node.r = newnode.r | |
node.op = newnode.op | |
node.degree = newnode.degree | |
node.val = newnode.val | |
node.constant = newnode.constant | |
return tree | |
end | |
# Add random node to the top of a tree | |
function prependRandomOp(tree::Node)::Node | |
node = tree | |
choice = rand() | |
makeNewBinOp = choice < nbin/nops | |
left = copyNode(tree) | |
if makeNewBinOp | |
right = randomConstantNode() | |
newnode = Node( | |
rand(1:length(binops)), | |
left, | |
right | |
) | |
else | |
newnode = Node( | |
rand(1:length(unaops)), | |
left | |
) | |
end | |
node.l = newnode.l | |
node.r = newnode.r | |
node.op = newnode.op | |
node.degree = newnode.degree | |
node.val = newnode.val | |
node.constant = newnode.constant | |
return node | |
end | |
function randomConstantNode()::Node | |
if rand() > 0.5 | |
val = Float32(randn()) | |
else | |
val = rand(1:nvar) | |
end | |
newnode = Node(val) | |
return newnode | |
end | |
# Return a random node from the tree with parent | |
function randomNodeAndParent(tree::Node, parent::Union{Node, Nothing})::Tuple{Node, Union{Node, Nothing}} | |
if tree.degree == 0 | |
return tree, parent | |
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 randomNodeAndParent(tree.l, tree) | |
elseif i == b + 1 | |
return tree, parent | |
end | |
return randomNodeAndParent(tree.r, tree) | |
end | |
# Select a random node, and replace it an the subtree | |
# with a variable or constant | |
function deleteRandomOp(tree::Node)::Node | |
node, parent = randomNodeAndParent(tree, nothing) | |
isroot = (parent === nothing) | |
if node.degree == 0 | |
# Replace with new constant | |
newnode = randomConstantNode() | |
node.l = newnode.l | |
node.r = newnode.r | |
node.op = newnode.op | |
node.degree = newnode.degree | |
node.val = newnode.val | |
node.constant = newnode.constant | |
elseif node.degree == 1 | |
# Join one of the children with the parent | |
if isroot | |
return node.l | |
elseif parent.l == node | |
parent.l = node.l | |
else | |
parent.r = node.l | |
end | |
else | |
# Join one of the children with the parent | |
if rand() < 0.5 | |
if isroot | |
return node.l | |
elseif parent.l == node | |
parent.l = node.l | |
else | |
parent.r = node.l | |
end | |
else | |
if isroot | |
return node.r | |
elseif parent.l == node | |
parent.l = node.r | |
else | |
parent.r = node.r | |
end | |
end | |
end | |
return tree | |
end | |
# Create a random equation by appending random operators | |
function genRandomTree(length::Integer)::Node | |
tree = Node(1.0f0) | |
for i=1:length | |
tree = appendRandomOp(tree) | |
end | |
return tree | |
end |