namespace HeuristicLab.Problems.ProgramSynthesis.Push.Configuration { using System; using System.Collections.Generic; using System.Linq; using Base.Erc; using Common; using Core; using Expressions; using Persistence.Default.CompositeSerializers.Storable; using Stack; [StorableClass] public class PushConfiguration : ParameterizedNamedItem, IReadOnlyPushConfiguration, IEnabledExpressionsConfiguration { public PushConfiguration() { Name = "Push Configuration"; enabledExpressions = ExpressionTable.ExpressionNames.ToList(); enabledStacks = new Dictionary(); ErcOptions = new ErcOptions(); EvalPushLimit = 1024; MinPointsInProgram = 25; MaxPointsInProgram = 200; TopLevelPushCode = true; TopLevelPopCode = false; MaxPointsInRandomExpression = 64; MaxStringLength = 128; MaxVectorLength = 64; MaxDepth = 32; InitEnabledStacks(); } private void InitEnabledStacks(bool state = true) { foreach (StackTypes type in Enum.GetValues(typeof(StackTypes))) { if (!enabledStacks.ContainsKey(type) && type != StackTypes.None) enabledStacks.Add(type, state); } } [StorableConstructor] public PushConfiguration(bool deserializing) : base(deserializing) { } public PushConfiguration(PushConfiguration origin, Cloner cloner) : base(origin, cloner) { enabledExpressions = origin.EnabledExpressions.ToList(); enabledStacks = origin.EnabledStacks.ToDictionary(x => x.Key, x => x.Value); ErcOptions = cloner.Clone(origin.ErcOptions); EvalPushLimit = origin.EvalPushLimit; MinPointsInProgram = origin.MinPointsInProgram; MaxPointsInProgram = origin.MaxPointsInProgram; MaxPointsInRandomExpression = origin.MaxPointsInRandomExpression; TopLevelPushCode = origin.TopLevelPushCode; TopLevelPopCode = origin.TopLevelPopCode; MaxStringLength = origin.MaxStringLength; MaxVectorLength = origin.MaxVectorLength; MaxDepth = origin.MaxDepth; } [StorableHook(HookType.AfterDeserialization)] // ReSharper disable once UnusedMember.Local private void AfterDeserialization() { // Ensures that all types added after last serialization are available in enabledStacks InitEnabledStacks(false); } [Storable] private readonly Dictionary enabledStacks; public IReadOnlyDictionary EnabledStacks { get { return enabledStacks; } } public event EventHandler EnabledExpressionsChanged; [Storable] private readonly List enabledExpressions; public IList EnabledExpressions { get { return enabledExpressions; } set { var removedExpressions = enabledExpressions.ToArray(); enabledExpressions.Clear(); enabledExpressions.AddRange(value); if (EnabledExpressionsChanged != null) { EnabledExpressionsChanged(this, new EnabledExpressionsChangedEventArgs(value, removedExpressions)); } } } IReadOnlyList IReadOnlyPushConfiguration.EnabledExpressions { get { return enabledExpressions; } } [Storable] public ErcOptions ErcOptions { get; set; } IReadOnlyErcOptions IReadOnlyPushConfiguration.ErcOptions { get { return ErcOptions; } } /// /// This is the maximum allowed number of "executions" in a single top-level call to the interpreter. /// The execution of a single Push instruction counts as one execution, as does the processing of a single literal, /// as does the descent into one layer of parentheses (that is, the processing of the "(" counts as one execution). /// When this limit is exceeded the interpreter aborts immediately, leaving its stacks in the states they were in prior /// to the abort (so they may still be examined by a calling program). Whether or not this counts as an "abnormal" /// termination /// is up to the calling program. /// [Storable] public int EvalPushLimit { get; set; } /// /// This is the maximum of depth a push program can have. Expressions, which lead to exceed this limit are interpreted as NOOP. /// [Storable] public int MaxDepth { get; set; } /// /// This is the minimum size of an item on the CODE stack, expressed as a number of points. /// A point is an instruction, a literal, or a pair of parentheses. Any instruction that would cause this limit to be /// exceeded should instead act as a NOOP, leaving all stacks in the states that they were in before the execution of the /// instruction. /// [Storable] public int MinPointsInProgram { get; set; } /// /// This is the maximum size of an item on the CODE stack, expressed as a number of points. /// A point is an instruction, a literal, or a pair of parentheses. Any instruction that would cause this limit to be /// exceeded should instead act as a NOOP, leaving all stacks in the states that they were in before the execution of the /// instruction. /// [Storable] public int MaxPointsInProgram { get; set; } /// /// The maximum number of points in an expression produced by the CODE.RAND instruction. /// [Storable] public int MaxPointsInRandomExpression { get; set; } /// /// When TRUE (which is the default), code passed to the top level of the interpreter /// will be pushed onto the CODE stack prior to execution. /// [Storable] public bool TopLevelPushCode { get; set; } /// /// When TRUE, the CODE stack will be popped at the end of top level calls to the interpreter. The default is FALSE. /// [Storable] public bool TopLevelPopCode { get; set; } [Storable] public int MaxStringLength { get; set; } [Storable] public int MaxVectorLength { get; set; } public void SetEnabledStacks(StackTypes types) { // Disable all EnabledExpressions.Clear(); foreach (StackTypes type in Enum.GetValues(types.GetType())) { if (type == StackTypes.None) continue; enabledStacks[type] = false; } foreach (var pair in ExpressionTable.StackDependencyToNamesTable) { if (types.HasFlag(pair.Key)) { foreach (var name in pair.Value) { EnableExpression(name, true); } } } } public void EnableExpressionOfStack(StackTypes types) { EnableExpressions(ExpressionTable.StackTypeToNamesTable[types]); } public void EnableExpressionDependentOnStack(StackTypes types) { var names = ExpressionTable.StackDependencyToNamesTable[types].Where( name => { var type = ExpressionTable.NameToTypeTable[name]; var attribute = ExpressionTable.TypeToAttributeTable[type]; return (attribute.StackType | attribute.AdditionalStackDependencies) .ToEnumerable() .All(st => enabledStacks.ContainsKey(st) && enabledStacks[st]); }); EnableExpressions(names); } private void EnableExpressions(IEnumerable names) { foreach (var name in names.Except(EnabledExpressions)) EnabledExpressions.Add(name); if (EnabledExpressionsChanged != null) { EnabledExpressionsChanged(this, new EnabledExpressionsChangedEventArgs(names, new string[0])); } } public void DisableExpressionsOfStack(StackTypes types) { DisableExpressions(ExpressionTable.StackTypeToNamesTable[types]); } public void DisableExpressionsDependentOnStack(StackTypes types) { var names = ExpressionTable.StackDependencyToNamesTable .Where(pair => pair.Key.HasFlag(types)) .SelectMany(pair => pair.Value); DisableExpressions(names); } private void DisableExpressions(IEnumerable names) { foreach (var name in names.Intersect(EnabledExpressions)) EnabledExpressions.Remove(name); if (EnabledExpressionsChanged != null) { EnabledExpressionsChanged(this, new EnabledExpressionsChangedEventArgs(new string[0], names)); } } public void EnableExpression(string name, bool enableStackIfDisabled = false) { if (EnabledExpressions.Contains(name)) return; EnabledExpressions.Add(name); if (enableStackIfDisabled) { var type = ExpressionTable.TypeToNameTable.Single(x => x.Value == name).Key; var attribute = ExpressionTable.TypeToAttributeTable[type]; enabledStacks[attribute.StackType] = true; } if (EnabledExpressionsChanged != null) { EnabledExpressionsChanged(this, new EnabledExpressionsChangedEventArgs( new[] { name }, new string[0])); } } public void DisableExpression(string name, bool disableStackIfEnabled = false) { if (!EnabledExpressions.Contains(name)) return; EnabledExpressions.Remove(name); if (disableStackIfEnabled) { var type = ExpressionTable.TypeToNameTable.Single(x => x.Value == name).Key; var attribute = ExpressionTable.TypeToAttributeTable[type]; enabledStacks[attribute.StackType] = false; } if (EnabledExpressionsChanged != null) { EnabledExpressionsChanged(this, new EnabledExpressionsChangedEventArgs( new string[0], new[] { name })); } } public void EnableExpression(bool enableStackIfDisabled = false) where T : Expression { var attribute = ExpressionTable.TypeToAttributeTable[typeof(T)]; EnableExpression(attribute.ExpressionName, enableStackIfDisabled); } public void DisableExpression(bool disableStackIfEnabled = false) where T : Expression { var attribute = ExpressionTable.TypeToAttributeTable[typeof(T)]; DisableExpression(attribute.ExpressionName, disableStackIfEnabled); } public void SetExpression(string name, bool state, bool cascadeForStack = false) { if (state) EnableExpression(name, cascadeForStack); else DisableExpression(name, cascadeForStack); } public void SetExpression(bool state, bool cascadeForStack = false) where T : Expression { if (state) EnableExpression(cascadeForStack); else DisableExpression(cascadeForStack); } public void EnableStack(StackTypes type, bool enableExpressions = true, bool enableDependencies = true) { enabledStacks[type] = true; if (enableExpressions) EnableExpressionOfStack(type); if (enableDependencies) EnableExpressionDependentOnStack(type); } public void DisableStack(StackTypes type, bool disableExpressions = true, bool disableDependencies = true) { enabledStacks[type] = false; if (disableExpressions) DisableExpressionsOfStack(type); if (disableDependencies) DisableExpressionsDependentOnStack(type); } public void SetStack(StackTypes type, bool state, bool setExpressions = true, bool setDependencies = true) { if (state) EnableStack(type, setExpressions, setDependencies); else DisableStack(type, setExpressions, setDependencies); } public override IDeepCloneable Clone(Cloner cloner) { return new PushConfiguration(this, cloner); } } }