// Keep in mind that Mutation is more about structure than 'variations' of multiples and constants. private (IGene Root, string Origin) MutateUnfrozen(EvalGenome <bool> target) { /* Possible mutations: * 1) Adding a parameter node to an operation. * 2) Apply a function to node. * 3) Adding an operator and a parameter node. * 4) Removing a node from an operation. * 5) Removing an operation. * 6) Removing a function. */ var genes = Catalog.Factory.Map(target.Root); while (genes.Any()) { var gene = genes .GetNodes() .ToArray() .RandomSelectOne() as Node <IGene> ?? throw new InvalidCastException("Expected a Node<IGene."); var gv = gene.Value; switch (gv) { // ReSharper disable once RedundantEmptySwitchSection default: break; } } return(null, null); }
public new EvalGenome <T> Clone() { #if DEBUG var clone = new EvalGenome <T>(Root); clone.AddLogEntry("Origin", "Cloned"); return(clone); #else return(new EvalGenome <T>(Root)); #endif }
protected override EvalGenome <double> MutateInternal(EvalGenome <double> target) { var(root, origin) = MutateUnfrozen(target); return(root == null ? null : Registration(root, ($"Mutation > {origin}", target.Hash))); }
// Keep in mind that Mutation is more about structure than 'variations' of multiples and constants. private (IGene Root, string Origin) MutateUnfrozen(EvalGenome <double> target) { /* Possible mutations: * 1) Adding a parameter node to an operation. * 2) Apply a function to node. * 3) Adding an operator and a parameter node. * 4) Removing a node from an operation. * 5) Removing an operation. * 6) Removing a function. */ var genes = Catalog.Factory.Map(target.Root); while (genes.Any()) { var gene = genes .GetNodes() .ToArray() .RandomSelectOne() as Node <IGene> ?? throw new InvalidCastException("Expected a Node<IGene."); var gv = gene.Value; switch (gv) { case Constant <double> c: switch (RandomUtilities.Random.Next(10)) { case 0: // This is a bit controversial since it can bloat constant values. return(Catalog.Variation.ApplyRandomFunction(gene), "Apply function to constant"); case 3: return(Catalog.Mutation.MutateSign(gene, 1), "Mutate sign of constant"); case 4: case 5: if (gene.Parent?.Value is Exponent <double> exponent && exponent.Power == gv) { goto case 6; } goto default; case 6: var a = Math.Abs(c.Value); return((a > 0 && a < 1) // Look for fractional exponents and avoid. ? Catalog.ApplyClone(gene, newNode => Catalog.GetConstant(c.Value > 0 ? 1 : -1)) // should be rare (1/10) chance to increase multiple for non power of exponents. : Catalog.AdjustNodeMultiple(gene, c.Value < 0 ? -1 : +1), "Increase constant"); default: if (gene.Parent?.Value is Exponent <double> ) { return(Catalog.AdjustNodeMultiple(gene, c.Value > 0 ? -1 : +1), "Decrease constant"); } if (Catalog.Variation.TryRemoveValid(gene, out var newRoot)) { return(newRoot, "Remove constant"); } break; } break; case Parameter _: { var options = Enumerable.Range(0, 5).ToList(); while (options.Any()) { switch (options.RandomPluck()) { case 0: return(Catalog.Mutation.MutateSign(gene, 1), "Mutate sign"); // Simply change parameters case 1: return(Catalog.Mutation.MutateParameter(gene), "Mutate parameter"); // Apply a function case 2: return(Catalog.Variation.ApplyRandomFunction(gene), "Apply random function to paramter"); // Favor squaring... case 3: return(Catalog.Mutation.Square(gene), "Apply random function to paramter"); //// Split it... //case 3: // if (RandomUtilities.Random.Next(0, 2) == 0) // return (Catalog.Mutation.Square(gene), // "Square parameter"); // break; // Remove it! default: if (Catalog.Variation.TryRemoveValid(gene, out var attempt)) { return(attempt, "Remove descendant"); } break; } } } break; default: if (gv is IFunction) { var options = Enumerable.Range(0, 8).ToList(); while (options.Any()) { (IGene Root, string Origin)ng = default; switch (options.RandomPluck()) { case 0 when gv is IOperator: ng = (Catalog.Mutation.MutateSign(gene, 1), "Mutate sign of function"); break; case 1 when gv is IOperator: ng = (Catalog.Variation.PromoteChildren(gene), "Promote decendant children of function"); break; case 2 when gv is IOperator: ng = (Catalog.Mutation.ChangeOperation(gene), "Change operation"); break; case 3: // Reduce the pollution of functions... if (RandomUtilities.Random.Next(0, gv is IOperator ? 2 : 4) == 0) { //var f = Open.Evaluation.Registry.Arithmetic.Functions.RandomSelectOne(); //// Function of function? Reduce probability even further. Coin toss. //if (f.GetType() != gene.GetType() || RandomUtilities.Random.Next(2) == 0) var f = Open.Evaluation.Registry.Arithmetic.GetRandomFunction(Catalog, gv); Debug.Assert(f != null); return(f, "Apply function to function"); } break; case 4: if (Catalog.Variation.TryRemoveValid(gene, out var n)) { ng = (n, "Remove decendant function"); } break; case 5: ng = (Catalog.Mutation.AddParameter(gene), "Add parameter to function"); break; case 6: ng = (Catalog.Mutation.BranchOperation(gene), "Branch operation"); break; case 7: // This has a potential to really bloat the function so allow, but very sparingly. if (RandomUtilities.Random.Next(0, 3) == 0) { return(Catalog.Mutation.Square(gene), "Square function"); } break; } if (ng.Root != null) { return(ng); } } } break; } } return(null, null); }
protected override EvalGenome <T> GenerateOneInternal() { // ReSharper disable once NotAccessedVariable var attempts = 0; // For debugging. EvalGenome <T> genome = null; for (byte m = 1; m < 26; m++) // The 26 effectively represents the max parameter depth. { // Establish a maximum. var tries = 10; ushort paramCount = 0; do { if (ParamsOnlyAttempted.Add(paramCount)) { // Try a param only version first. genome = GenerateParamOnly(paramCount); attempts++; if (!AlreadyProduced(genome)) { return(genome); } } paramCount += 1; // Operators need at least 2 params to start. // Then try an operator based version. var pcOne = paramCount; var operated = OperatedCatalog.GetOrAdd(++pcOne, pc => { var e = GenerateOperated(pc)?.GetEnumerator(); Debug.Assert(e != null); return(e); }); if (operated.ConcurrentTryMoveNext(out genome)) { Debug.Assert(genome != null); attempts++; if (!AlreadyProduced(genome)) // May be supurfulous. { return(genome); } } pcOne = paramCount; var functioned = FunctionedCatalog.GetOrAdd(--pcOne, pc => GenerateFunctioned(pc).GetEnumerator()); // ReSharper disable once InvertIf if (functioned.MoveNext()) { genome = functioned.Current; Debug.Assert(genome != null); attempts++; if (!AlreadyProduced(genome)) // May be supurfulous. { return(genome); } } } while (--tries != 0); } return(genome); }