static double GetTreeOptimalByAscending(AndOrTree <int> tree, Func <int, int, int> comparer) { var nodeOptions = new int[tree.nodes.Length]; for (int nodeIndex = tree.nodes.Length - 1; nodeIndex >= 0; nodeIndex--) { if (tree.nodes[nodeIndex].childrenIndices.Length == 0) { nodeOptions[nodeIndex] = tree.nodes[nodeIndex].content; } else { if (tree.nodes[nodeIndex].type == NodeType.AND) { nodeOptions[nodeIndex] = tree.nodes[nodeIndex].content + tree.nodes[nodeIndex].childrenIndices .Select(childIndex => nodeOptions[childIndex]) .Aggregate((result, item) => result + item); } else { nodeOptions[nodeIndex] = tree.nodes[nodeIndex].content + tree.nodes[nodeIndex].childrenIndices .Select(childIndex => nodeOptions[childIndex]) .Aggregate((result, item) => comparer(result, item)); } } } return(nodeOptions[0]); }
static AndOrTree <int> GetHardcodedTree() { var tree = new AndOrTree <int>(); tree.nodes = new AndOrTreeNode <int> [10]; tree.nodes[0] = new AndOrTreeNode <int>(-4, new int[] { 1, 2, 3, 4 }, NodeType.OR); tree.nodes[1] = new AndOrTreeNode <int>(4, new int[] { 5, 6, 7, 8, 9 }, NodeType.AND); tree.nodes[2] = new AndOrTreeNode <int>(-8, new int[] { }, NodeType.OR); tree.nodes[3] = new AndOrTreeNode <int>(-6, new int[] { }, NodeType.OR); tree.nodes[4] = new AndOrTreeNode <int>(7, new int[] { }, NodeType.OR); tree.nodes[5] = new AndOrTreeNode <int>(0, new int[] { }, NodeType.OR); tree.nodes[6] = new AndOrTreeNode <int>(6, new int[] { }, NodeType.OR); tree.nodes[7] = new AndOrTreeNode <int>(-1, new int[] { }, NodeType.OR); tree.nodes[8] = new AndOrTreeNode <int>(-4, new int[] { }, NodeType.OR); tree.nodes[9] = new AndOrTreeNode <int>(-9, new int[] { }, NodeType.OR); return(tree); }
public static AndOrTree <ContentType> GetRandomTree( int nodesAmount, int averageChildrenAmount, int childrenAmountRadius, Func <int, ContentType> contentGetter) { Random rnd = new Random(); int nextChildIndex = 1; var tree = new AndOrTree <ContentType>(); tree.nodes = new AndOrTreeNode <ContentType> [nodesAmount]; for (int nodeIndex = 0; nodeIndex != tree.nodes.Length; nodeIndex++) { tree.nodes[nodeIndex] = new AndOrTreeNode <ContentType>(); tree.nodes[nodeIndex].content = contentGetter(nodeIndex); tree.nodes[nodeIndex].type = rnd.Next(2) == 0 ? NodeType.AND : NodeType.OR; int childrenAmount = Math.Min( rnd.Next(averageChildrenAmount - childrenAmountRadius, averageChildrenAmount + childrenAmountRadius + 1), nodesAmount - nextChildIndex ); if (nextChildIndex + childrenAmount == nodesAmount - 1) { childrenAmount++; } tree.nodes[nodeIndex].childrenIndices = new int[childrenAmount]; for (int childIndex = 0; childIndex != tree.nodes[nodeIndex].childrenIndices.Length; childIndex++) { if (nextChildIndex != nodesAmount) { tree.nodes[nodeIndex].childrenIndices[childIndex] = nextChildIndex++; } } } return(tree); }
static void Main(string[] args) { Random rnd = new Random(); var tree = AndOrTree <int> .GetRandomTree(100000, 5, 2, index => rnd.Next(-10, 11)); var treeMax = GetTreeOptimalByAscending(tree, Math.Max); var treeMin = GetTreeOptimalByAscending(tree, Math.Min); var orNodeIndices = tree.GetOrNodeIndices(); int orNodesAmount = orNodeIndices.Count; var orNodeOptionMax = new Dictionary <int, int>(); Func <Dictionary <int, int>, double> fitness1 = (Dictionary <int, int> gen) => { var structure = new List <int>(); var queue = new Queue <int>(); queue.Enqueue(0); while (queue.Count > 0) { int currentNode = queue.Dequeue(); structure.Add(currentNode); if (tree.nodes[currentNode].childrenIndices.Length > 0) { if (tree.nodes[currentNode].type == NodeType.AND) { foreach (var childIndex in tree.nodes[currentNode].childrenIndices) { queue.Enqueue(childIndex); } } else { queue.Enqueue(tree.nodes[currentNode].childrenIndices[gen[currentNode]]); } } } return(structure.Aggregate(0, (sum, node) => sum + tree.nodes[node].content)); }; Func <Dictionary <int, int> > generate1 = () => { var gen = new Dictionary <int, int>(); orNodeIndices.ForEach(index => gen.Add(index, rnd.Next(tree.nodes[index].childrenIndices.Length))); return(gen); }; Func <Dictionary <int, int>, Dictionary <int, int>, Dictionary <int, int> > cross1 = (Dictionary <int, int> gen1, Dictionary <int, int> gen2) => { var gen = new Dictionary <int, int>(); for (int i = 0; i != orNodesAmount; i++) { int key = orNodeIndices[i]; gen.Add(key, rnd.Next(2) == 0 ? gen1[key] : gen2[key]); } return(gen); }; Action <Dictionary <int, int> > mutate1 = (Dictionary <int, int> sourceGen) => { int[] keys = sourceGen.Keys.ToArray(); for (int i = 0; i != orNodesAmount; i++) { if (rnd.Next(10) > 8) { int key = keys[i]; sourceGen[key] = rnd.Next(tree.nodes[key].childrenIndices.Length); } } }; double scope = treeMax - treeMin; Func <double, bool> stop1 = (double result) => { return((treeMax - result) / scope < 0.05); }; Action <int, double, List <Dictionary <int, int> > > logger1 = (int generationNumber, double result, List <Dictionary <int, int> > generation) => { var mistake = (treeMax - result) / scope; var evaluations = generation.Select(gen => fitness1(gen)).ToList(); int segmentAmount = 10; double segmentSize = (treeMax - treeMin) / segmentAmount; string info = ""; var histogram = new List <double>(); for (int i = 0; i != segmentAmount; i++) { var begin = treeMin + segmentSize * i; var end = begin + segmentSize + ((i == segmentAmount - 1) ? 1 : 0); histogram.Add(Math.Round((double)evaluations.Where(e => e >= begin && e < end).Count() / evaluations.Count() * 10000) / 100); info += histogram.Last() + "% "; } var sum = Math.Round(histogram.Sum() * 10000) / 10000; info += $" (sum is {sum}) "; Console.WriteLine($"{generationNumber}: {info}-> {Convert.ToInt32(mistake * 100)}%"); }; var geneticSolver = new GeneticSolver <Dictionary <int, int> >(fitness1, generate1, cross1, mutate1, stop1, logger1); var gen = geneticSolver.Solve(10000, 1, (Dictionary <int, int> source) => new Dictionary <int, int>(source)); var result = fitness1(gen); Console.WriteLine("Result: " + result); Console.WriteLine("Best: " + treeMax); Console.WriteLine("Worst: " + treeMin); double mistake = (treeMax - result) / scope; Console.WriteLine("Mistake: " + Convert.ToInt32(mistake * 100) + "%"); Console.ReadKey(); }