#region License Information /* HeuristicLab * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using Google.OrTools.LinearSolver; using HEAL.Attic; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Optimization; using HeuristicLab.Parameters; namespace HeuristicLab.ExactOptimization.LinearProgramming { [Item("Mixed-Integer Linear Programming Problem (LP, MIP)", "Represents a linear/mixed integer problem.")] [StorableType("0F6BD4A4-8C70-4922-9BA1-1F372820DD76")] public sealed class LinearProblem : Problem, IStorableContent { [Storable] private readonly IValueParameter problemDefinitionParam; public LinearProblem() { Parameters.Remove(Parameters["Operators"]); Parameters.Add(problemDefinitionParam = new ValueParameter("Model", "The linear programming problem", new ProgrammableLinearProblemDefinition()) { GetsCollected = false }); } private LinearProblem(LinearProblem original, Cloner cloner) : base(original, cloner) { problemDefinitionParam = cloner.Clone(original.problemDefinitionParam); } [StorableConstructor] private LinearProblem(StorableConstructorFlag _) : base(_) { } public event EventHandler ProblemDefinitionChanged; public string Filename { get; set; } public ILinearProblemDefinition ProblemDefinition { get => problemDefinitionParam.Value; set { if (problemDefinitionParam.Value == value) return; problemDefinitionParam.Value = value; ProblemDefinitionChanged?.Invoke(this, EventArgs.Empty); } } public IValueParameter ProblemDefinitionParameter => problemDefinitionParam; public override IDeepCloneable Clone(Cloner cloner) => new LinearProblem(this, cloner); public override void CollectParameterValues(IDictionary values) { base.CollectParameterValues(values); if (ProblemDefinition == null) return; values.Add("Model Type", new StringValue( (ProblemDefinition.GetType().GetCustomAttributes().Single(a => a is ItemAttribute) as ItemAttribute).Name)); if (ProblemDefinition is ProgrammableLinearProblemDefinition model) { values.Add("Model Name", new StringValue(model.Name)); } } public void ExportModel(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentNullException(nameof(fileName)); if (ProblemDefinition == null) throw new ArgumentNullException(nameof(ProblemDefinition)); var fileInfo = new FileInfo(fileName); if (!fileInfo.Directory?.Exists ?? false) { Directory.CreateDirectory(fileInfo.Directory.FullName); } var solver = new Solver(ProblemDefinition.ItemName, Solver.OptimizationProblemType.CbcMixedIntegerProgramming); ProblemDefinition.BuildModel(solver); var exportSuccessful = false; switch (fileInfo.Extension) { case ".lp": var lpFormat = solver.ExportModelAsLpFormat(false); if (!string.IsNullOrEmpty(lpFormat)) { File.WriteAllText(fileName, lpFormat); exportSuccessful = true; } break; case ".mps": var mpsFormat = solver.ExportModelAsMpsFormat(false, false); if (!string.IsNullOrEmpty(mpsFormat)) { File.WriteAllText(fileName, mpsFormat); exportSuccessful = true; } break; case ".prototxt": exportSuccessful = solver.ExportModelAsProtoFormat(fileName, (Google.OrTools.LinearSolver.ProtoWriteFormat)ProtoWriteFormat.ProtoText); break; case ".bin": // remove file extension as it is added by OR-Tools fileName = Path.ChangeExtension(fileName, null); exportSuccessful = solver.ExportModelAsProtoFormat(fileName, (Google.OrTools.LinearSolver.ProtoWriteFormat)ProtoWriteFormat.ProtoBinary); break; default: throw new NotSupportedException($"File format {fileInfo.Extension} to export model is not supported."); } if (!exportSuccessful) throw new InvalidOperationException($"Model could not be exported. " + $"For details, see the log files in '{LinearSolver.LogDirectory}'."); } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { } } }