#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
namespace HeuristicLab.Problems.ProgramSynthesis.Push.Selector {
using System;
using System.Collections.Generic;
using System.Linq;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.Problems.ProgramSynthesis.Push.Problem;
using HeuristicLab.Random;
using HeuristicLab.Selection;
///
/// A lexicase selection operator which considers all successful evaluated training cases for selection.
///
[Item("LexicaseSelector", "A lexicase selection operator which considers all successful evaluated training cases for selection.")]
[StorableClass]
public sealed class LexicaseSelector : StochasticSingleObjectiveSelector, ICaseSingleObjectiveSelector {
public ILookupParameter> CaseQualitiesParameter
{
get { return (ILookupParameter>)Parameters[IntegerVectorPushProblem.CaseQualitiesScopeParameterName]; }
}
[StorableConstructor]
private LexicaseSelector(bool deserializing) : base(deserializing) { }
private LexicaseSelector(LexicaseSelector original, Cloner cloner) : base(original, cloner) { }
public override IDeepCloneable Clone(Cloner cloner) {
return new LexicaseSelector(this, cloner);
}
public LexicaseSelector() {
Parameters.Add(new ScopeTreeLookupParameter(
IntegerVectorPushProblem.CaseQualitiesScopeParameterName,
"The quality of every single training case for each individual."));
}
protected override IScope[] Select(List scopes) {
var count = NumberOfSelectedSubScopesParameter.ActualValue.Value;
var copy = CopySelectedParameter.Value.Value;
var random = RandomParameter.ActualValue;
var maximization = MaximizationParameter.ActualValue.Value;
var caseQualities = CaseQualitiesParameter.ActualValue.ToList();
var selected = Apply(
scopes,
count,
copy,
maximization,
random,
caseQualities);
return selected;
}
public static IScope[] Apply(
List scopes,
int count,
bool copy,
bool maximization,
IRandom random,
List caseQualities) {
for (var i = 0; i < caseQualities.Count; i++) {
if (caseQualities[i].Length == 0) {
scopes.RemoveAt(i);
caseQualities.RemoveAt(i);
}
}
var qualitiesLength = caseQualities[0].Length;
if (caseQualities.Any(x => x.Length != qualitiesLength)) {
throw new ArgumentException("Not all case qualities have the same length");
}
var selected = new IScope[count];
var candidates = new List(caseQualities.Count);
for (var i = 0; i < caseQualities.Count; i++) candidates.Add(i);
var orderSource = new List(qualitiesLength);
for (var i = 0; i < qualitiesLength; i++) orderSource.Add(i);
for (var i = 0; i < count; i++) {
var index = LexicaseSelect(
caseQualities,
candidates,
orderSource.Shuffle(random),
random,
maximization);
if (copy) {
selected[i] = (IScope)scopes[index].Clone();
} else {
selected[i] = scopes[index];
scopes.RemoveAt(index);
caseQualities.RemoveAt(index);
}
}
return selected;
}
private static int LexicaseSelect(
List caseQualities,
List candidates,
IEnumerable order,
IRandom random,
bool maximization) {
foreach (var curCase in order) {
var nextCandidates = new List();
var best = maximization
? double.NegativeInfinity
: double.PositiveInfinity;
for (var i = 0; i < candidates.Count; i++) {
var candidate = candidates[i];
var caseQuality = caseQualities[candidate][curCase];
if (caseQuality.IsAlmost(best)) {
// if the individuals is as good as the best one, add it
nextCandidates.Add(candidate);
} else if (
(maximization && (caseQuality > best)) ||
(!maximization && (caseQuality < best))) {
// if the individual is better than the best one, remove all previous candidates and add the new one
nextCandidates.Clear();
nextCandidates.Add(candidate);
// also set the next best quality value
best = caseQuality;
}
// else {do nothing}
}
if (nextCandidates.Count == 1) {
return nextCandidates[0];
}
if (nextCandidates.Count < 1) {
return candidates.SampleRandom(random);
}
candidates = nextCandidates;
}
return candidates.Count == 1
? candidates[0]
: candidates.SampleRandom(random);
}
}
}