Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
03/11/17 20:07:13 (7 years ago)
Author:
pkimmesw
Message:

#2665 PooledPushProgram reduces memory usage and increases performance

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/PushGP/HeuristicLab.PushGP/HeuristicLab.Problems.ProgramSynthesis/Push/Expressions/PushProgram.cs

    r14745 r14746  
    66  using System.Diagnostics;
    77
     8  using HeuristicLab.Problems.ProgramSynthesis.Push.Data.Pool;
     9
    810  using Interpreter;
    911
    10   public class PushProgram : StatefulExpression<Expression[]> {
     12  [Serializable]
     13  public sealed class PushProgram : Expression {
     14    private static readonly Expression[] EmptyExpressions = new Expression[0];
    1115    public static readonly PushProgram Empty = new PushProgram();
    1216
     
    1721    private const string Delimiter = " ";
    1822
    19     public readonly bool IsEmpty;
    20 
    21     public PushProgram(params Expression[] state) : base(state) {
    22       IsEmpty = state.Length == 0;
    23     }
    24 
    25     public PushProgram(IEnumerable<Expression> state) : this(state.ToArray()) {
    26       // TODO: lazy evaluation of ToArray()
     23    private Expression[] expressions;
     24
     25    public PushProgram() : this(EmptyExpressions) {
     26    }
     27
     28    public PushProgram(Expression[] expressions) {
     29      this.expressions = expressions;
     30    }
     31
     32    public bool IsEmpty { get { return Count == 0; } }
     33    public int Count { get { return expressions.Length; } }
     34
     35    public IReadOnlyList<Expression> Expressions { get { return this.expressions; } }
     36
     37    public static PushProgram Create(IManagedPool<PushProgram> pool, params Expression[] expressions) {
     38      var program = pool.Get();
     39
     40      program.expressions = expressions;
     41      program.Reset();
     42
     43      return program;
     44    }
     45
     46    private void Reset() {
     47      stringRepresentation = null;
     48      depth = null;
     49      treeIndex = null;
     50      hashCode = null;
     51    }
     52
     53    public static PushProgram Merge(IManagedPool<PushProgram> pool, PushProgram first, Expression second) {
     54      var program = pool.Get();
     55
     56      program.Reset();
     57      program.expressions = new Expression[first.Expressions.Count + 1];
     58      first.CopyExpressionsTo(program.expressions);
     59      program.expressions[0] = first;
     60
     61      return program;
     62    }
     63
     64    public static PushProgram Merge(IManagedPool<PushProgram> pool, Expression first, PushProgram second) {
     65      var program = pool.Get();
     66
     67      program.Reset();
     68
     69      program.expressions = new Expression[second.Expressions.Count + 1];
     70      program.expressions[0] = first;
     71      second.CopyExpressionsTo(program.expressions, 0, 1, second.Count);
     72
     73      return program;
     74    }
     75
     76    public static PushProgram Merge(IManagedPool<PushProgram> pool, PushProgram first, PushProgram second) {
     77      var program = pool.Get();
     78
     79      program.Reset();
     80      program.expressions = new Expression[first.Count + second.Count];
     81
     82      first.CopyExpressionsTo(program.expressions);
     83      second.CopyExpressionsTo(program.expressions, 0, first.Count, second.Count);
     84
     85      return program;
     86    }
     87
     88    public int IndexOf(Expression expression) {
     89      return Array.IndexOf(this.expressions, expression);
    2790    }
    2891
     
    3295      get
    3396      {
    34         if (string.IsNullOrEmpty(stringRepresentation))
    35           stringRepresentation = BuildString();
     97        if (stringRepresentation == null) stringRepresentation = BuildString();
    3698        return stringRepresentation;
    3799      }
    38100    }
    39101
    40     private int depth = -1;
     102
     103    private int? depth;
    41104    public int Depth
    42105    {
    43106      get
    44107      {
    45         if (depth == -1) depth = CalcDepth();
    46         return depth;
     108        if (depth == null) depth = CalcDepth();
     109        return depth.Value;
    47110      }
    48111    }
     
    53116      get
    54117      {
    55         return treeIndex ?? (treeIndex = BuildTreeIndex());
    56       }
    57     }
    58 
    59     private int hashCode;
    60     private int HashCode
    61     {
    62       get
    63       {
    64         if (hashCode == default(int)) hashCode = HashExpressions();
    65         return hashCode;
    66       }
     118        if (treeIndex == null) treeIndex = BuildTreeIndex();
     119        return treeIndex;
     120      }
     121    }
     122
     123    private int? hashCode;
     124    public override int GetHashCode() {
     125      if (hashCode == null) hashCode = HashExpressions();
     126      return hashCode.Value;
    67127    }
    68128
    69129    //public PushProgram Copy() {
    70130    //  // as the empty list is a static stateless expression, no copy required
    71     //  return ReferenceEquals(this, Empty) || this.State.IsEmpty
     131    //  return ReferenceEquals(this, Empty) || this.expressions.IsEmpty
    72132    //    ? Empty
    73     //    : new PushProgram(this.State.Copy());
     133    //    : new PushProgram(this.expressions.Copy());
    74134    //}
    75135
    76136    public override bool Eval(IPushInterpreter interpreter) {
    77       interpreter.ExecStack.Push(this.State);
     137      interpreter.ExecStack.Push(this.expressions);
    78138      return true;
    79139    }
    80140
    81     public override int GetHashCode() {
    82       return HashCode;
    83     }
    84 
    85141    public override string ToString() {
    86       return this.StringRepresentation;
     142      return StringRepresentation;
    87143    }
    88144
     
    103159
    104160    public IEnumerable<Expression> DepthFirst() {
    105       foreach (var expr in this.State) {
    106         if (expr.CanExpand) {
     161      foreach (var expr in this.expressions) {
     162        if (expr.IsProgram) {
    107163          var expandExpr = (PushProgram)expr;
    108164
     
    114170
    115171    public PushProgram Copy() {
    116       return IsEmpty ? this : new PushProgram(State) {
     172      if (IsEmpty) return this;
     173
     174      var program = new PushProgram(this.expressions) {
    117175        stringRepresentation = this.stringRepresentation,
    118176        hashCode = this.hashCode,
     
    120178        treeIndex = this.treeIndex
    121179      };
    122     }
    123 
    124     public Expression[] CopyExpressions()
    125     {
    126       if (IsEmpty) return Empty.State;
    127 
    128       var copy = new Expression[State.Length];
    129       State.CopyTo(copy, 0);
     180
     181      return program;
     182    }
     183
     184    public PushProgram Copy(IManagedPool<PushProgram> pool) {
     185      if (IsEmpty) return this;
     186
     187      var program = pool.Get();
     188      program.expressions = this.expressions;
     189      program.stringRepresentation = stringRepresentation;
     190      program.hashCode = hashCode;
     191      program.depth = depth;
     192      program.treeIndex = treeIndex;
     193
     194      return program;
     195    }
     196
     197    public PushProgram Copy(IManagedPool<PushProgram> pool, int startIndex, int length) {
     198      if (IsEmpty) return this;
     199
     200      var program = pool.Get();
     201      program.expressions = CopyExpressions(startIndex, length);
     202
     203      program.Reset();
     204
     205      return program;
     206    }
     207
     208    public Expression[] CopyExpressions() {
     209      return CopyExpressions(Count);
     210    }
     211
     212    public Expression[] CopyExpressions(int length) {
     213      if (IsEmpty) return EmptyExpressions;
     214
     215      var copy = new Expression[length];
     216      this.expressions.CopyTo(copy, 0);
    130217
    131218      return copy;
     219    }
     220
     221    public Expression[] CopyExpressions(int startIndex, int length) {
     222      if (IsEmpty) return EmptyExpressions;
     223
     224      var copy = new Expression[length];
     225      CopyExpressionsTo(copy, startIndex, 0, length);
     226
     227      return copy;
     228    }
     229
     230    public void CopyExpressionsTo(Expression[] destination, int? sourceIndex = null, int? destinationIndex = null, int? length = null) {
     231      if (IsEmpty) return;
     232
     233      Array.Copy(this.expressions, sourceIndex ?? 0, destination, destinationIndex ?? 0, length ?? Count);
    132234    }
    133235
    134236    private int CalcDepth() {
    135237      var maxDepth = 1;
    136       for (var i = 0; i < State.Length; i++) {
    137         var expression = State[i];
    138         if (!expression.CanExpand) continue;
     238      for (var i = 0; i < Count; i++) {
     239        var expression = this.expressions[i];
     240        if (!expression.IsProgram) continue;
    139241        var expandExpression = (PushProgram)expression;
    140242
     
    149251      // prevent too big string
    150252      return this.TotalCount > 50
    151         ? PrefixReduced + this.State.Length + PostfixReduced
    152         : Prefix + string.Join(Delimiter, this.State.Where(e => !string.IsNullOrWhiteSpace(e.StringRepresentation))) + Postfix;
     253        ? PrefixReduced + this.Count + PostfixReduced
     254        : Prefix + string.Join(Delimiter, this.expressions.Where(e => !string.IsNullOrWhiteSpace(e.StringRepresentation))) + Postfix;
    153255    }
    154256
    155257    private int[] BuildTreeIndex() {
    156       var local_treeIndex = new int[State.Length];
     258      var local_treeIndex = new int[Count];
    157259
    158260      var next = 1;
    159261
    160       for (var i = State.Length - 1; i >= 0; i--) {
    161         var subExpression = State[i];
     262      for (var i = Count - 1; i >= 0; i--) {
     263        var subExpression = this.expressions[i];
    162264
    163265        local_treeIndex[i] = next;
    164266
    165         if (subExpression.CanExpand) {
     267        if (subExpression.IsProgram) {
    166268          next += ((PushProgram)subExpression).TotalCount;
    167269        } else {
     
    176278      var hash = 19 * 31 + this.GetType().FullName.GetHashCode();
    177279
    178       for (var i = 0; i < State.Length; i++) {
    179         hash = hash * 31 + State[i].GetHashCode();
     280      for (var i = 0; i < Count; i++) {
     281        hash = hash * 31 + this.expressions[i].GetHashCode();
    180282      }
    181283
     
    195297      }
    196298
    197       for (var i = 0; i < current.State.Length; i++) {
    198         if (current.State[i].CanExpand)
     299      for (var i = 0; i < current.Count; i++) {
     300        if (current.expressions[i].IsProgram)
    199301          continue;
    200302
    201         var subExpression = current.State[i] as PushProgram;
     303        var subExpression = current.expressions[i] as PushProgram;
    202304
    203305        if (ReferenceEquals(target, subExpression)) {
     
    231333      if (index == 0) return resolver(parent, parent, this, 0, parentIndex);
    232334
    233       var min = State.Length - 1;
     335      var min = Count - 1;
    234336      var max = 0;
    235337      var mid = (min + max) / 2;
     
    243345
    244346      return TreeIndex[mid] == index
    245           ? resolver(parent, this, State[mid], mid, parentIndex)
    246           : (State[mid + 1] as PushProgram).GetFromTree(index - TreeIndex[mid + 1], mid + 1,
     347          ? resolver(parent, this, this.expressions[mid], mid, parentIndex)
     348          : (this.expressions[mid + 1] as PushProgram).GetFromTree(index - TreeIndex[mid + 1], mid + 1,
    247349              this, resolver);
    248350    }
Note: See TracChangeset for help on using the changeset viewer.