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 |