Пример #1
0
 public StackMachine(AptNode node)
 {
     nodeCount    = node.Count();
     instructions = new Instruction[nodeCount];
     inPtr        = 0;
     BuildInstructions(node);
 }
Пример #2
0
        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");
        }
Пример #3
0
 public void RebuildInstructions(AptNode node)
 {
     nodeCount    = node.Count();
     instructions = new Instruction[nodeCount];
     inPtr        = 0;
     BuildInstructions(node);
 }
Пример #4
0
        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);
            }
        }
Пример #5
0
        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);
        }
Пример #6
0
        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;
            }
        }
Пример #7
0
        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));
        }
Пример #8
0
 public void Optimize()
 {
     for (int i = 0; i < Trees.Length; i++)
     {
         Trees[i]    = AptNode.ConstantFolding(Trees[i]);
         Machines[i] = new StackMachine(Trees[i]);
     }
 }
Пример #9
0
        public AptNode ShallowClone()
        {
            AptNode result = new AptNode {
            };

            result.type     = type;
            result.value    = value;
            result.filename = filename;
            return(result);
        }
Пример #10
0
        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);
            }
        }
Пример #11
0
 //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);
 }
Пример #12
0
        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);
            }
        }
Пример #13
0
        // 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);
            }
        }
Пример #14
0
        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;
            }
        }
Пример #15
0
        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);
            }
        }
Пример #16
0
        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);
                }
            }
        }
Пример #17
0
        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);
        }
Пример #18
0
        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);
                }
            }
        }
Пример #19
0
        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);
        }
Пример #20
0
 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);
 }
Пример #21
0
        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");
        }
Пример #22
0
        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
                });
            }
        }
Пример #23
0
        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();
        }
Пример #24
0
        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);
            }
        }
Пример #25
0
        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);
        }
Пример #26
0
        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);
        }