#region License Information
/* HeuristicLab
* Copyright (C) 2002-2015 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.Linq;
using HeuristicLab.Analysis;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.RealVectorEncoding;
using HeuristicLab.Operators;
using HeuristicLab.Optimization;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Algorithms.GradientDescent {
[StorableClass]
[Item(Name = "LBFGS Analyzer", Description = "Analyzer to collect results for the LM-BFGS algorithm.")]
public sealed class LbfgsAnalyzer : SingleSuccessorOperator, IAnalyzer {
private const string PointParameterName = "Point";
private const string QualityGradientsParameterName = "QualityGradients";
private const string QualityParameterName = "Quality";
private const string ResultCollectionParameterName = "Results";
private const string QualitiesTableParameterName = "Qualities";
private const string PointsTableParameterName = "PointTable";
private const string QualityGradientsTableParameterName = "QualityGradientsTable";
private const string StateParameterName = "State";
private const string ApproximateGradientsParameterName = "ApproximateGradients";
#region Parameter Properties
public ILookupParameter QualityGradientsParameter {
get { return (ILookupParameter)Parameters[QualityGradientsParameterName]; }
}
public ILookupParameter PointParameter {
get { return (ILookupParameter)Parameters[PointParameterName]; }
}
public ILookupParameter QualityParameter {
get { return (ILookupParameter)Parameters[QualityParameterName]; }
}
public ILookupParameter ResultCollectionParameter {
get { return (ILookupParameter)Parameters[ResultCollectionParameterName]; }
}
public ILookupParameter QualitiesTableParameter {
get { return (ILookupParameter)Parameters[QualitiesTableParameterName]; }
}
public ILookupParameter PointsTableParameter {
get { return (ILookupParameter)Parameters[PointsTableParameterName]; }
}
public ILookupParameter QualityGradientsTableParameter {
get { return (ILookupParameter)Parameters[QualityGradientsTableParameterName]; }
}
public ILookupParameter StateParameter {
get { return (ILookupParameter)Parameters[StateParameterName]; }
}
public ILookupParameter ApproximateGradientsParameter {
get { return (ILookupParameter)Parameters[ApproximateGradientsParameterName]; }
}
#endregion
#region Properties
private RealVector QualityGradients { get { return QualityGradientsParameter.ActualValue; } }
private RealVector Point { get { return PointParameter.ActualValue; } }
private DoubleValue Quality { get { return QualityParameter.ActualValue; } }
private ResultCollection ResultCollection { get { return ResultCollectionParameter.ActualValue; } }
private BoolValue ApproximateGradients { get { return ApproximateGradientsParameter.ActualValue; } }
public bool EnabledByDefault {
get { return true; }
}
#endregion
[StorableConstructor]
private LbfgsAnalyzer(bool deserializing) : base(deserializing) { }
private LbfgsAnalyzer(LbfgsAnalyzer original, Cloner cloner) : base(original, cloner) { }
public LbfgsAnalyzer()
: base() {
// in
Parameters.Add(new LookupParameter(PointParameterName, "The current point of the function to optimize."));
Parameters.Add(new LookupParameter(QualityGradientsParameterName, "The current gradients of the function to optimize."));
Parameters.Add(new LookupParameter(QualityParameterName, "The current value of the function to optimize."));
Parameters.Add(new LookupParameter(QualitiesTableParameterName, "The table of all visited quality values."));
Parameters.Add(new LookupParameter(PointsTableParameterName, "The table of all visited points."));
Parameters.Add(new LookupParameter(QualityGradientsTableParameterName, "The table of all visited gradient values."));
Parameters.Add(new LookupParameter(StateParameterName, "The state of the LM-BFGS optimization algorithm."));
Parameters.Add(new LookupParameter(ApproximateGradientsParameterName,
"Flag that indicates if gradients should be approximated."));
// in & out
Parameters.Add(new LookupParameter(ResultCollectionParameterName, "The result collection of the algorithm."));
}
public override IDeepCloneable Clone(Cloner cloner) {
return new LbfgsAnalyzer(this, cloner);
}
public override IOperation Apply() {
if (StateParameter.ActualValue.State.xupdated) {
var f = Quality.Value;
double[] g;
if (ApproximateGradients.Value) {
g = StateParameter.ActualValue.State.g;
} else {
g = QualityGradients.ToArray();
}
var x = Point.ToArray();
var resultCollection = ResultCollection;
// create and add tables on the first time
if (QualitiesTableParameter.ActualValue == null) {
QualitiesTableParameter.ActualValue = new DataTable(QualityParameter.ActualName);
PointsTableParameter.ActualValue = new DataTable(PointParameter.ActualName);
QualityGradientsTableParameter.ActualValue = new DataTable(QualityGradientsParameter.ActualName);
QualitiesTableParameter.ActualValue.Rows.Add(new DataRow(QualityParameter.ActualName));
resultCollection.Add(new Result(QualitiesTableParameter.ActualName,
QualitiesTableParameter.ActualValue));
resultCollection.Add(new Result(PointsTableParameter.ActualName,
PointsTableParameter.ActualValue));
resultCollection.Add(new Result(QualityGradientsTableParameter.ActualName,
QualityGradientsTableParameter.ActualValue));
resultCollection.Add(new Result(QualityParameter.ActualName, QualityParameter.ActualValue));
}
// update
var functionValueRow = QualitiesTableParameter.ActualValue.Rows[QualityParameter.ActualName];
resultCollection[QualityParameter.ActualName].Value = Quality;
functionValueRow.Values.Add(f);
AddValues(g, QualityGradientsTableParameter.ActualValue);
AddValues(x, PointsTableParameter.ActualValue);
}
return base.Apply();
}
private void AddValues(double[] x, DataTable dataTable) {
if (!dataTable.Rows.Any()) {
for (int i = 0; i < x.Length; i++) {
var newRow = new DataRow("x" + i);
newRow.Values.Add(x[i]);
dataTable.Rows.Add(newRow);
}
} else {
for (int i = 0; i < x.Length; i++) {
dataTable.Rows.ElementAt(i).Values.Add(x[i]);
}
}
}
}
}