private static GLPKSolver CreateGLPKSolver() { //TODO heuristics //TODO better GLPK configuration GLPKSolver solver = new GLPKSolver(); return(solver); }
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" ); //} }
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); }
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); }