#region License Information /* HeuristicLab * Copyright (C) 2002-2010 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.Linq; using alglib; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using System.Collections.Generic; namespace HeuristicLab.Problems.DataAnalysis.Operators { [Item("DynOpEqHistogramInitializer", "Dynamic Operator Equalization Histogram Initializer.")] [StorableClass] public class DynOpEqHistogramInitializer : SingleSuccessorOperator { public ILookupParameter> BinCapacityParameter { get { return (ILookupParameter>)Parameters["BinCapacity"]; } } public ILookupParameter>> AcceptedBinQualitiesParameter { get { return (ILookupParameter>>)Parameters["AcceptedBinQualities"]; } } public ILookupParameter PopulationSizeParameter { get { return (ILookupParameter)Parameters["PopulationSize"]; } } public IScopeTreeLookupParameter SymbolicExpressionTreeParameter { get { return (IScopeTreeLookupParameter)Parameters["SymbolicExpressionTree"]; } } public IScopeTreeLookupParameter QualityParameter { get { return (IScopeTreeLookupParameter)Parameters["Quality"]; } } public ILookupParameter BinSizeParameter { get { return (ILookupParameter)Parameters["BinSize"]; } } public ILookupParameter> AcceptedCountsParameter { get { return (ILookupParameter>)Parameters["AcceptedCounts"]; } } public ILookupParameter> TotalCountsParameter { get { return (ILookupParameter>)Parameters["TotalCounts"]; } } public ILookupParameter MaximizationParameter { get { return (ILookupParameter)Parameters["Maximization"]; } } public DynOpEqHistogramInitializer() : base() { Parameters.Add(new ScopeTreeLookupParameter("SymbolicExpressionTree")); Parameters.Add(new ScopeTreeLookupParameter("Quality")); Parameters.Add(new LookupParameter("PopulationSize")); Parameters.Add(new ValueLookupParameter("BinSize", new IntValue(5))); Parameters.Add(new LookupParameter>("BinCapacity")); Parameters.Add(new LookupParameter>>("AcceptedBinQualities")); Parameters.Add(new LookupParameter>("AcceptedCounts")); Parameters.Add(new LookupParameter>("TotalCounts")); Parameters.Add(new LookupParameter("Maximization")); } public override IOperation Apply() { if (BinCapacityParameter.ActualValue == null) { InitDefaultCapacityHistogram(); } else { ItemList> acceptedBinQualities = AcceptedBinQualitiesParameter.ActualValue; ItemList acceptedCounts = AcceptedCountsParameter.ActualValue; ItemList totalCounts = TotalCountsParameter.ActualValue; int popSize = PopulationSizeParameter.ActualValue.Value; ScaleBinQualities(acceptedBinQualities, 0, 1, MaximizationParameter.ActualValue.Value); double avgQualitySum = (from binAccepted in acceptedBinQualities where binAccepted.Count > 0 select (from quality in binAccepted select quality.Value).Average()) .Sum(); ItemList binCapacity = BinCapacityParameter.ActualValue; int totalCapacity = 0; for (int i = 0; i < binCapacity.Count; i++) { double avgBinQuality = (from quality in acceptedBinQualities[i] select quality.Value) .DefaultIfEmpty(0.0) .Average(); binCapacity[i].Value = Math.Max(1, (int)Math.Round(popSize * (avgBinQuality / avgQualitySum))); // rounding can lead to loss of capacity // this is problematic if the bin capacities are strict totalCapacity += binCapacity[i].Value; acceptedBinQualities[i].Clear(); acceptedCounts[i].Value = 0; } // distribute the remaining slots starting with the largest bins IEnumerator orderedBinCapacities = binCapacity.OrderBy(x => -x.Value).GetEnumerator(); while (totalCapacity < popSize & orderedBinCapacities.MoveNext()) { orderedBinCapacities.Current.Value = orderedBinCapacities.Current.Value + 1; totalCapacity++; } if (totalCapacity < popSize) throw new InvalidProgramException("The sum of bin capacities doesn't match the population size"); for (int i = 0; i < totalCounts.Count; i++) totalCounts[i].Value = 0; } return base.Apply(); } public static void ScaleBinQualities(ItemList> acceptedBinQualities, double min, double max, bool maximization) { double minValue = (from bin in acceptedBinQualities from value in bin select value.Value).Min(); double maxValue = (from bin in acceptedBinQualities from value in bin select value.Value).Max(); if (!maximization) { double tmp = minValue; minValue = maxValue; maxValue = tmp; } double valuesRange = maxValue - minValue; double targetRange = max - min; foreach (var bin in acceptedBinQualities) { foreach (var value in bin) { double unitScaledValue = (value.Value - minValue) / valuesRange; double targetScaledValue = unitScaledValue * targetRange + min; value.Value = targetScaledValue; } } } private void InitDefaultCapacityHistogram() { ItemArray trees = SymbolicExpressionTreeParameter.ActualValue; ItemArray quality = QualityParameter.ActualValue; var binCapacities = new ItemList(); var acceptedQuality = new ItemList>(20); var acceptedCounts = new ItemList(); var totalCounts = new ItemList(); BinCapacityParameter.ActualValue = binCapacities; AcceptedBinQualitiesParameter.ActualValue = acceptedQuality; TotalCountsParameter.ActualValue = totalCounts; AcceptedCountsParameter.ActualValue = acceptedCounts; for (int i = 0; i < trees.Length; i++) { int binIndex = GetBinIndexForSize(trees[i].Size); if (Exists(binIndex)) { AddToBin(binIndex, quality[i].Value); } else { CreateNewBin(binIndex); } } } private void CreateNewBin(int binIndex) { ItemList binCapacities = BinCapacityParameter.ActualValue; ItemList> acceptedQualities = AcceptedBinQualitiesParameter.ActualValue; ItemList acceptedCounts = AcceptedCountsParameter.ActualValue; ItemList totalCounts = TotalCountsParameter.ActualValue; for (int i = binCapacities.Count; i <= binIndex; i++) { binCapacities.Add(new IntValue(1)); acceptedQualities.Add(new ItemList(10)); acceptedCounts.Add(new IntValue(0)); totalCounts.Add(new IntValue(0)); } } private void AddToBin(int binIndex, double quality) { ItemList binCapacity = BinCapacityParameter.ActualValue; binCapacity[binIndex].Value = binCapacity[binIndex].Value + 1; } private bool Exists(int binIndex) { // if the bin has a capacity set then it exists ItemList binCapacities = BinCapacityParameter.ActualValue; return binIndex < binCapacities.Count; } private int GetBinIndexForSize(int size) { int binSize = ((IntValue)BinSizeParameter.ActualValue).Value; return (int)Math.Floor((size - 3.0) / binSize); } } }