public StackMachine(AptNode node) { nodeCount = node.Count(); instructions = new Instruction[nodeCount]; inPtr = 0; BuildInstructions(node); }
public static void BreedingSelf(GraphicsDevice g, GameWindow w) { const int TEST_SIZE = 500; Random r = new Random(); var results = new List <float>(1024); Console.WriteLine("start opt test"); for (int i = 0; i < TEST_SIZE; i++) { Console.WriteLine(i); var treeA = AptNode.GenerateTree(r.Next(1, 20), r, true); var childTree = treeA.BreedWith(treeA, r, true); var machine = new StackMachine(childTree); var stack = new float[machine.nodeCount]; for (float y = -1.0f; y <= 1.0f; y += .005f) { for (float x = -1.0f; x <= 1.0f; x += .005f) { results.Add(machine.Execute(x, y, stack)); } } Console.WriteLine("result[2]" + results[2]); results.Clear(); } Console.WriteLine("done breed test"); }
public void RebuildInstructions(AptNode node) { nodeCount = node.Count(); instructions = new Instruction[nodeCount]; inPtr = 0; BuildInstructions(node); }
public AptNode BreedWith(AptNode partner, Random r, bool video) { var(newNode, _) = partner.GetNthNode(r.Next(0, partner.Count())); var(nodeToReplace, _) = this.GetNthNode(r.Next(0, this.Count())); //TODO - this prevents things from getting screwed up by warp nodes // But maybe we could allow crossover at warp nodes if we think of a clean way to handle it if (newNode.type == NodeType.WARP1 || nodeToReplace.type == NodeType.WARP1) { return(nodeToReplace); } newNode.parent = nodeToReplace.parent; if (newNode.parent != null) { for (int i = 0; i < newNode.parent.children.Length; i++) { if (newNode.parent.children[i] == nodeToReplace) { newNode.parent.children[i] = newNode; } } return(null); } else { return(newNode); } }
public (AptNode, int) GetNthNode(int n) { if (n == 0) { return(this, n); } AptNode node = new AptNode { type = NodeType.EMPTY }; if (children != null) { foreach (var child in children) { (node, n) = child.GetNthNode(n - 1); if (node.type != NodeType.EMPTY) { return(node, n); } } } return(new AptNode { type = NodeType.EMPTY }, n); }
public void BuildInstructions(AptNode node) { if (node.children != null) { for (int i = node.children.Length - 1; i >= 0; i--) { BuildInstructions(node.children[i]); } } switch (node.type) { case NodeType.EMPTY: throw new Exception("can't BuildInstructions with a non finished APT"); case NodeType.CONSTANT: case NodeType.PICTURE: instructions[inPtr] = new Instruction { type = node.type, value = node.value }; inPtr++; break; default: instructions[inPtr] = new Instruction { type = node.type }; inPtr++; break; } }
public static float Evaluate(AptNode node, float x, float y, float t) { StackMachine m = new StackMachine(node); var stack = new float[m.nodeCount]; return(m.Execute(x, y, t, stack)); }
public void Optimize() { for (int i = 0; i < Trees.Length; i++) { Trees[i] = AptNode.ConstantFolding(Trees[i]); Machines[i] = new StackMachine(Trees[i]); } }
public AptNode ShallowClone() { AptNode result = new AptNode { }; result.type = type; result.value = value; result.filename = filename; return(result); }
public AptNode ParseNodes() { var t = ParseExpect(new[] { TokenType.OPEN_PAREN, TokenType.CONSTANT, TokenType.VARIABLE }); if (t.type == TokenType.VARIABLE) { var s = input.Slice(t.start, t.len).ToString().ToLower(); return(stringToNode(s, t)); } else if (t.type == TokenType.CONSTANT) { var result = new AptNode { type = NodeType.CONSTANT }; string numStr = input.Slice(t.start, t.len).ToString(); result.value = float.Parse(numStr); return(result); } else { t = ParseExpect(TokenType.OP); var s = input.Slice(t.start, t.len).ToString().ToLower(); var result = stringToNode(s, t); if (result.type == NodeType.PICTURE) { var filenameToken = ParseExpect(TokenType.STRING); result.filename = input.Slice(filenameToken.start, filenameToken.len).ToString(); } int warpCount = 0; for (int i = 0; i < result.children.Length; i++) { result.children[i - warpCount] = ParseNodes(); result.children[i - warpCount].parent = result; // warp returns two values, so it is a special case if (result.children[i - warpCount].type == NodeType.WARP1) { warpCount++; i++; } } if (warpCount > 0) { var newChildren = new AptNode[result.children.Length - warpCount]; for (int i = 0; i < newChildren.Length; i++) { newChildren[i] = result.children[i]; } result.children = newChildren; } ParseExpect(TokenType.CLOSE_PAREN); return(result); } }
//todo both same completely? //todo can pic work here? public static bool BothSameVariables(AptNode a, AptNode b) { switch (a.type) { case NodeType.X: case NodeType.Y: case NodeType.T: return(a.type == b.type); } return(false); }
public AptNode stringToNode(string s, Token t) { NodeType type; if (nodeDict.TryGetValue(s, out type)) { return(AptNode.MakeNode(type)); } else { throw new ParseException("invalid name:" + s, t); } }
// Note: assumes you are adding to a non leaf node, always public void AddRandom(AptNode nodeToAdd, Random r) { var addIndex = r.Next(this.children.Length); if (children[addIndex] == null || children[addIndex].type == NodeType.EMPTY) { children[addIndex] = nodeToAdd; nodeToAdd.parent = this; } else { children[addIndex].AddRandom(nodeToAdd, r); } }
private void BuildInstructions(AptNode node) { if (node.children != null) { for (int i = node.children.Length - 1; i >= 0; i--) { BuildInstructions(node.children[i]); } } switch (node.type) { case NodeType.EMPTY: throw new Exception("can't BuildInstructions with a non finished APT"); case NodeType.CONSTANT: instructions[inPtr] = new Instruction { type = node.type, value = node.value }; inPtr++; break; case NodeType.PICTURE: var value = -1; for (int i = 0; i < GameState.externalImages.Count; i++) { var filename = GameState.externalImages[i].filename; if (filename.Equals(node.filename)) { value = i; break; } } if (value == -1) { throw new Exception("picture string invalid"); } instructions[inPtr] = new Instruction { type = node.type, value = value }; inPtr++; break; default: instructions[inPtr] = new Instruction { type = node.type }; inPtr++; break; } }
public AptNode Mutate(Random r, bool video) { var nodeIndex = r.Next(0, Count()); var(nodeToMutate, _) = GetNthNode(nodeIndex); var leafChance = r.Next(0, Settings.MUTATE_LEAF_CHANCE); AptNode newNode; if (leafChance == 0) { newNode = GetRandomLeaf(r, video); } else { newNode = GetRandomNode(r); } newNode.parent = nodeToMutate.parent; if (nodeToMutate.children != null && newNode.children != null) { for (int i = 0; i < nodeToMutate.children.Length; i++) { if (i == newNode.children.Length) { break; } newNode.children[i] = nodeToMutate.children[i]; newNode.children[i].parent = newNode; } } while (newNode.AddLeaf(AptNode.GetRandomLeaf(r, video))) { } if (newNode.parent != null) { for (int i = 0; i < newNode.parent.children.Length; i++) { if (newNode.parent.children[i] == nodeToMutate) { newNode.parent.children[i] = newNode; } } return(null); } else { return(newNode); } }
public void InsertWarp(Random r, bool video) { var node = this; if (node.children == null) { return; } //1 in 3 chance of applying warp to a node that has an X and a Y as children if (node.children.Length >= 2 && r.Next(0, 3) == 0 && ((node.children[0].type == NodeType.X && node.children[1].type == NodeType.Y) || (node.children[1].type == NodeType.X && node.children[0].type == NodeType.Y))) { var newChildren = new AptNode[node.children.Length - 1]; var warp = MakeNode(NodeType.WARP1); warp.children[0] = new AptNode { type = NodeType.X }; warp.children[0].parent = warp; warp.children[1] = new AptNode { type = NodeType.Y }; warp.children[1].parent = warp; warp.children[4] = new AptNode { type = NodeType.CONSTANT, value = (float)r.NextDouble() * 2.0f - 1.0f }; warp.children[4].parent = warp; //fill in the stuff the warp node needs while (warp.AddLeaf(GetRandomLeaf(r, video))) { } newChildren[0] = warp; warp.parent = node; for (int i = 1; i < newChildren.Length; i++) { newChildren[i] = node.children[i + 1]; } node.children = newChildren; } else { foreach (var child in node.children) { child.InsertWarp(r, video); } } }
public AptNode Clone() { AptNode result = ShallowClone(); if (children != null) { result.children = new AptNode[children.Length]; for (int i = 0; i < children.Length; i++) { result.children[i] = children[i].Clone(); result.children[i].parent = result; } } return(result); }
public Lexer(string s) { input = s.AsSpan(); tokens = new Queue <Token>(8); nodeDict = new Dictionary <string, NodeType>(); start = 0; pos = 0; foreach (var typeObj in Enum.GetValues(typeof(NodeType))) { var type = (NodeType)typeObj; if (type != NodeType.EMPTY && type != NodeType.CONSTANT) { nodeDict.Add(AptNode.OpString(type).ToLower(), type); } } }
public static AptNode GenerateTree(int nodeCount, Random r, bool video) { AptNode first = GetRandomNode(r); for (int i = 1; i < nodeCount; i++) { first.AddRandom(GetRandomNode(r), r); } while (first.AddLeaf(GetRandomLeaf(r, video))) { //just keep adding leaves until we can't } ; first.InsertWarp(r, video); first = ConstantFolding(first); return(first); }
public bool AddLeaf(AptNode leafToAdd) { if (children == null) { return(false); } for (int i = 0; i < children.Length; i++) { if (children[i] == null || children[i].IsEmpty()) { children[i] = leafToAdd; leafToAdd.parent = this; return(true); } else if (!children[i].IsLeaf() && children[i].AddLeaf(leafToAdd)) { return(true); } } return(false); }
public static void Optimizing(GraphicsDevice g, GameWindow w) { const int TEST_SIZE = 10000; Random r = new Random(); Console.WriteLine("start opt test"); for (int i = 0; i < TEST_SIZE; i++) { Console.WriteLine(i); var tree = AptNode.GenerateTree(r.Next(1, 20), r, true); var machine = new StackMachine(tree); var optTree = AptNode.ConstantFolding(tree); var optMachine = new StackMachine(optTree); var stack = new float[machine.nodeCount]; var optStack = new float[optMachine.nodeCount]; for (float y = -1.0f; y <= 1.0f; y += .01f) { for (float x = -1.0f; x <= 1.0f; x += .01f) { float result = machine.Execute(x, y, stack); float optResult = optMachine.Execute(x, y, optStack); if (Math.Abs(optResult - result) > .01f) { Console.WriteLine("result:" + result); Console.WriteLine("optResult:" + optResult); Console.WriteLine("x:" + x + "y:" + y); Console.WriteLine("--- tree --"); Console.WriteLine(tree.ToLisp()); Console.WriteLine("--- optTree --"); Console.WriteLine(optTree.ToLisp()); throw new Exception("opt fail"); } } } } Console.WriteLine("done opt test"); }
public static AptNode GetRandomLeaf(Random r, bool videoMode) { var picChance = r.Next(0, 3); NodeType type; //We start at 2 because 0 is EMPTY and 1 is Time for videos only int start = 2; if (videoMode) { start = 1; } if (picChance == 0) { type = (NodeType)r.Next(start, NUM_LEAF_TYPES); } else { type = (NodeType)r.Next(start, NUM_LEAF_TYPES - 1); } switch (type) { case NodeType.PICTURE: { var pic = GameState.externalImages[r.Next(0, GameState.externalImages.Count)]; var result = new AptNode { type = type, children = new AptNode[2], filename = pic.filename }; result.children[0] = new AptNode { type = NodeType.X }; result.children[1] = new AptNode { type = NodeType.Y }; return(result); } case NodeType.CONSTANT: { var c = new AptNode { type = type, value = (float)r.NextDouble() * 2.0f - 1.0f }; if (!videoMode) { return(c); } // In video mode we will go with fewer constants and more Time else { int half = r.Next(0, 4); if (half == 0) { return(c); } else { int chooser = r.Next(0, 3); if (chooser == 0) { return new AptNode { type = NodeType.T } } ; else if (chooser == 1) { return new AptNode { type = NodeType.X } } ; else { return new AptNode { type = NodeType.Y } }; } } } default: return(new AptNode { type = type }); } }
public Pic(PicType type, Random rand, int min, int max, GraphicsDevice g, GameWindow w, bool video, GameState state) { this.video = video; SharedConstructor(type, g, w, state); for (int i = 0; i < Trees.Length; i++) { Trees[i] = AptNode.GenerateTree(rand.Next(min, max), rand, video); Machines[i] = new StackMachine(Trees[i]); } if (type == PicType.GRADIENT) { var enum_size = Enum.GetNames(typeof(GradientType)).Length; var gradType = (GradientType)rand.Next(0, enum_size); float[] hues; switch (gradType) { case GradientType.ANALOGOUS: { hues = new float[3]; (hues[0], hues[1], hues[2]) = GetAnalogousHues((float)rand.NextDouble()); break; } case GradientType.COMPLEMENTARY: { hues = new float[2]; (hues[0], hues[1]) = GetComplementaryHues((float)rand.NextDouble()); break; } case GradientType.SPLIT_COMPLEMENTARY: { hues = new float[3]; (hues[0], hues[1], hues[2]) = GetSplitComplementaryHues((float)rand.NextDouble()); break; } case GradientType.SQUARE: { hues = new float[4]; (hues[0], hues[1], hues[2], hues[3]) = GetSquareHues((float)rand.NextDouble()); break; } case GradientType.TETRADIC: { hues = new float[4]; (hues[0], hues[1], hues[2], hues[3]) = GetTetradicHues((float)rand.NextDouble()); break; } case GradientType.TRIADIC: { hues = new float[3]; (hues[0], hues[1], hues[2]) = GetTriadicHues((float)rand.NextDouble()); break; } case GradientType.RANDOM: { hues = new float[rand.Next(Settings.MIN_GRADIENTS, Settings.MAX_GRADIENTS)]; for (int i = 0; i < hues.Length; i++) { hues[i] = (float)rand.NextDouble(); } break; } case GradientType.DOUBLE_COMPLEMENT: { hues = new float[4]; (hues[0], hues[1], hues[2], hues[3]) = GetTetradicHues((float)rand.NextDouble()); break; } case GradientType.DIAD: { hues = new float[2]; (hues[0], hues[1]) = GetComplementaryHues((float)rand.NextDouble()); break; } default: throw new Exception("hues broke"); } colors = hues.SelectF(h => { float s = (float)rand.NextDouble(); float v = (float)rand.NextDouble(); var(red, green, blue) = HSV2RGB(h, s, v); return(new Color(red, green, blue)); }); pos = new float[colors.Length]; int chance = Settings.STOP_GRADIENT_CHANCE * pos.Length; for (int i = 0; i < colors.Length; i++) { if (i > 0 && rand.Next(0, chance) == 0) { pos[i] = pos[i - 1]; } else { pos[i] = (float)(rand.NextDouble() * 2.0 - 1.0); } } Array.Sort(pos); } SetupTextbox(); }
public Pic BreedWith(Pic partner, Random r, GameState state) { var result = Clone(state); var partnerClone = partner.Clone(state); if (result.type != partner.type && r.Next(0, Settings.CROSSOVER_ROOT_CHANCE) == 0) { //Not gradient -> gradient if (partner.type == PicType.GRADIENT) { result.pos = new float[partner.pos.Length]; Array.Copy(partner.pos, result.pos, partner.pos.Length); result.colors = new Color[partner.colors.Length]; Array.Copy(partner.colors, result.colors, partner.colors.Length); var newMachines = new StackMachine[1]; var newTrees = new AptNode[1]; var(tree, machine) = result.GetRandomTree(r); newTrees[0] = tree.Clone(); newMachines[0] = new StackMachine(newTrees[0]); result.Machines = newMachines; result.Trees = newTrees; } //Gradient -> not gradient else if (result.type == PicType.GRADIENT) { result.pos = null; result.colors = null; var newMachines = new StackMachine[3]; var newTrees = new AptNode[3]; var i = r.Next(0, newTrees.Length); newTrees[i] = result.Trees[0].Clone(); newMachines[i] = new StackMachine(newTrees[i]); for (i = 0; i < newTrees.Length; i++) { if (newTrees[i] == null) { newTrees[i] = AptNode.GetRandomLeaf(r, video); newMachines[i] = new StackMachine(newTrees[i]); } } result.Trees = newTrees; result.Machines = newMachines; } result.type = partner.type; return(result); } else { var(ft, fs) = result.GetRandomTree(r); var(st, ss) = partnerClone.GetRandomTree(r); var rootBred = ft.BreedWith(st, r, video); if (rootBred != null) { for (int i = 0; i < result.Trees.Length; i++) { if (result.Trees[i] == ft) { result.Trees[i] = rootBred; } } } return(result); } }
public static AptNode MakeNode(NodeType type) { AptNode result; switch (type) { case NodeType.FBM: case NodeType.BILLOW: case NodeType.CELL1: case NodeType.IF: result = new AptNode { type = type, children = new AptNode[3] }; break; case NodeType.ADD: case NodeType.SUB: case NodeType.MUL: case NodeType.DIV: case NodeType.ATAN2: case NodeType.MIN: case NodeType.MAX: case NodeType.MOD: result = new AptNode { type = type, children = new AptNode[2] }; break; case NodeType.SIN: case NodeType.COS: case NodeType.ATAN: case NodeType.SQUARE: case NodeType.LOG: case NodeType.FLOOR: case NodeType.CEIL: case NodeType.SQRT: case NodeType.ABS: case NodeType.NEGATE: case NodeType.CLAMP: case NodeType.WRAP: result = new AptNode { type = type, children = new AptNode[1] }; break; case NodeType.X: case NodeType.Y: case NodeType.T: result = new AptNode { type = type }; break; case NodeType.PICTURE: result = new AptNode { type = type, children = new AptNode[2] }; break; case NodeType.WARP1: result = new AptNode { type = type, children = new AptNode[5] }; break; default: throw new Exception("MakeNode failed to match the switch"); } return(result); }
public static AptNode ConstantFolding(AptNode node) { var clone = node.ShallowClone(); if (node.children != null) { clone.children = new AptNode[node.children.Length]; } switch (node.type) { case NodeType.X: case NodeType.T: case NodeType.Y: case NodeType.CONSTANT: return(clone); } // if all are constants, return the evaluation of the constant bool allConstants = true; for (int i = 0; i < node.children.Length; i++) { clone.children[i] = ConstantFolding(node.children[i]); if (clone.children[i].type != NodeType.CONSTANT) { allConstants = false; } } if (allConstants) { var v = Evaluate(clone, 0, 0, 0); return(new AptNode { type = NodeType.CONSTANT, value = v }); } // Deal with constants of 1 or 0 on 1 side if (clone.children.Length == 2) { for (int i = 0; i < 2; i++) { if (clone.children[i].type == NodeType.CONSTANT) { var constNode = clone.children[i]; var otherNode = clone.children[(i + 1) % 2]; if (clone.type == NodeType.MUL) { if (constNode.value == 1.0f) { return(otherNode); } if (constNode.value == 0.0f) { return new AptNode { type = NodeType.CONSTANT, value = 0.0f } } ; } else if (clone.type == NodeType.ADD) { if (constNode.value == 0.0f) { return(otherNode); } } } } if (clone.type == NodeType.MUL) { if (BothSameVariables(clone.children[0], clone.children[1])) { var square = new AptNode { type = NodeType.SQUARE, children = new AptNode[1] }; square.children[0] = clone.children[0]; //dont return yet because SQUARE nodes are subject to more opts clone = square; } } if (clone.type == NodeType.DIV) { if (BothSameVariables(clone.children[0], clone.children[1])) { return(new AptNode { type = NodeType.CONSTANT, value = 1.0f }); } } if (clone.type == NodeType.SUB) { if (BothSameVariables(clone.children[0], clone.children[1])) { return(new AptNode { type = NodeType.CONSTANT, value = 0.0f }); } } // Min or Max of the same things = the thing if (clone.type == NodeType.MIN || clone.type == NodeType.MAX) { if (BothSameVariables(clone.children[0], clone.children[1])) { return(clone.children[0]); } } } //abs of abs is redunant //abs of square is redundant if (clone.type == NodeType.ABS && (clone.children[0].type == NodeType.ABS || clone.children[0].type == NodeType.SQUARE)) { return(clone.children[0]); } //negate twice is the thing again if (clone.type == NodeType.NEGATE && clone.children[0].type == NodeType.NEGATE) { return(clone.children[0].children[0]); } //wrap and clamp in a row is redundant if (clone.type == NodeType.WRAP || clone.type == NodeType.CLAMP) { //X/Y/T need not be wrapped or clamped if (BothSameVariables(clone.children[0], clone.children[0])) { return(clone.children[0]); } //Pictures need not be wrapped or clamped if (clone.children[0].type == NodeType.PICTURE) { return(clone.children[0]); } //FBM need not be wrapped or clamped if (clone.children[0].type == NodeType.FBM) { return(clone.children[0]); } //Billow need not be wrapped or clamped if (clone.children[0].type == NodeType.BILLOW) { return(clone.children[0]); } //Cell need not be wrapped or clamped if (clone.children[0].type == NodeType.CELL1) { return(clone.children[0]); } if (clone.children[0].type == NodeType.WRAP || clone.children[0].type == NodeType.CLAMP) { return(clone.children[0]); } } if (clone.type == NodeType.SQRT && clone.children[0].type == NodeType.SQUARE) { var n = clone.children[0].children[0]; var abs = MakeNode(NodeType.ABS); abs.children[0] = n; return(abs); } if (clone.type == NodeType.SQUARE && clone.children[0].type == NodeType.SQRT) { var n = clone.children[0].children[0]; var abs = MakeNode(NodeType.ABS); abs.children[0] = n; return(abs); } //if the if condition is constant, or both choices are same, fold it away if (clone.type == NodeType.IF && clone.children.Length == 3) { var child1 = clone.children[0]; var child2 = clone.children[1]; var child3 = clone.children[2]; if (child1.type == NodeType.CONSTANT) { if (child1.value < 0.0f) { return(child2); } else { return(child3); } } if (BothSameVariables(child2, child3)) { return(child2); } } return(clone); }