/// /// For explicit code manipulation and execution. May also be used as a general list data type. /// This type must always be present, as the top level interpreter will push any code to be executed on the /// CODE stack prior to execution. However, one may turn off all CODE instructions if code manipulation is not needed. /// namespace HeuristicLab.Problems.ProgramSynthesis.Push.Expressions { using System; using System.Collections.Generic; using System.Linq; using HeuristicLab.Problems.ProgramSynthesis.Push.Attributes; using HeuristicLab.Problems.ProgramSynthesis.Push.Stack; using Interpreter; /// /// Recursively invokes the interpreter on the program on top of the CODE stack. After evaluation the /// CODE stack is popped; normally this pops the program that was just executed, but if the expression itself /// manipulates the stack then this final pop may end up popping something else. /// [PushExpression(StackType.Code, "CODE.DO")] public class CodeDoExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { // not enough arguments on stack if (interpreter.CodeStack.Count == 0) return false; var codePopExpression = ExpressionTable.GetStatelessExpression(); interpreter.ExecStack.Push(codePopExpression, interpreter.CodeStack.Top); return true; } } /// /// Like CODE.DO but pops the stack before, rather than after, the recursive execution /// [PushExpression(StackType.Code, "CODE.DO*")] public class CodeDoXExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { // not enough arguments on stack if (interpreter.CodeStack.Count == 0) return false; var expression = interpreter.CodeStack.Pop(); interpreter.ExecStack.Push(expression); return true; } } /// /// Does nothing. /// [PushExpression(StackType.Code, "CODE.NOOP")] public class CodeNoopExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { return false; } } /// /// Specifies that the next expression submitted for execution will instead be pushed literally onto the CODE stack. /// This can be implemented by moving the top item on the EXEC stack onto the CODE stack. /// [PushExpression(StackType.Code, "CODE.QUOTE")] public class CodeQuoteExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { // not enough arguments on stack if (interpreter.ExecStack.Count == 0) return false; var expression = interpreter.ExecStack.Pop(); interpreter.CodeStack.Push(expression); return true; } } /// /// If the top item of the BOOLEAN stack is TRUE this recursively executes the second item of the CODE stack; /// otherwise it recursively executes the first item of the CODE stack. Either way both elements of the CODE stack /// (and the BOOLEAN value upon which the decision was made) are popped. /// [PushExpression(StackType.Code, "CODE.IF")] public class CodeIfExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { // not enough arguments on stack if ((interpreter.BooleanStack.Count == 0) || (interpreter.CodeStack.Count < 2)) return false; var condition = interpreter.BooleanStack.Pop(); var items = interpreter.CodeStack.Pop(2); interpreter.ExecStack.Push(condition ? items[0] : items[1]); return true; } } /// /// Pushes the result of appending the top two pieces of code. If one of the pieces of code is a single instruction or /// literal (that is, something not surrounded by parentheses) then it is surrounded by parentheses first. /// [PushExpression(StackType.Code, "CODE.APPEND")] public class CodeAppendExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.CodeStack.Count < 2) return false; var first = interpreter.CodeStack.Pop(); var second = interpreter.CodeStack.Top; var isFirstList = first.CanExpand; var isSecondList = second.CanExpand; Expression[] result = null; if (isFirstList) { var expand1 = first as ExecExpandExpression; if (isSecondList) { var expand2 = second as ExecExpandExpression; var size = expand2.State.Expressions.Count + expand1.State.Expressions.Count; // if size > maxPointsInProgram this expressions results in a NOOP if (size > interpreter.Configuration.MaxPointsInProgram) return false; result = new Expression[size]; Array.Copy(expand2.State.Expressions as Expression[], result, expand2.State.Expressions.Count); Array.Copy( expand1.State.Expressions as Expression[], 0, result, expand2.State.Expressions.Count, expand1.State.Expressions.Count); } else { var size = expand1.State.Expressions.Count + 1; // if size > maxPointsInProgram this expressions results in a NOOP if (size > interpreter.Configuration.MaxPointsInProgram) return false; result = new Expression[size]; result[0] = second; Array.Copy(expand1.State.Expressions as Expression[], 0, result, 1, expand1.State.Expressions.Count); } } else if (isSecondList) { var expand2 = second as ExecExpandExpression; var size = expand2.State.Expressions.Count + 1; // if size > maxPointsInProgram this expressions results in a NOOP if (size > interpreter.Configuration.MaxPointsInProgram) return false; result = new Expression[size]; result[0] = first; Array.Copy(expand2.State.Expressions as Expression[], 0, result, 1, expand2.State.Expressions.Count); } else { result = new[] { second, first }; } var expression = new ExecExpandExpression(result); interpreter.CodeStack.SetTop(expression); return true; } } /// /// Pushes TRUE onto the BOOLEAN stack if the top piece of code is a single instruction or a literal, /// and FALSE otherwise (that is, if it is something surrounded by parentheses). /// [PushExpression(StackType.Code, "CODE.ATOM")] public class CodeAtomExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.CodeStack.Count == 0) return false; var expression = interpreter.CodeStack.Pop(); var isExpandExpression = expression.CanExpand; interpreter.BooleanStack.Push(!isExpandExpression); return true; } } /// /// Pushes the first item of the list on top of the CODE stack. For example, if the top piece of code is "( A B )" /// then this pushes "A" (after popping the argument). If the code on top of the stack is not a list then this has no /// effect. /// The name derives from the similar Lisp function; a more generic name would be "FIRST". /// [PushExpression(StackType.Code, "CODE.CAR")] public class CodeCarExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if ((interpreter.CodeStack.Count == 0) || (interpreter.CodeStack.Top.GetType() != typeof(ExecExpandExpression))) return false; var expand = interpreter.CodeStack.Top as ExecExpandExpression; if (expand.State.IsEmpty) return false; var first = expand.State.Expressions[expand.State.Expressions.Count - 1]; interpreter.CodeStack.SetTop(first); return true; } } /// /// Pushes a version of the list from the top of the CODE stack without its first element. /// For example, if the top piece of code is "( A B )" then this pushes "( B )" (after popping the argument). /// If the code on top of the stack is not a list then this pushes the empty list ("( )"). The name derives from /// the similar Lisp function; a more generic name would be "REST". /// [PushExpression(StackType.Code, "CODE.CDR")] public class CodeCdrExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.CodeStack.Count == 0) return false; ExecExpandExpression expandExpression; var top = interpreter.CodeStack.Top; if (top.CanExpand) { var expand = (ExecExpandExpression)top; if (expand.State.IsEmpty) return false; var length = expand.State.Expressions.Count - 1; var newExpressions = new Expression[length]; Array.Copy((Expression[])expand.State.Expressions, 0, newExpressions, 0, length); expandExpression = new ExecExpandExpression(newExpressions); } else { expandExpression = ExecExpandExpression.Empty; } interpreter.CodeStack.SetTop(expandExpression); return true; } } /// /// Pushes the result of "consing" (in the Lisp sense) the second stack item onto the first stack item /// (which is coerced to a list if necessary). For example, if the top piece of code is "( A B )" and the /// second piece of code is "X" then this pushes "( X A B )" (after popping the argument). /// [PushExpression(StackType.Code, "CODE.CONS")] public class CodeConsExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.CodeStack.Count < 2) return false; ExecExpandExpression result; if (interpreter.CodeStack.Top.CanExpand) { var first = (ExecExpandExpression)interpreter.CodeStack.Pop(); var size = first.State.Expressions.Count + 1; if (size > interpreter.Configuration.MaxPointsInProgram) return false; var expressions = new Expression[size]; expressions[first.State.Expressions.Count] = interpreter.CodeStack.Top; Array.Copy(first.State.Expressions as Expression[], expressions, first.State.Expressions.Count); result = new ExecExpandExpression(expressions); } else { result = new ExecExpandExpression(interpreter.CodeStack.Pop(), interpreter.CodeStack.Top); } interpreter.CodeStack.SetTop(result); return true; } } /// /// Pushes the "container" of the second CODE stack item within the first CODE stack item onto the CODE stack. /// If second item contains the first anywhere (i.e. in any nested list) then the container is the smallest sub-list /// that contains but is not equal to the first instance. For example, if the top piece of code is "( B ( C ( A ) ) ( D /// ( A ) ) )" /// and the second piece of code is "( A )" then this pushes ( C ( A ) ). Pushes an empty list if there is no such /// container. /// [PushExpression(StackType.Code, "CODE.CONTAINER")] public class CodeContainerExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if ((interpreter.CodeStack.Count < 2) || (interpreter.CodeStack[interpreter.CodeStack.Count - 2].GetType() != typeof(ExecExpandExpression))) return false; var target = interpreter.CodeStack.Pop(); var source = interpreter.CodeStack.Top; var container = GetContainer(source as ExecExpandExpression, target); var result = container ?? ExecExpandExpression.Empty; interpreter.CodeStack.SetTop(result); return true; } private static ExecExpandExpression GetContainer(ExecExpandExpression current, Expression target) { if (current == target) return null; var subContainer = current.State.Expressions.Where(e => e.CanExpand) .Select(e => GetContainer(e as ExecExpandExpression, target)) .Where(e => e != null); var execExpandExpressions = subContainer as IList ?? subContainer.ToList(); return execExpandExpressions.Any() ? execExpandExpressions.OrderBy(c => c.State.Expressions.Count).LastOrDefault() : current.State.Expressions.Contains(target) ? current : null; } } /// /// Pushes TRUE on the BOOLEAN stack if the second CODE stack item contains the first CODE stack /// item anywhere (e.g. in a sub-list). /// [PushExpression(StackType.Code, "CODE.CONTAINS")] public class CodeContainsExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.CodeStack.Count < 2 || !interpreter.CodeStack[interpreter.CodeStack.Count - 2].CanExpand) return false; var values = interpreter.CodeStack.Pop(2); var second = (ExecExpandExpression)values[0]; var contains = second.State.Expressions.Contains(values[1]); interpreter.BooleanStack.Push(contains); return true; } } /// /// Pushes the definition associated with the top NAME on the NAME stack (if any) onto the CODE stack. /// This extracts the definition for inspection/manipulation, rather than for immediate execution (although it /// may then be executed with a call to CODE.DO or a similar instruction). /// [PushExpression(StackType.Code, "CODE.DEFINITION")] public class CodeDefinitionExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if ((interpreter.NameStack.Count == 0) || !interpreter.CustomExpressions.ContainsKey(interpreter.NameStack.Top)) return false; var name = interpreter.NameStack.Pop(); var definition = interpreter.CustomExpressions[name]; interpreter.CodeStack.Push(definition); return true; } } /// /// Pushes a measure of the discrepancy between the top two CODE stack items onto the INTEGER stack. This will be zero /// if the top two items are equivalent, and will be higher the 'more different' the items are from one another. The calculation /// is as follows: /// /// /// /// Construct a list of all of the unique items in both of the lists(where uniqueness is determined by equalp). /// Sub-lists and atoms all count as items. /// /// /// Initialize the result to zero. /// /// /// /// For each unique item increment the result by the difference between the number of occurrences of the /// item in the two pieces of code. /// /// /// Push the result. /// /// /// [PushExpression(StackType.Code, "CODE.DISCREPANCY")] public class CodeDiscrepancyExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.CodeStack.Count < 2) return false; var expressions = interpreter.CodeStack.Pop(2); var firstItems = new Dictionary(); var secondItems = new Dictionary(); DetermineUniqueItems(expressions[0], secondItems); DetermineUniqueItems(expressions[1], firstItems); var discrepancy = GetDiscrepancy(firstItems, secondItems); interpreter.IntegerStack.Push(discrepancy); return true; } private int GetDiscrepancy(IDictionary first, IDictionary second) { var discrepancy = 0; var keys = first.Keys.Concat(second.Keys).Distinct(); foreach (var key in keys) if (first.ContainsKey(key) && second.ContainsKey(key)) discrepancy += Math.Abs(first[key] - second[key]); else if (first.ContainsKey(key)) discrepancy += first[key]; else discrepancy += second[key]; return discrepancy; } private void DetermineUniqueItems(Expression source, IDictionary items) { if (source.CanExpand) { var expand = source as ExecExpandExpression; foreach (var e in expand.State.Expressions) { var id = e.GetHashCode(); if (!items.ContainsKey(id)) items.Add(id, 1); else items[id]++; } } else { items.Add(source.GetHashCode(), 1); } } } /// /// Pushes the sub-expression of the top item of the CODE stack that is indexed by the top item of the INTEGER stack. /// The indexing here counts "points," where each parenthesized expression and each literal/instruction is considered a /// point, /// and it proceeds in depth first order. The entire piece of code is at index 0; if it is a list then the first item /// in the list /// is at index 1, etc. The integer used as the index is taken modulo the number of points in the overall expression /// (and its /// absolute value is taken in case it is negative) to ensure that it is within the meaningful range. /// [PushExpression(StackType.Code, "CODE.EXTRACT")] public class CodeExtractExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.IntegerStack.Count == 0 || interpreter.CodeStack.Count == 0 || !interpreter.CodeStack.Top.CanExpand) return false; var expression = (ExecExpandExpression)interpreter.CodeStack.Top; var index = (int)Math.Abs(interpreter.IntegerStack.Pop() % expression.State.TotalCount); var result = expression.GetFromTree(index); interpreter.CodeStack.SetTop(result); return true; } } /// /// Pops the BOOLEAN stack and pushes the popped item (TRUE or FALSE) onto the CODE stack. /// [PushExpression(StackType.Code, "CODE.FROMBOOLEAN")] public class CodeFromBooleanExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.BooleanStack.Count == 0) return false; var value = interpreter.BooleanStack.Pop(); var expression = new BooleanPushExpression(value); interpreter.CodeStack.Push(expression); return true; } } /// /// Pops the FLOAT stack and pushes the popped item onto the CODE stack. /// [PushExpression(StackType.Code, "CODE.FROMFLOAT")] public class CodeFromFloatExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.FloatStack.Count == 0) return false; var value = interpreter.FloatStack.Pop(); var expression = new FloatPushExpression(value); interpreter.CodeStack.Push(expression); return true; } } /// /// Pops the INTEGER stack and pushes the popped integer onto the CODE stack. /// [PushExpression(StackType.Code, "CODE.FROMINTEGER")] public class CodeFromIntegerExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.IntegerStack.Count == 0) return false; var value = interpreter.IntegerStack.Pop(); var expression = new IntegerPushExpression(value); interpreter.CodeStack.Push(expression); return true; } } /// /// Pops the NAME stack and pushes the popped item onto the CODE stack. /// [PushExpression(StackType.Code, "CODE.FROMNAME")] public class CodeFromNameExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.NameStack.Count == 0) return false; var value = interpreter.NameStack.Pop(); var expression = new NameDefineXExecExpression(value); interpreter.CodeStack.Push(expression); return true; } } /// /// Pushes the result of inserting the second item of the CODE stack into the first item, at the position indexed /// by the top item of the INTEGER stack (and replacing whatever was there formerly). /// [PushExpression(StackType.Code, "CODE.CODEINSERT")] public class CodeInsertExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.IntegerStack.Count == 0 || interpreter.CodeStack.Count < 2 || !interpreter.CodeStack.Top.CanExpand) return false; var source = interpreter.CodeStack[interpreter.CodeStack.Count - 2]; var target = (ExecExpandExpression)interpreter.CodeStack.Pop(); var index = (int)interpreter.IntegerStack.Pop(); Expression[] newExpressions; if (target.State.Expressions.Count > 0) { index = target.State.Expressions.Count - 1 - Math.Abs(index % target.State.Expressions.Count); newExpressions = target.State.CopyExpressions(); newExpressions[index] = source.CanExpand ? ((ExecExpandExpression)source).Copy() : source; } else { newExpressions = new[] { source }; } var result = new ExecExpandExpression(newExpressions); interpreter.CodeStack.SetTop(result); return true; } } /// /// Pushes the length of the top item on the CODE stack onto the INTEGER stack. /// If the top item is not a list then this pushes a 1. If the top item is a list then this pushes the /// number of items in the top level of the list; that is, nested lists contribute only 1 to this count, no /// matter what they contain. /// [PushExpression(StackType.Code, "CODE.LENGTH")] public class CodeLengthExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.CodeStack.Count == 0) return false; var expression = interpreter.CodeStack.Pop(); var count = 1; if (expression.CanExpand) count = ((ExecExpandExpression)expression).State.Expressions.Count; interpreter.IntegerStack.Push(count); return true; } } /// /// Pushes a list of the top two items of the CODE stack onto the CODE stack. /// [PushExpression(StackType.Code, "CODE.LIST")] public class CodeListExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.CodeStack.Count < 2) return false; var first = interpreter.CodeStack.Pop(); var second = interpreter.CodeStack.Top; var expandExpression = new ExecExpandExpression(second, first); interpreter.CodeStack.SetTop(expandExpression); return true; } } /// /// Pushes TRUE onto the BOOLEAN stack if the second item of the CODE stack is a member of the first item /// (which is coerced to a list if necessary). Pushes FALSE onto the BOOLEAN stack otherwise. /// [PushExpression(StackType.Code, "CODE.MEMBER")] public class CodeMemberExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.CodeStack.Count < 2) return false; var expressions = interpreter.CodeStack.Pop(2); var contains = expressions[1].CanExpand ? ((ExecExpandExpression)expressions[1]).State.Expressions.Contains(expressions[0]) : expressions[1].Equals(expressions[0]); interpreter.BooleanStack.Push(contains); return true; } } /// /// Pushes the nth element of the expression on top of the CODE stack (which is coerced to a list first if necessary). /// If the expression is an empty list then the result is an empty list. N is taken from the INTEGER stack and is taken /// modulo the length of the expression into which it is indexing. /// [PushExpression(StackType.Code, "CODE.NTH")] public class CodeNthExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if ((interpreter.CodeStack.Count == 0) || (interpreter.IntegerStack.Count == 0)) return false; var n = interpreter.IntegerStack.Pop(); var expression = interpreter.CodeStack.Top; Expression nthExpression; if (expression.CanExpand) { var subExpression = (ExecExpandExpression)expression; if (subExpression.State.IsEmpty) { nthExpression = ExecExpandExpression.Empty; } else { var index = (int)(subExpression.State.Expressions.Count - 1 - Math.Abs(n % subExpression.State.Expressions.Count)); nthExpression = subExpression.State.Expressions[index]; } } else { nthExpression = expression; } interpreter.CodeStack.SetTop(nthExpression); return true; } } /// /// Pushes the nth "CDR" (in the Lisp sense) of the expression on top of the CODE stack (which is coerced to a list /// first if necessary). If the expression is an empty list then the result is an empty list. N is taken from the /// INTEGER /// stack and is taken modulo the length of the expression into which it is indexing. A "CDR" of a list is the list /// without /// its first element. /// [PushExpression(StackType.Code, "CODE.NTHCDR")] public class CodeNthCdrExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if ((interpreter.CodeStack.Count == 0) || (interpreter.IntegerStack.Count == 0)) return false; var n = interpreter.IntegerStack.Pop(); var expression = interpreter.CodeStack.Top; Expression nthExpression = null; if (expression.CanExpand) { var subExpressions = ((ExecExpandExpression)expression).State.Expressions; if (subExpressions.Count < 2) { nthExpression = ExecExpandExpression.Empty; } else { var index = (int)(subExpressions.Count - 2 - Math.Abs(n % (subExpressions.Count - 1))); nthExpression = subExpressions[index]; } } else { nthExpression = expression; } interpreter.CodeStack.SetTop(nthExpression); return true; } } /// /// Pushes TRUE onto the BOOLEAN stack if the top item of the CODE stack is an empty list, or FALSE otherwise. /// [PushExpression(StackType.Code, "CODE.NULL")] public class CodeNullExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.CodeStack.Count == 0) return false; var result = interpreter.CodeStack.Pop().Equals(ExecExpandExpression.Empty); interpreter.BooleanStack.Push(result); return true; } } /// /// Pushes onto the INTEGER stack the position of the second item on the CODE stack within the first item /// (which is coerced to a list if necessary). Pushes -1 if no match is found. /// [PushExpression(StackType.Code, "CODE.POSITION")] public class CodePositionExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.CodeStack.Count < 2) return false; var expressions = interpreter.CodeStack.Pop(2); var first = expressions[1]; var second = expressions[0]; var position = -1; if (first.CanExpand) { var expand = (ExecExpandExpression)first; position = expand.State.Expressions.Count - 1 - Array.FindIndex((Expression[])expand.State.Expressions, e => e.Equals(second)); } else if (first.Equals(second)) { position = 0; } interpreter.IntegerStack.Push(position); return true; } } /// /// Pushes the number of "points" in the top piece of CODE onto the INTEGER stack. Each instruction, literal, /// and pair of parentheses counts as a point. /// [PushExpression(StackType.Code, "CODE.SIZE")] public class CodeSizeExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if (interpreter.CodeStack.Count == 0) return false; var expression = interpreter.CodeStack.Pop(); var points = expression.CanExpand ? ((ExecExpandExpression)expression).State.Expressions.Count : 1; interpreter.IntegerStack.Push(points); return true; } } /// /// Pushes the result of substituting the third item on the code stack for the second item in the first item. /// As of this writing this is implemented only in the Lisp implementation, within which it relies on the Lisp "subst" /// function. As such, there are several problematic possibilities; for example "dotted-lists" can result in certain /// cases with empty-list arguments. If any of these problematic possibilities occurs the stack is left unchanged. /// [PushExpression(StackType.Code, "CODE.SUBST")] public class CodeSubstitutionExpression : StatelessExpression { public override bool Eval(IPushInterpreter interpreter) { if ((interpreter.CodeStack.Count < 3) || (interpreter.CodeStack.Top.GetType() != typeof(ExecExpandExpression))) return false; var expressions = interpreter.CodeStack.Pop(2); var third = interpreter.CodeStack.Top; var second = expressions[0]; var first = expressions[1] as ExecExpandExpression; var newExpressions = new Expression[first.State.Expressions.Count]; for (var i = 0; i < first.State.Expressions.Count; i++) newExpressions[i] = first.State.Expressions[i].Equals(third) ? second /* no cloning needed here because first is removed and therefore newExpression is the only container of sub expressions */ : first.State.Expressions[i]; var result = new ExecExpandExpression(newExpressions); interpreter.CodeStack.SetTop(result); return true; } } }