public void TestInterpretersEstimatedValuesConsistency()
        {
            var twister = new MersenneTwister();
            int seed    = twister.Next(0, int.MaxValue);

            twister.Seed((uint)seed);
            const int numRows = 100;
            var       dataset = Util.CreateRandomDataset(twister, numRows, Columns);

            var grammar = new TypeCoherentExpressionGrammar();

            var interpreters = new ISymbolicDataAnalysisExpressionTreeInterpreter[] {
                new SymbolicDataAnalysisExpressionTreeLinearInterpreter(),
                new SymbolicDataAnalysisExpressionTreeInterpreter(),
            };

            var rows        = Enumerable.Range(0, numRows).ToList();
            var randomTrees = Util.CreateRandomTrees(twister, dataset, grammar, N, 1, 10, 0, 0);

            foreach (ISymbolicExpressionTree tree in randomTrees)
            {
                Util.InitTree(tree, twister, new List <string>(dataset.VariableNames));
            }

            for (int i = 0; i < randomTrees.Length; ++i)
            {
                var tree         = randomTrees[i];
                var valuesMatrix = interpreters.Select(x => x.GetSymbolicExpressionTreeValues(tree, dataset, rows)).ToList();
                for (int m = 0; m < interpreters.Length - 1; ++m)
                {
                    var sum = valuesMatrix[m].Sum();
                    for (int n = m + 1; n < interpreters.Length; ++n)
                    {
                        var s = valuesMatrix[n].Sum();
                        if (double.IsNaN(sum) && double.IsNaN(s))
                        {
                            continue;
                        }

                        string errorMessage = string.Format("Interpreters {0} and {1} do not agree on tree {2} (seed = {3}).", interpreters[m].Name, interpreters[n].Name, i, seed);
                        Assert.AreEqual(sum, s, 1e-12, errorMessage);
                    }
                }
            }
        }
        public void TestCompiledInterpreterEstimatedValuesConsistency()
        {
            const double delta = 1e-12;

            var twister = new MersenneTwister();
            int seed    = twister.Next(0, int.MaxValue);

            twister.Seed((uint)seed);

            Console.WriteLine(seed);

            const int numRows = 100;
            var       dataset = Util.CreateRandomDataset(twister, numRows, Columns);

            var grammar = new TypeCoherentExpressionGrammar();

            grammar.ConfigureAsDefaultRegressionGrammar();
            grammar.Symbols.First(x => x.Name == "Power Functions").Enabled = true;

            var randomTrees = Util.CreateRandomTrees(twister, dataset, grammar, N, 1, 10, 0, 0);

            foreach (ISymbolicExpressionTree tree in randomTrees)
            {
                Util.InitTree(tree, twister, new List <string>(dataset.VariableNames));
            }

            var interpreters = new ISymbolicDataAnalysisExpressionTreeInterpreter[] {
                new SymbolicDataAnalysisExpressionCompiledTreeInterpreter(),
                new SymbolicDataAnalysisExpressionTreeInterpreter(),
                new SymbolicDataAnalysisExpressionTreeLinearInterpreter(),
            };
            var rows      = Enumerable.Range(0, numRows).ToList();
            var formatter = new SymbolicExpressionTreeHierarchicalFormatter();

            for (int i = 0; i < randomTrees.Length; ++i)
            {
                var tree         = randomTrees[i];
                var valuesMatrix = interpreters.Select(x => x.GetSymbolicExpressionTreeValues(tree, dataset, rows).ToList()).ToList();
                for (int m = 0; m < interpreters.Length - 1; ++m)
                {
                    for (int n = m + 1; n < interpreters.Length; ++n)
                    {
                        for (int row = 0; row < numRows; ++row)
                        {
                            var v1 = valuesMatrix[m][row];
                            var v2 = valuesMatrix[n][row];
                            if (double.IsNaN(v1) && double.IsNaN(v2))
                            {
                                continue;
                            }
                            if (Math.Abs(v1 - v2) > delta)
                            {
                                Console.WriteLine(formatter.Format(tree));
                                foreach (var node in tree.Root.GetSubtree(0).GetSubtree(0).IterateNodesPrefix().ToList())
                                {
                                    var rootNode = (SymbolicExpressionTreeTopLevelNode)grammar.ProgramRootSymbol.CreateTreeNode();
                                    if (rootNode.HasLocalParameters)
                                    {
                                        rootNode.ResetLocalParameters(twister);
                                    }
                                    rootNode.SetGrammar(grammar.CreateExpressionTreeGrammar());

                                    var startNode = (SymbolicExpressionTreeTopLevelNode)grammar.StartSymbol.CreateTreeNode();
                                    if (startNode.HasLocalParameters)
                                    {
                                        startNode.ResetLocalParameters(twister);
                                    }
                                    startNode.SetGrammar(grammar.CreateExpressionTreeGrammar());

                                    rootNode.AddSubtree(startNode);
                                    var t     = new SymbolicExpressionTree(rootNode);
                                    var start = t.Root.GetSubtree(0);
                                    var p     = node.Parent;
                                    start.AddSubtree(node);
                                    Console.WriteLine(node);

                                    var y1 = interpreters[m].GetSymbolicExpressionTreeValues(t, dataset, new[] { row }).First();
                                    var y2 = interpreters[n].GetSymbolicExpressionTreeValues(t, dataset, new[] { row }).First();

                                    if (double.IsNaN(y1) && double.IsNaN(y2))
                                    {
                                        continue;
                                    }
                                    string prefix = Math.Abs(y1 - y2) > delta ? "++" : "==";
                                    Console.WriteLine("\t{0} Row {1}: {2} {3}, Deviation = {4}", prefix, row, y1, y2, Math.Abs(y1 - y2));
                                    node.Parent = p;
                                }
                            }
                            string errorMessage = string.Format("Interpreters {0} and {1} do not agree on tree {2} and row {3} (seed = {4}).", interpreters[m].Name, interpreters[n].Name, i, row, seed);
                            Assert.AreEqual(v1, v2, delta, errorMessage);
                        }
                    }
                }
            }
        }