namespace HeuristicLab.Problems.ProgramSynthesis.Push.Analyzer {
using System;
using System.Collections.Generic;
using System.Linq;
using HeuristicLab.Analysis;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.IntegerVectorEncoding;
using HeuristicLab.Operators;
using HeuristicLab.Optimization;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.Problems.ProgramSynthesis.Push.Attributes;
using HeuristicLab.Problems.ProgramSynthesis.Push.Configuration;
using HeuristicLab.Problems.ProgramSynthesis.Push.Encoding;
using HeuristicLab.Problems.ProgramSynthesis.Push.Expressions;
using HeuristicLab.Problems.ProgramSynthesis.Push.Individual;
///
/// An operater that tracks the frequencies of distinct push expressions in a push solution
///
[Item("PushExpressionFrequencyAnalyzer", "An operater that tracks the frequencies of distinct push expressions in a push solution")]
[StorableClass]
public class PushExpressionFrequencyAnalyzer : SingleSuccessorOperator, IPushExpressionAnalyzer {
private const string PUSH_CONFIGURATION_PARAMETER_NAME = "PushConfiguration";
private const string INTEGER_VECTOR_PARAMETER_NAME = "IntegerVector";
private const string RESULTS_PARAMETER_NAME = "Results";
private const string EXPRESSION_FREQUENCIES_PARAMETER_NAME = "InstructionFrequencies";
private const string AGGREGATE_STACK_TYPES_PARAMETER_NAME = "Aggregate stack types";
private const string IN_EXPRESSION_GROUP_NAME = "IN";
private const string RANDOM_PARAMETER_NAME = "Random";
private const string RESULT_PARAMETER_NAME = "Instruction frequencies";
private const string RESULT_PARAMETER_DESCRIPTION = "Relative frequency of instructions aggregated over the whole population.";
private const string Y_AXIS_TITLE = "Relative Instruction Frequency";
public PushExpressionFrequencyAnalyzer() {
Parameters.Add(new LookupParameter(PUSH_CONFIGURATION_PARAMETER_NAME, "The current specified push configuration."));
Parameters.Add(new ScopeTreeLookupParameter(INTEGER_VECTOR_PARAMETER_NAME, "The integer vectors to analyze."));
Parameters.Add(new ScopeTreeLookupParameter("Plush", "The plush vectors to analyze."));
Parameters.Add(new LookupParameter(EXPRESSION_FREQUENCIES_PARAMETER_NAME, "The data table to store the instruction frequencies."));
Parameters.Add(new LookupParameter(RESULTS_PARAMETER_NAME, "The result collection where the symbol frequencies should be stored."));
Parameters.Add(new FixedValueParameter(AGGREGATE_STACK_TYPES_PARAMETER_NAME, "Determines if expressions should be aggregated by their primary stack type.", new BoolValue(true)));
}
[StorableConstructor]
public PushExpressionFrequencyAnalyzer(bool deserializing) : base(deserializing) { }
public PushExpressionFrequencyAnalyzer(PushExpressionFrequencyAnalyzer origin, Cloner cloner) : base(origin, cloner) { }
public override IDeepCloneable Clone(Cloner cloner) {
return new PushExpressionFrequencyAnalyzer(this, cloner);
}
public bool EnabledByDefault { get { return true; } }
public ILookupParameter PushConfigurationParameter
{
get { return (ILookupParameter)Parameters[PUSH_CONFIGURATION_PARAMETER_NAME]; }
}
public IScopeTreeLookupParameter PlushVectorParameter
{
get { return (IScopeTreeLookupParameter)Parameters["Plush"]; }
}
public IScopeTreeLookupParameter IntegerVectorParameter
{
get { return (IScopeTreeLookupParameter)Parameters[INTEGER_VECTOR_PARAMETER_NAME]; }
}
public ILookupParameter ExpressionFrequenciesParameter
{
get { return (ILookupParameter)Parameters[EXPRESSION_FREQUENCIES_PARAMETER_NAME]; }
}
public ILookupParameter RandomParameter
{
get { return (ILookupParameter)Parameters[RANDOM_PARAMETER_NAME]; }
}
public ILookupParameter ResultsParameter
{
get { return (ILookupParameter)Parameters[RESULTS_PARAMETER_NAME]; }
}
public IValueParameter AggregateStackTypesParameter
{
get { return (IValueParameter)Parameters[AGGREGATE_STACK_TYPES_PARAMETER_NAME]; }
}
public bool AggregateStackTypes
{
get { return AggregateStackTypesParameter.Value.Value; }
set { AggregateStackTypesParameter.Value.Value = value; }
}
public override IOperation Apply() {
var config = PushConfigurationParameter.ActualValue;
IReadOnlyList pushPrograms = null;
if (IntegerVectorParameter.ActualValue.Length > 0) {
pushPrograms = IntegerVectorParameter.ActualValue.Select(iv => iv.ToPushProgram(config)).ToList();
} else if (PlushVectorParameter.ActualValue.Length > 0) {
pushPrograms = PlushVectorParameter.ActualValue.Select(pv => pv.PushProgram).ToList();
} else {
// nothing to do
return base.Apply();
}
var results = ResultsParameter.ActualValue;
var frequencies = ExpressionFrequenciesParameter.ActualValue;
if (frequencies == null) {
frequencies = new DataTable(
RESULT_PARAMETER_NAME,
RESULT_PARAMETER_DESCRIPTION) {
VisualProperties = {
YAxisTitle = Y_AXIS_TITLE
}
};
ExpressionFrequenciesParameter.ActualValue = frequencies;
results.Add(new Result(RESULT_PARAMETER_NAME, frequencies));
}
var allExpressions = pushPrograms
.SelectMany(p => p.DepthLast())
.Select(e => new {
Expression = e,
Attribute = ExpressionTable.TypeToAttributeTable[e.GetType()]
});
var expressionFrequencies = allExpressions
.GroupBy(x => GetGroupName(x.Attribute, AggregateStackTypes))
.ToDictionary(
group => group.Key,
group => group.Count());
var totalNumberOfExpressions = Math.Max(1.0, expressionFrequencies.Values.Sum());
// all rows must have the same number of values so we can just take the first
var numberOfValues = frequencies.Rows.Select(r => r.Values.Count).FirstOrDefault();
foreach (var pair in expressionFrequencies) {
if (!frequencies.Rows.ContainsKey(pair.Key)) {
var row = new DataRow(pair.Key, string.Empty, Enumerable.Repeat(0.0, numberOfValues)) {
VisualProperties = {
StartIndexZero = true,
}
};
frequencies.Rows.Add(row);
}
frequencies.Rows[pair.Key].Values.Add(Math.Round(pair.Value / totalNumberOfExpressions, 3));
}
// add a zero for each data row that was not modified in the previous loop
foreach (var row in frequencies.Rows.Where(r => r.Values.Count != numberOfValues + 1))
row.Values.Add(0.0);
return base.Apply();
}
private string GetGroupName(PushExpressionAttribute attribute, bool aggregateStackTypes) {
if (aggregateStackTypes) {
return attribute.IsInExpression
? IN_EXPRESSION_GROUP_NAME
: attribute.StackType.ToString();
}
return attribute.Name;
}
}
}