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; } } }