#region License Information /* HeuristicLab * Copyright (C) 2002-2017 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.IO; using System.Linq; using System.Reflection; using System.Threading; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.IntegerVectorEncoding; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Random; using ILOG.CPLEX; using ILOG.OPL; namespace HeuristicLab.Problems.FacilityLocation.CplexSolver { public enum FlpVariant { FLP_1, FLP_2 } [Item("FLP CPLEX Solver", "Solves facility location problem (FLP) instances using CPLEX.")] [Creatable(CreatableAttribute.Categories.SingleSolutionAlgorithms)] [StorableClass] public sealed class FLPCplexSolver : BasicAlgorithm { public override bool SupportsPause { get { return false; } } public override Type ProblemType { get { return typeof(FacilityLocationProblem); } } public new FacilityLocationProblem Problem { get { return (FacilityLocationProblem)base.Problem; } set { base.Problem = value; } } [Storable] private IFixedValueParameter maximumRuntimeParameter; public IFixedValueParameter MaximumRuntimeParameter { get { return maximumRuntimeParameter; } } public TimeSpan MaximumRuntime { get { return maximumRuntimeParameter.Value.Value; } set { maximumRuntimeParameter.Value.Value = value; } } [Storable] private IFixedValueParameter> flpVariantParameter; public IFixedValueParameter> FlpVariantParameter { get { return flpVariantParameter; } } public FlpVariant FlpVariant { get { return flpVariantParameter.Value.Value; } set { flpVariantParameter.Value.Value = value; } } [StorableConstructor] private FLPCplexSolver(bool deserializing) : base(deserializing) { } private FLPCplexSolver(FLPCplexSolver original, Cloner cloner) : base(original, cloner) { maximumRuntimeParameter = cloner.Clone(original.maximumRuntimeParameter); flpVariantParameter = cloner.Clone(original.flpVariantParameter); } public FLPCplexSolver() { Parameters.Add(maximumRuntimeParameter = new FixedValueParameter("Maximum Runtime", "Specifies how long CPLEX should be allowed to run.", new TimeSpanValue(TimeSpan.FromSeconds(60)))); Parameters.Add(flpVariantParameter = new FixedValueParameter>("FLP Variant", "Which FLP variant should be run.", new EnumValue(FlpVariant.FLP_1))); Problem = new FacilityLocationProblem(); } public override IDeepCloneable Clone(Cloner cloner) { return new FLPCplexSolver(this, cloner); } protected override void Run(CancellationToken cancellationToken) { var factory = new OplFactory(); var cplex = factory.CreateCplex(); var model = Assembly.GetExecutingAssembly().GetManifestResourceNames().SingleOrDefault(x => x.EndsWith(@"." + FlpVariant.ToString() + ".mod")); var modelStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(model); var depots = Problem.DepotCapacitiesParameter.Value.Length; var customers = Problem.CustomerDemandsParameter.Value.Length; using (var reader = new StreamReader(modelStream)) using (var modelSource = factory.CreateOplModelSourceFromString(reader.ReadToEnd(), Path.GetFileNameWithoutExtension(model))) using (var errorHandler = factory.CreateOplErrorHandler()) using (var settings = factory.CreateOplSettings(errorHandler)) using (var def = factory.CreateOplModelDefinition(modelSource, settings)) using (var opl = factory.CreateOplModel(def, cplex)) using (var dataSource = new FLPDataSource(factory, Problem)) { opl.AddDataSource(dataSource); opl.Generate(); cplex.SetParam(Cplex.DoubleParam.TiLim, MaximumRuntimeParameter.Value.Value.TotalSeconds); var solved = cplex.Solve(); var assignment = new IntegerVector(customers); if (solved) { Results.Add(new Result("BestQuality", new DoubleValue(cplex.ObjValue))); Results.Add(new Result("Best Solution Optimal", new BoolValue( opl.Cplex.GetCplexStatus().Equals(Cplex.CplexStatus.Optimal) || opl.Cplex.GetCplexStatus().Equals(Cplex.CplexStatus.OptimalTol)))); Results.Add(new Result("Best Solution Feasible", new BoolValue(true))); var sol = opl.GetElement(FLPDataSource.CustomerDepotAssignment).AsIntMap(); for (var i = 0; i < depots; i++) { var solI = sol.GetSub(i); for (var j = 0; j < customers; j++) { var solIJ = solI.Get(j); if (solIJ == 0) continue; assignment[j] = i; } } } else { var demands = Problem.CustomerDemandsParameter.Value; var capacities = Problem.DepotCapacitiesParameter.Value; assignment.Randomize(new FastRandom(), 0, depots); // output a random solution Results.Add(new Result("Best Solution Optimal", new BoolValue(false))); var feasible = assignment.Select((v, i) => new { Demand = demands[i], Depot = v }).GroupBy(x => x.Depot, x => x.Demand).All(x => capacities[x.Key] <= x.Sum()); Results.Add(new Result("Best Solution Feasible", new BoolValue(feasible))); Results.Add(new Result("BestQuality", new DoubleValue(Problem.Evaluate(assignment)))); } Results.Add(new Result("Best Solution", assignment)); } } } }