Exemple #1
0
        private static GLPKSolver CreateGLPKSolver()
        {
            //TODO heuristics
            //TODO better GLPK configuration
            GLPKSolver solver = new GLPKSolver();

            return(solver);
        }
Exemple #2
0
        public IActionResult Solver()
        {
            //try {
            var model = new Model();
            var x     = new Variable("x");
            var y     = new Variable("y");

            model.AddConstraint(10 * x + 20 * y >= 2);
            model.AddConstraint(40 * x + 60 * y >= 64);
            model.AddConstraint(50 * x + 20 * y >= 34);
            model.AddObjective(new Objective(0.6 * x + 0.8 * y));

            var solver = new GLPKSolver();

            solver.Solve(model);
            var solution = solver.Solve(model);

            return(Ok(solution.ObjectiveValues));
            //} catch {
            //    return BadRequest( "It was not possible to calculate the simplex" );
            //}
        }
Exemple #3
0
        static void Main(string[] args)
        {
            var config = new Configuration();

            config.NameHandling            = NameHandlingStyle.UniqueLongNames;
            config.ComputeRemovedVariables = true;

            using (var scope = new ModelScope(config))
            {
                var model = new Model();

                // days in crop planning
                var horizon = Enumerable.Range(1, 9).ToList();

                // only 1 crop for demonstration purposes
                var crops = new List <string>();
                crops.Add("Crop A");
                crops.Add("Crop B");

                // the assignment of a crop planted on a day in the horizon
                var CropAssignment = new VariableCollection <int, string>(
                    model,
                    horizon,
                    crops,
                    "CropAssignment",
                    (d, c) => $"CropAssignment_{d}_{c}",
                    (d, c) => 0,
                    (d, c) => 1,
                    (d, c) => VariableType.Binary
                    );

                foreach (var day in horizon)
                {
                    // max 1 crop per day
                    model.AddConstraint(Expression.Sum(crops.Select(crop => CropAssignment[day, crop])) <= 1);

                    foreach (var crop in crops)
                    {
                        // let's say a crop grows for 2 days after the day it was planted
                        var cropGrowing = horizon.Where(d => d > day && d <= day + 2);

                        if (cropGrowing.Count() == 2)
                        {
                            // set otherDay to zero, if the crop is planted on day.
                            foreach (var otherDay in cropGrowing)
                            {
                                model.AddConstraint(-CropAssignment[day, crop] + 1 >= Expression.Sum(crops.Select(c => CropAssignment[otherDay, c])));
                            }
                        }
                        else
                        {
                            // the crop can't finish before end of horizon
                            var cropCantFinishGrowingConstraint = CropAssignment[day, crop] == 0;
                            model.AddConstraint(cropCantFinishGrowingConstraint);
                        }
                    }
                }

                var total = Expression.Sum(horizon.SelectMany(day => crops.Select(crop => CropAssignment[day, crop])));
                model.AddObjective(new Objective(total, "total", ObjectiveSense.Maximize));

                using (var solver = new GLPKSolver())
                {
                    var solution = solver.Solve(model);

                    // import values back into the model
                    model.VariableCollections.ToList().ForEach(vc => vc.SetVariableValues(solution.VariableValues));

                    // print solution
                    foreach (var day in horizon)
                    {
                        foreach (var crop in crops)
                        {
                            if (CropAssignment[day, crop].Value == 1)
                            {
                                Console.WriteLine($"Day {day} {crop} planted");
                            }
                        }
                    }
                }
            }
        }
        //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);
        }
Exemple #5
0
        public IActionResult Solver([FromBody] GLPKInput input)
        {
            try {
                // Cria o modelo e adiciona as variaveis
                Dictionary <string, string> variableKeyName = new Dictionary <string, string>( );
                var             model     = new Model( );
                List <Variable> variables = new List <Variable>( );
                foreach (var val in input.Variables)
                {
                    var variable = new Variable(val, 0);
                    variables.Add(variable);
                    variableKeyName.Add(variable.Name, val);
                }

                // Adiciona as restrições ao problema
                Expression expression = Expression.EmptyExpression;
                foreach (var val in input.Restrictions)
                {
                    for (int i = 0; i < val.Values.Count( ); i++)
                    {
                        expression = val.Values.ElementAt(i) * variables.ElementAt(i) + expression;
                    }

                    if (val.Operation == GLPKRestriction.Operator.GreaterOrEqual)
                    {
                        model.AddConstraint(expression >= val.Disponibility);
                    }
                    else
                    {
                        model.AddConstraint(expression <= val.Disponibility);
                    }
                    expression = Expression.EmptyExpression;
                }

                // Adiciona a função objetiva ao modelo
                expression = Expression.EmptyExpression;
                for (int i = 0; i < input.Objective.Values.Count( ); i++)
                {
                    expression = input.Objective.Values.ElementAt(i) * variables.ElementAt(i) + expression;
                }

                if (input.Objective.Operation == GLPKObjective.Operator.Maximize)
                {
                    model.AddObjective(new Objective(expression, "Z", OPTANO.Modeling.Optimization.Enums.ObjectiveSense.Maximize));
                }
                else
                {
                    model.AddObjective(new Objective(expression, "Z", OPTANO.Modeling.Optimization.Enums.ObjectiveSense.Minimize));
                }

                // Resolve o modelo por meio do GLPK
                var solver = new GLPKSolver( );
                solver.Solve(model);
                var solution = solver.Solve(model);

                // Renomeia as variaveis para as variaveis do problema recebido
                var variablesRenamed = new Dictionary <string, double>( );
                foreach (var val in solution.VariableValues)
                {
                    variablesRenamed.Add(variableKeyName[val.Key], val.Value);
                }

                var objectiveRenamed = new Dictionary <string, double>( );
                foreach (var val in solution.ObjectiveValues)
                {
                    objectiveRenamed.Add("Z", val.Value);
                }

                // Formata a resposta
                var resp = new GLPKOutput {
                    Objectives = objectiveRenamed,
                    Variables  = variablesRenamed,
                    Status     = solution.Status
                };

                // Retorna a resposta
                return(Ok(resp));
            } catch {
                // Para qualquer erro na resolução
                return(BadRequest("It was not possible to calculate the simplex"));
            }
        }
        GeoHydroSolutionOutput SolveTheModel(HydroSourceValues inputValues,
                                             HydroMixModelConfig config,
                                             SourceConfiguration sourceConfiguration)
        {
            var text = new StringBuilder(
                $"\n"
                + $"              ===================================\n"
                + $"Result for target: '{inputValues.Target.Source.Name}' and configuration: '{config.ConfigAlias}' and source conf: '{sourceConfiguration.Alias}' :"
                + $"\n\n");
            var optanoConfig = new Configuration();

            optanoConfig.NameHandling            = NameHandlingStyle.UniqueLongNames;
            optanoConfig.ComputeRemovedVariables = true;
            GeoHydroSolutionOutput geoHydroSolutionOutput;

            using (var scope = new ModelScope(optanoConfig))
            {
                var problem = new HydroMixProblem(inputValues, config, inputValues.Target, sourceConfiguration);

                using (var solver = new GLPKSolver())
                {
                    // solve the model
                    var solution = solver.Solve(problem.Model);
                    // import the results back into the model
                    foreach (var vc in problem.Model.VariableCollections)
                    {
                        vc.SetVariableValues(solution.VariableValues);
                    }

                    var TOLERANCE = 0.001;

                    var sourcesContributions = problem.Sources.Select(s => (Source: s, Contribution: problem.SourceContribution[s].Value)).ToList();
                    var resultingMix         = inputValues.MarkerInfos().Select(x => x.MarkerName).ToDictionary(x => x, x => 0.0);

                    foreach (var source in sourcesContributions.Where(x => x.Contribution > 0.01).OrderByDescending(x => x.Contribution))
                    {
                        var array = source.Source.Name.Take(25).ToArray();
                        var sourceContribution = problem.SourceUsed[source.Source].Value;
                        var formattableString  = $"Source({sourceContribution:F0}): {new string(array),25} | Contribution: {source.Contribution * 100:F1} ";
                        text.AppendLine(formattableString);

                        foreach (var markerVal in source.Source.MarkerValues)
                        {
                            resultingMix[markerVal.MarkerInfo.MarkerName] += markerVal.Value * markerVal.MarkerInfo.NormalizationCoefficient * source.Contribution;
                        }
                    }

                    text.AppendLine();
                    var totalError     = 0.0;
                    var optimizedError = 0.0;
                    foreach (var markerInfo in inputValues.MarkerInfos()
                             //.Where(x => x.Weight > 0)
                             )
                    {
                        var epsilonMarkerErrorPos = problem.PositiveErrors[markerInfo].Value;
                        var epsilonMarkerErrorNeg = problem.NegativeErrors[markerInfo].Value;

                        totalError += Math.Abs(epsilonMarkerErrorNeg) + Math.Abs(epsilonMarkerErrorPos);

                        if (markerInfo.Weight > 0)
                        {
                            optimizedError += Math.Abs(epsilonMarkerErrorNeg) + Math.Abs(epsilonMarkerErrorPos);
                        }

                        var originalTargetValue = inputValues.Target.Source[markerInfo].OriginalValue.Value;

                        var computedValue = resultingMix[markerInfo.MarkerName] - (epsilonMarkerErrorPos * markerInfo.NormalizationCoefficient) + (epsilonMarkerErrorNeg * markerInfo.NormalizationCoefficient);

                        string diffInfo = null;
                        if (Math.Abs(computedValue - originalTargetValue) > TOLERANCE)
                        {
                            diffInfo = $"| diffComputed/Target: ({computedValue,6:F3}/{originalTargetValue,6:F3})";
                        }

                        var realDiff = resultingMix[markerInfo.MarkerName] - originalTargetValue;

                        var formattableString = $"Marker({markerInfo.Weight:F0}) {markerInfo.MarkerName,10} | targetVal: {originalTargetValue,6:F2}  | diff: ({realDiff,6:F2}) | mixValue: {resultingMix[markerInfo.MarkerName],6:F2} {diffInfo}";
                        text.AppendLine(formattableString);
                    }

                    geoHydroSolutionOutput = new GeoHydroSolutionOutput()
                    {
                        TextOutput         = text + $"              ===================================\n" + '\n',
                        ConfigALias        = config.ConfigAlias,
                        Target             = inputValues.Target,
                        SourcesConfigAlias = sourceConfiguration.Alias,
                        UsedSources        = sourcesContributions.Where(x => x.Contribution > 0.01).OrderByDescending(x => x.Contribution),
                        NormalizedError    = totalError,
                        ResultingMix       = resultingMix,
                        OptimalizedError   = optimizedError
                    };
                }
            }
            return(geoHydroSolutionOutput);
        }