#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 HeuristicLab.Common;
namespace HeuristicLab.Problems.DataAnalysis {
public class OnlineLinearScalingParameterCalculator : DeepCloneable {
///
/// Additive constant
///
public double Alpha {
get {
return targetMeanCalculator.Mean - Beta * originalMeanAndVarianceCalculator.Mean;
}
}
///
/// Multiplicative factor
///
public double Beta {
get {
if (originalMeanAndVarianceCalculator.PopulationVariance.IsAlmost(0.0))
return 1;
else
return originalTargetCovarianceCalculator.Covariance / originalMeanAndVarianceCalculator.PopulationVariance;
}
}
public OnlineCalculatorError ErrorState {
get {
return targetMeanCalculator.MeanErrorState | originalMeanAndVarianceCalculator.MeanErrorState |
originalMeanAndVarianceCalculator.PopulationVarianceErrorState | originalTargetCovarianceCalculator.ErrorState;
}
}
private readonly OnlineMeanAndVarianceCalculator targetMeanCalculator;
private readonly OnlineMeanAndVarianceCalculator originalMeanAndVarianceCalculator;
private readonly OnlineCovarianceCalculator originalTargetCovarianceCalculator;
public OnlineLinearScalingParameterCalculator() {
targetMeanCalculator = new OnlineMeanAndVarianceCalculator();
originalMeanAndVarianceCalculator = new OnlineMeanAndVarianceCalculator();
originalTargetCovarianceCalculator = new OnlineCovarianceCalculator();
Reset();
}
protected OnlineLinearScalingParameterCalculator(OnlineLinearScalingParameterCalculator original, Cloner cloner)
: base(original, cloner) {
targetMeanCalculator = cloner.Clone(original.targetMeanCalculator);
originalMeanAndVarianceCalculator = cloner.Clone(original.originalMeanAndVarianceCalculator);
originalTargetCovarianceCalculator = cloner.Clone(original.originalTargetCovarianceCalculator);
// do not reset the calculators here
}
public override IDeepCloneable Clone(Cloner cloner) {
return new OnlineLinearScalingParameterCalculator(this, cloner);
}
public void Reset() {
targetMeanCalculator.Reset();
originalMeanAndVarianceCalculator.Reset();
originalTargetCovarianceCalculator.Reset();
}
///
/// Calculates linear scaling parameters in one pass.
/// The formulas to calculate the scaling parameters were taken from Scaled Symblic Regression by Maarten Keijzer.
/// http://www.springerlink.com/content/x035121165125175/
///
public void Add(double original, double target) {
// validity of values is checked in mean calculator and covariance calculator
targetMeanCalculator.Add(target);
originalMeanAndVarianceCalculator.Add(original);
originalTargetCovarianceCalculator.Add(original, target);
}
///
/// Calculates alpha and beta parameters to linearly scale elements of original to the scale and location of target
/// original[i] * beta + alpha
///
/// Values that should be scaled
/// Target values to which the original values should be scaled
/// Additive constant for the linear scaling
/// Multiplicative factor for the linear scaling
/// Flag that indicates if errors occurred in the calculation of the linea scaling parameters.
public static void Calculate(IEnumerable original, IEnumerable target, out double alpha, out double beta, out OnlineCalculatorError errorState) {
OnlineLinearScalingParameterCalculator calculator = new OnlineLinearScalingParameterCalculator();
IEnumerator originalEnumerator = original.GetEnumerator();
IEnumerator targetEnumerator = target.GetEnumerator();
// always move forward both enumerators (do not use short-circuit evaluation!)
while (originalEnumerator.MoveNext() & targetEnumerator.MoveNext()) {
double originalElement = originalEnumerator.Current;
double targetElement = targetEnumerator.Current;
calculator.Add(originalElement, targetElement);
if (calculator.ErrorState != OnlineCalculatorError.None) break;
}
// check if both enumerators are at the end to make sure both enumerations have the same length
if (calculator.ErrorState == OnlineCalculatorError.None &&
(originalEnumerator.MoveNext() || targetEnumerator.MoveNext())) {
throw new ArgumentException("Number of elements in original and target enumeration do not match.");
} else {
errorState = calculator.ErrorState;
alpha = calculator.Alpha;
beta = calculator.Beta;
}
}
}
}