Exemple #1
0
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine(Figgle.FiggleFonts.Standard.Render("Frisia Generator"));
                logger.Info(appName);
                logger.Info("Filip Liwiński (c) 2019");
                Console.WriteLine();

                // Setup configuration source
                var    appSettings = "appsettings.json";
                string projectPath = AppDomain.CurrentDomain.BaseDirectory;

                var configuration = new ConfigurationBuilder()
                                    .SetBasePath(projectPath)
                                    .AddJsonFile(appSettings)
                                    .Build();

                var rewriterSection          = configuration.GetSection("Rewriter");
                var loopIterations           = Convert.ToUInt32(rewriterSection.GetSection("LoopIterations").Value);
                var visitUnsatisfiablePaths  = Convert.ToBoolean(rewriterSection.GetSection("VisitUnsatisfiablePaths").Value);
                var visitTimeoutPaths        = Convert.ToBoolean(rewriterSection.GetSection("VisitTimeoutPaths").Value);
                var logFoundBranches         = Convert.ToBoolean(rewriterSection.GetSection("LogFoundBranches").Value);
                var writeRewrittenCodeToFile = Convert.ToBoolean(rewriterSection.GetSection("WriteRewrittenCodeToFile").Value);
                var timeout = Convert.ToByte(rewriterSection.GetSection("TimeoutInSeconds").Value);

                logger.Info($"Loop iterations: {loopIterations}\nTimeout: {timeout}s\n");

                var solver    = new Z3Solver();
                var generator = new ParamsGenerator(logger, solver, loopIterations, visitUnsatisfiablePaths, visitTimeoutPaths, logFoundBranches, timeout);

                StartAsync(logger, solver, generator, args, writeRewrittenCodeToFile, loopIterations).Wait();
            }
            catch (Exception ex)
            {
                if (debug)
                {
                    logger.Error(ex);
                }
                else
                {
                    logger.Fatal(ex);
                }
            }

            LogManager.Flush();

            Console.WriteLine("\n\nPress any key to close...");
            Console.ReadKey();
        }
        public void While_loop_should_be_converted_to_if_statements()
        {
            foreach (var tc in TestCases)
            {
                try
                {
                    // Debugging
                    if (!string.IsNullOrEmpty(TestToDebug) && tc.Key != TestToDebug)
                    {
                        continue;
                    }

                    // Arrange
                    var rootNode = CSharpSyntaxTree.ParseText(tc.Value).GetRoot();
                    var methods  = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>();

                    foreach (var m in methods)
                    {
                        var conditions = new List <ExpressionSyntax>();
                        var solver     = new Z3Solver();
                        var sms        = new SymbolicMemoryState(m.ParameterList.Parameters);
                        var rewriter   = new FrisiaSyntaxRewriter(conditions, m.ParameterList.Parameters, sms, solver, null, LoopIterations, visitUnsatPaths: true, visitTimeoutPaths: true, logFoundBranches: false, timeout: 5);

                        // Act
                        var rewrittenNode = rewriter.Visit(m);

                        //Assert
                        var whileStatements = rootNode.DescendantNodes().OfType <WhileStatementSyntax>().ToArray();
                        foreach (var whileStatement in whileStatements)
                        {
                            var whileCondition        = (BinaryExpressionSyntax)whileStatement.Condition;
                            var rewrittenIfStatements = rewrittenNode.DescendantNodes().OfType <IfStatementSyntax>().Where(s => s.Condition.ToString() == whileCondition.ToString()).ToArray();
                            Assert.NotEmpty(rewrittenIfStatements);
                        }

                        var rewrittenWhileStatements = rewrittenNode.DescendantNodes().OfType <WhileStatementSyntax>().ToArray();
                        Assert.Empty(rewrittenWhileStatements);
                    }
                }
                catch (Exception ex)
                {
                    throw new TestCaseFailedException(tc.Key, ex);
                }
            }
        }
        public void Single_child_in_block_with_parent_of_kind_block_should_be_moved_one_level_up()
        {
            // Arrange
            var rootNode   = CSharpSyntaxTree.ParseText(@"
            using System;

            namespace Frisia.CodeReduction
            {
                class Program
                {
                    public static void Method(int a)
                    {
                        {
                            {
                                {
                                    Console.WriteLine (""First content in block."");
                                }
                                {
                                    Console.WriteLine (""Second content in block."");
                                }
                            }
                        }
                    }
                }
            }
            ").GetRoot();
            var m          = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>().First();
            var conditions = new List <ExpressionSyntax>();
            var solver     = new Z3Solver();
            var sms        = new SymbolicMemoryState(m.ParameterList.Parameters);
            var rewriter   = new FrisiaSyntaxRewriter(conditions, m.ParameterList.Parameters, sms, solver, null, LoopIterations, visitUnsatPaths: true, visitTimeoutPaths: true, logFoundBranches: false, timeout: 5);

            // Act
            var rewrittenNode = rewriter.Visit(rootNode);

            var blockStatementsWithParentBlockAndSingleChild = rootNode.DescendantNodes().OfType <BlockSyntax>()
                                                               .Where(b => b.Parent.Kind() == SK.Block && b.ChildNodes().Count() == 1);
            var rewrittenBlockStatementsWithParentBlockAndSingleChild = rewrittenNode.DescendantNodes().OfType <BlockSyntax>()
                                                                        .Where(b => b.Parent.Kind() == SK.Block && b.ChildNodes().Count() == 1);

            // Assert
            Assert.NotEmpty(blockStatementsWithParentBlockAndSingleChild);
            Assert.Empty(rewrittenBlockStatementsWithParentBlockAndSingleChild);
        }
        public void Rewritten_TestCases_should_exists()
        {
            foreach (var tc in TestCases)
            {
                // Debugging
                if (!string.IsNullOrEmpty(TestToDebug) && tc.Key != TestToDebug)
                {
                    continue;
                }

                var timer = new Stopwatch();

                // Arrange
                var rootNode = CSharpSyntaxTree.ParseText(tc.Value).GetRoot();
                var methods  = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>();

                foreach (var m in methods)
                {
                    var conditions = new List <ExpressionSyntax>();
                    var solver     = new Z3Solver();
                    var sms        = new SymbolicMemoryState(m.ParameterList.Parameters);
                    var rewriter   = new FrisiaSyntaxRewriter(conditions, m.ParameterList.Parameters, sms, solver, null, LoopIterations, visitUnsatPaths: true, visitTimeoutPaths: true, logFoundBranches: false, timeout: 5);

                    // Act
                    timer.Start();
                    var rewrittenNode = (MethodDeclarationSyntax)rewriter.Visit(m);
                    timer.Stop();

                    rootNode = rootNode.ReplaceNode(m, rewrittenNode);
                }

                var directory         = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..\\..\\..\\")) + "TestCasesRewritten\\";
                var path              = $"{directory}{tc.Key}";
                var rewrittenNodeText = $"// This code was generated by Frisia.Rewriter.{Environment.NewLine}// Loop iterations: {LoopIterations}{Environment.NewLine}// Date: {DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss")}{Environment.NewLine}// Time: {timer.Elapsed}{Environment.NewLine}{Environment.NewLine}{rootNode.ToFullString()}";

                File.WriteAllText(path, rewrittenNodeText);

                // Assert
                Assert.True(File.Exists(path));
            }
        }
        public void Each_block_statement_should_contain_single_statement()
        {
            foreach (var tc in TestCases)
            {
                try
                {
                    // Debugging
                    if (!string.IsNullOrEmpty(TestToDebug) && tc.Key != TestToDebug)
                    {
                        continue;
                    }

                    // Arrange
                    var rootNode = CSharpSyntaxTree.ParseText(tc.Value).GetRoot();
                    var methods  = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>();

                    foreach (var m in methods)
                    {
                        var conditions = new List <ExpressionSyntax>();
                        var solver     = new Z3Solver();
                        var sms        = new SymbolicMemoryState(m.ParameterList.Parameters);
                        var rewriter   = new FrisiaSyntaxRewriter(conditions, m.ParameterList.Parameters, sms, solver, null, LoopIterations, visitUnsatPaths: true, visitTimeoutPaths: true, logFoundBranches: false, timeout: 5);

                        // Act

                        var rewrittenNode = rewriter.Visit(m);

                        var blocks = rewrittenNode.DescendantNodes().OfType <BlockSyntax>();

                        // Assert
                        Assert.All(blocks, b => b.ChildNodes().OfType <StatementSyntax>().Where(x => x.Kind() != SK.ExpressionStatement &&
                                                                                                x.Kind() != SK.LocalDeclarationStatement).SingleOrDefault());
                    }
                }
                catch (Exception ex)
                {
                    throw new TestCaseFailedException(tc.Key, ex);
                }
            }
        }
        public void If_statement_should_not_contain_logical_OR_expression()
        {
            foreach (var tc in TestCases)
            {
                try
                {
                    // Debugging
                    if (!string.IsNullOrEmpty(TestToDebug) && tc.Key != TestToDebug)
                    {
                        continue;
                    }

                    // Arrange
                    var rootNode = CSharpSyntaxTree.ParseText(tc.Value).GetRoot();
                    var methods  = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>();

                    foreach (var m in methods)
                    {
                        var conditions = new List <ExpressionSyntax>();
                        var solver     = new Z3Solver();
                        var sms        = new SymbolicMemoryState(m.ParameterList.Parameters);
                        var rewriter   = new FrisiaSyntaxRewriter(conditions, m.ParameterList.Parameters, sms, solver, null, LoopIterations, visitUnsatPaths: true, visitTimeoutPaths: true, logFoundBranches: false, timeout: 5);

                        // Act
                        var rewrittenNode = rewriter.Visit(m);

                        //Assert
                        var rewrittenIfStatements = rewrittenNode.DescendantNodes().OfType <IfStatementSyntax>();

                        Assert.All(rewrittenIfStatements, s => Assert.True(s.Condition.Kind() != SK.LogicalOrExpression));
                    }
                }
                catch (Exception ex)
                {
                    throw new TestCaseFailedException(tc.Key, ex);
                }
            }
        }
        //TODO: make this more pretty
        public static void Main(string[] args)
        {
            var cliApp     = new CommandLineApplication();
            var xivPathOpt = cliApp.Option("-p |--game-path <pathToFFXIV>",
                                           "Path to the FFXIV game install (folder containing boot and game)", CommandOptionType.SingleValue);

            var configOpt = cliApp.Option("-c |--config-path <pathToYaml>",
                                          "Path to configuration YAML file, default to config.yaml", CommandOptionType.SingleValue);

            var excludedOpt = cliApp.Option("-X |--exclude <itemId>",
                                            "Item ids of items to exclude from solving", CommandOptionType.MultipleValue);

            var minIlvlOpt = cliApp.Option("-m |--min-itemlevel <ilvl>",
                                           "Minimum item level of items to consider. Uses max-20 if not passed.", CommandOptionType.SingleValue);
            var maxIlvlOpt = cliApp.Option("-M |--max-itemlevel <ilvl>",
                                           "Maximum item level of items to consider", CommandOptionType.SingleValue);

            var maxOvermeldTierOpt = cliApp.Option("-T |--max-overmeld-tier <tier>",
                                                   "The max tier of materia allowed for overmelds", CommandOptionType.SingleValue);

            var noMaximizeUnweightedOpt = cliApp.Option("--no-maximize-unweighted",
                                                        "Choose to disable maximizing unweighted stats (usually accuracy). Shouldn't be needed.",
                                                        CommandOptionType.NoValue);

            var solverOpt = cliApp.Option("-s |--solver <solver>", "Solver to use (default: GLPK)",
                                          CommandOptionType.SingleValue);

            var debugOpt = cliApp.Option("-d |--debug", "Print the used models in the current directory as model.lp",
                                         CommandOptionType.NoValue);

            var jobArg = cliApp.Argument("<job>", "Enter the job abbreviation to solve for");

            cliApp.HelpOption("-h |--help");

            cliApp.OnExecute(() =>
            {
                if (jobArg.Value == null)
                {
                    Console.Error.WriteLine("You must provide a job to solve for.");
                    return(1);
                }

                if (!xivPathOpt.HasValue())
                {
                    Console.Error.WriteLine("You must provide a path to FFXIV!");
                    return(1);
                }

                var realm   = new ARealmReversed(xivPathOpt.Value(), Language.English);
                var xivColl = realm.GameData;

                var deserializer = new DeserializerBuilder()
                                   .WithTypeConverter(new BaseParamConverter(xivColl))
                                   .WithTypeConverter(new ClassJobConverter(xivColl))
                                   .WithNamingConvention(new CamelCaseNamingConvention())
                                   .Build();

                AppConfig config = null;

                using (var s = new FileStream(configOpt.HasValue() ? configOpt.Value() : "config.yaml", FileMode.Open))
                {
                    config = deserializer.Deserialize <AppConfig>(new StreamReader(s));
                }

                var classJob = xivColl.GetSheet <ClassJob>().Single(x => x.Abbreviation == jobArg.Value);

                var jobConfig = config.JobConfigs[classJob];

                var items = xivColl.GetSheet <Item>().ToList();

                if (excludedOpt.HasValue())
                {
                    var excludedIds = new List <int>();
                    foreach (var excluded in excludedOpt.Values)
                    {
                        var id   = int.Parse(excluded);
                        var item = xivColl.Items[id];
                        if (item != null)
                        {
                            Console.WriteLine($"Excluding {item}.");
                            excludedIds.Add(id);
                        }
                        else
                        {
                            Console.Error.WriteLine($"Unknown id {id}, ignoring.");
                        }
                    }
                    items = items.Where(k => !excludedIds.Contains(k.Key)).ToList();
                }

                var equip = items.OfType <Equipment>().Where(e => e.ClassJobCategory.ClassJobs.Contains(classJob));

                var maxIlvl = equip.Max(x => x.ItemLevel.Key);
                if (maxIlvlOpt.HasValue())
                {
                    maxIlvl = int.Parse(maxIlvlOpt.Value());
                }

                var minIlvl = maxIlvl - 20;
                if (minIlvlOpt.HasValue())
                {
                    minIlvl = int.Parse(minIlvlOpt.Value());
                }

                equip = equip.Where(e => e.ItemLevel.Key >= minIlvl && e.ItemLevel.Key <= maxIlvl).ToList();

                var food = items.Where(FoodItem.IsFoodItem).Select(t => new FoodItem(t));

                var materia = items.OfType <MateriaItem>()
                              .ToDictionary(i => i,
                                            i => !maxOvermeldTierOpt.HasValue() || i.Tier < int.Parse(maxOvermeldTierOpt.Value()));

                var relicCaps =
                    equip.Where(e => config.RelicCaps.ContainsKey(e.ItemLevel.Key))
                    .ToDictionary(e => e, e => config.RelicCaps[e.ItemLevel.Key]);

                //TODO: improve solver handling
                SolverBase solver = new GLPKSolver();
                if (solverOpt.HasValue())
                {
                    switch (solverOpt.Value())
                    {
                    case "Gurobi":
                        solver = new GurobiSolver();
                        break;

                    case "Z3":
                        solver = new Z3Solver();
                        break;
                    }
                }


                using (var scope = new ModelScope())
                {
                    var model = new BisModel(jobConfig.Weights, jobConfig.StatRequirements, config.BaseStats,
                                             equip, food, materia, relicCaps, maximizeUnweightedValues: !noMaximizeUnweightedOpt.HasValue());

                    if (debugOpt.HasValue())
                    {
                        using (var f = new FileStream("model.lp", FileMode.Create))
                        {
                            var obj        = model.Model.Objectives.First();
                            obj.Expression = obj.Expression.Normalize();
                            model.Model.Constraints.ForEach(c => c.Expression = c.Expression.Normalize());
                            model.Model.Write(f, FileType.LP);
                        }
                    }

                    var solution = solver.Solve(model.Model);
                    model.ApplySolution(solution);
                    Console.WriteLine("Gear: ");
                    model.ChosenGear.ForEach(Console.WriteLine);
                    Console.WriteLine("Materia: ");
                    model.ChosenMateria.ForEach(Console.WriteLine);
                    if (model.ChosenRelicStats.Any())
                    {
                        Console.WriteLine("Relic stats: ");
                        model.ChosenRelicStats.ForEach(Console.WriteLine);
                    }
                    Console.WriteLine("Food: ");
                    Console.WriteLine(model.ChosenFood);
                    Console.WriteLine("Allocated stats: ");
                    model.ResultAllocatableStats.ForEach(kv => Console.WriteLine(kv));
                    Console.WriteLine("Result stats with food:");
                    model.ResultTotalStats.ForEach(kv => Console.WriteLine(kv));
                    Console.WriteLine($"Result stat weight: {model.ResultWeight}");
                }

                return(0);
            });

            cliApp.Execute(args);
        }
        public void AND_expressions_should_be_replaced_correctly()
        {
            // Arrange
            var rootNode = CSharpSyntaxTree.ParseText(@"
            using System;

            namespace Frisia.CodeReduction
            {
                class Program
                {
                    public static void Method(int a, int b)
                    {
                        if (a > 0 && b > 0)
                        {
                            Console.WriteLine(""a > 0 && b > 0"");
                                
                            if (a > 1 && b > 1)
                            {
                                Console.WriteLine(""a > 1 && b > 1"");

                                if (a > 2 && b > 2)
                                {
                                    Console.WriteLine(""a > 2 && b > 2"");
                                }
                                else
                                {
                                    Console.WriteLine(""!(a > 2 && b > 2)"");
                                }
                            }
                            else
                            {
                                Console.WriteLine(""!(a > 1 && b > 1)"");

                                if (a > 2 && b > 2)
                                {
                                    Console.WriteLine(""a > 2 && b > 2"");
                                }
                                else
                                {
                                    Console.WriteLine(""!(a > 2 && b > 2)"");
                                }
                            }
                        }
                        else
                        {
                            Console.WriteLine(""!(a > 0 && b > 0)"");

                            if (a < 1 && b < 1)
                            {
                                Console.WriteLine(""a < 1 && b < 1"");

                                if (a < 2 && b < 2)
                                {
                                    Console.WriteLine(""a < 2 && b < 2"");
                                }
                                else
                                {
                                    Console.WriteLine(""!(a < 2 && b < 2)"");
                                }
                            }
                            else
                            {
                                Console.WriteLine(""!(a < 1 && b < 1)"");

                                if (a < 2 && b < 2)
                                {
                                    Console.WriteLine(""a < 2 && b < 2"");
                                }
                                else
                                {
                                    Console.WriteLine(""!(a < 2 && b < 2)"");
                                }
                            }
                        }
                    }
                }
            }
            ").GetRoot();

            var methods = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>();

            foreach (var m in methods)
            {
                var conditions = new List <ExpressionSyntax>();
                var solver     = new Z3Solver();
                var sms        = new SymbolicMemoryState(m.ParameterList.Parameters);
                var rewriter   = new FrisiaSyntaxRewriter(conditions, m.ParameterList.Parameters, sms, solver, null, LoopIterations, visitUnsatPaths: true, visitTimeoutPaths: true, logFoundBranches: false, timeout: 5);


                // Act
                var rewrittenNode = rewriter.Visit(rootNode);

                //var ifStatements = rootNode.DescendantNodes().OfType<IfStatementSyntax>().ToArray();
                var rewrittenIfStatements = rewrittenNode.DescendantNodes().OfType <IfStatementSyntax>().ToArray();

                // Assert
                Assert.Equal(26, rewrittenIfStatements.Length);
            }
        }