#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.Threading;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.IntegerVectorEncoding;
using HeuristicLab.Optimization;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using ILOG.CPLEX;
using ILOG.OPL;
namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.CPLEX {
[Item("CPLEX Solver (GQAP)", "Base class")]
[StorableClass]
public abstract class CplexSolver : ContextAlgorithm {
public override bool SupportsPause {
get { return false; }
}
public override Type ProblemType {
get { return typeof(GQAP); }
}
public new GQAP Problem {
get { return (GQAP)base.Problem; }
set { base.Problem = value; }
}
[StorableConstructor]
protected CplexSolver(bool deserializing) : base(deserializing) { }
protected CplexSolver(CplexSolver original, Cloner cloner)
: base(original, cloner) {
}
public CplexSolver() {
Problem = new GQAP();
}
protected override void Run(CancellationToken cancellationToken) {
base.Run(cancellationToken);
var factory = new OplFactory();
var cplex = factory.CreateCplex();
cplex.Use(new LogCallback(this, cancellationToken));
cplex.SetParam(Cplex.DoubleParam.TiLim, MaximumRuntime.TotalSeconds);
cplex.SetParam(Cplex.IntParam.Threads, 1);
var dataSource = new GQAPDataSource(factory, Problem.ProblemInstance);
using (var settings = factory.CreateOplSettings(factory.CreateOplErrorHandler()))
using (var opl = GetModel(factory, settings, cplex)) {
opl.AddDataSource(dataSource);
opl.Generate();
if (cplex.Solve()) {
var obj = cplex.ObjValue;
if (double.IsNaN(Context.BestQuality) || obj < Context.BestQuality)
Context.BestQuality = obj;
IResult result;
if (Results.TryGetValue("BestQuality", out result))
((DoubleValue)result.Value).Value = Context.BestQuality;
else Results.Add(new Result("BestQuality", new DoubleValue(Context.BestQuality)));
Context.RunOperator(Analyzer, CancellationToken.None);
}
cplex.End();
}
Context.RunOperator(Analyzer, CancellationToken.None);
}
protected abstract OplModel GetModel(OplFactory factory, OplSettings settings, Cplex cplex);
}
public class LogCallback : Cplex.MIPInfoCallback {
private CplexSolver algorithm;
private CancellationToken token;
private double prev;
public LogCallback(CplexSolver algorithm, CancellationToken token) {
this.algorithm = algorithm;
this.token = token;
prev = double.NaN;
}
protected override void Main() {
if (HasIncumbent()) {
var val = GetIncumbentObjValue();
if (val >= prev) return;
algorithm.Context.Iterations++;
algorithm.Context.BestQuality = val;
IResult result;
if (algorithm.Results.TryGetValue("Iterations", out result))
((IntValue)result.Value).Value = algorithm.Context.Iterations;
else algorithm.Results.Add(new Result("Iterations", new IntValue(algorithm.Context.Iterations)));
if (algorithm.Results.TryGetValue("BestQuality", out result))
((DoubleValue)result.Value).Value = algorithm.Context.BestQuality;
else algorithm.Results.Add(new Result("BestQuality", new DoubleValue(algorithm.Context.BestQuality)));
algorithm.Context.RunOperator(algorithm.Analyzer, CancellationToken.None);
prev = val;
if (val.IsAlmost(algorithm.Problem.BestKnownQuality))
Abort();
}
if (token.IsCancellationRequested) Abort();
}
}
}