Index: /trunk/sources/HeuristicLab.Problems.ExternalEvaluation.Views/3.3/EvaluationCacheView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.ExternalEvaluation.Views/3.3/EvaluationCacheView.Designer.cs	(revision 6168)
+++ /trunk/sources/HeuristicLab.Problems.ExternalEvaluation.Views/3.3/EvaluationCacheView.Designer.cs	(revision 6169)
@@ -1,10 +1,10 @@
-﻿namespace HeuristicLab.Problems.ExternalEvaluation {
+﻿namespace HeuristicLab.Problems.ExternalEvaluation.Views {
   partial class EvaluationCacheView {
-    /// <summary>
+    /// <summary> 
     /// Required designer variable.
     /// </summary>
     private System.ComponentModel.IContainer components = null;
 
-    /// <summary>
+    /// <summary> 
     /// Clean up any resources being used.
     /// </summary>
@@ -17,18 +17,21 @@
     }
 
-    #region Windows Form Designer generated code
+    #region Component Designer generated code
 
-    /// <summary>
-    /// Required method for Designer support - do not modify
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
     /// the contents of this method with the code editor.
     /// </summary>
     private void InitializeComponent() {
-      this.sizeLabel = new System.Windows.Forms.Label();
-      this.sizeTextBox = new System.Windows.Forms.TextBox();
-      this.hitsTextBox = new System.Windows.Forms.TextBox();
-      this.hitsLabel = new System.Windows.Forms.Label();
+      this.hits_sizeLabel = new System.Windows.Forms.Label();
+      this.hits_sizeTextBox = new System.Windows.Forms.TextBox();
       this.clearButton = new System.Windows.Forms.Button();
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
       this.SuspendLayout();
+      // 
+      // parameterCollectionView
+      // 
+      this.parameterCollectionView.Location = new System.Drawing.Point(0, 52);
+      this.parameterCollectionView.Size = new System.Drawing.Size(490, 301);
       // 
       // nameTextBox
@@ -37,50 +40,32 @@
       this.errorProvider.SetIconPadding(this.nameTextBox, 2);
       // 
-      // sizeLabel
+      // hits_sizeLabel
       // 
-      this.sizeLabel.AutoSize = true;
-      this.sizeLabel.Location = new System.Drawing.Point(6, 30);
-      this.sizeLabel.Name = "sizeLabel";
-      this.sizeLabel.Size = new System.Drawing.Size(30, 13);
-      this.sizeLabel.TabIndex = 3;
-      this.sizeLabel.Text = "Size:";
+      this.hits_sizeLabel.AutoSize = true;
+      this.hits_sizeLabel.Location = new System.Drawing.Point(3, 29);
+      this.hits_sizeLabel.Name = "hits_sizeLabel";
+      this.hits_sizeLabel.Size = new System.Drawing.Size(53, 13);
+      this.hits_sizeLabel.TabIndex = 4;
+      this.hits_sizeLabel.Text = "Hits/Size:";
       // 
-      // sizeTextBox
+      // hits_sizeTextBox
       // 
-      this.sizeTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+      this.hits_sizeTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
-      this.sizeTextBox.Location = new System.Drawing.Point(58, 27);
-      this.sizeTextBox.Name = "sizeTextBox";
-      this.sizeTextBox.ReadOnly = true;
-      this.sizeTextBox.Size = new System.Drawing.Size(290, 20);
-      this.sizeTextBox.TabIndex = 4;
-      // 
-      // hitsTextBox
-      // 
-      this.hitsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.hitsTextBox.Location = new System.Drawing.Point(58, 54);
-      this.hitsTextBox.Name = "hitsTextBox";
-      this.hitsTextBox.ReadOnly = true;
-      this.hitsTextBox.Size = new System.Drawing.Size(290, 20);
-      this.hitsTextBox.TabIndex = 5;
-      // 
-      // hitsLabel
-      // 
-      this.hitsLabel.AutoSize = true;
-      this.hitsLabel.Location = new System.Drawing.Point(6, 57);
-      this.hitsLabel.Name = "hitsLabel";
-      this.hitsLabel.Size = new System.Drawing.Size(28, 13);
-      this.hitsLabel.TabIndex = 6;
-      this.hitsLabel.Text = "Hits:";
+      this.hits_sizeTextBox.Location = new System.Drawing.Point(59, 26);
+      this.hits_sizeTextBox.Name = "hits_sizeTextBox";
+      this.hits_sizeTextBox.ReadOnly = true;
+      this.hits_sizeTextBox.Size = new System.Drawing.Size(379, 20);
+      this.hits_sizeTextBox.TabIndex = 5;
       // 
       // clearButton
       // 
       this.clearButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
-      this.clearButton.Location = new System.Drawing.Point(273, 80);
+      this.clearButton.Location = new System.Drawing.Point(444, 24);
       this.clearButton.Name = "clearButton";
-      this.clearButton.Size = new System.Drawing.Size(75, 23);
-      this.clearButton.TabIndex = 7;
+      this.clearButton.Size = new System.Drawing.Size(43, 23);
+      this.clearButton.TabIndex = 6;
       this.clearButton.Text = "Clear";
+      this.toolTip.SetToolTip(this.clearButton, "Clear");
       this.clearButton.UseVisualStyleBackColor = true;
       this.clearButton.Click += new System.EventHandler(this.clearButton_Click);
@@ -89,19 +74,16 @@
       // 
       this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-      this.Controls.Add(this.hitsTextBox);
-      this.Controls.Add(this.sizeTextBox);
-      this.Controls.Add(this.sizeLabel);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.hits_sizeTextBox);
+      this.Controls.Add(this.hits_sizeLabel);
       this.Controls.Add(this.clearButton);
-      this.Controls.Add(this.hitsLabel);
       this.Name = "EvaluationCacheView";
-      this.Size = new System.Drawing.Size(351, 107);
-      this.Controls.SetChildIndex(this.hitsLabel, 0);
       this.Controls.SetChildIndex(this.clearButton, 0);
-      this.Controls.SetChildIndex(this.sizeLabel, 0);
-      this.Controls.SetChildIndex(this.sizeTextBox, 0);
-      this.Controls.SetChildIndex(this.hitsTextBox, 0);
+      this.Controls.SetChildIndex(this.hits_sizeLabel, 0);
+      this.Controls.SetChildIndex(this.hits_sizeTextBox, 0);
+      this.Controls.SetChildIndex(this.infoLabel, 0);
+      this.Controls.SetChildIndex(this.nameTextBox, 0);
       this.Controls.SetChildIndex(this.nameLabel, 0);
-      this.Controls.SetChildIndex(this.nameTextBox, 0);
-      this.Controls.SetChildIndex(this.infoLabel, 0);
+      this.Controls.SetChildIndex(this.parameterCollectionView, 0);
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
       this.ResumeLayout(false);
@@ -112,8 +94,6 @@
     #endregion
 
-    private System.Windows.Forms.Label sizeLabel;
-    private System.Windows.Forms.TextBox sizeTextBox;
-    private System.Windows.Forms.TextBox hitsTextBox;
-    private System.Windows.Forms.Label hitsLabel;
+    private System.Windows.Forms.Label hits_sizeLabel;
+    private System.Windows.Forms.TextBox hits_sizeTextBox;
     private System.Windows.Forms.Button clearButton;
   }
Index: /trunk/sources/HeuristicLab.Problems.ExternalEvaluation.Views/3.3/EvaluationCacheView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.ExternalEvaluation.Views/3.3/EvaluationCacheView.cs	(revision 6168)
+++ /trunk/sources/HeuristicLab.Problems.ExternalEvaluation.Views/3.3/EvaluationCacheView.cs	(revision 6169)
@@ -1,10 +1,12 @@
-﻿
+﻿using System;
+using System.Windows.Forms;
 using HeuristicLab.Core.Views;
 using HeuristicLab.MainForm;
-namespace HeuristicLab.Problems.ExternalEvaluation {
+
+namespace HeuristicLab.Problems.ExternalEvaluation.Views {
 
   [View("EvaluationCacheView")]
   [Content(typeof(EvaluationCache), IsDefaultView = true)]
-  public sealed partial class EvaluationCacheView : NamedItemView {
+  public sealed partial class EvaluationCacheView : ParameterizedNamedItemView {
 
     public new EvaluationCache Content {
@@ -18,6 +20,6 @@
 
     protected override void DeregisterContentEvents() {
-      Content.CacheSizeChanged -= Content_CacheSizeChanged;
-      Content.CacheHitsChanged -= Content_CacheHitsChanged;
+      Content.SizeChanged -= new System.EventHandler(Content_StatusChanged);
+      Content.HitsChanged -= new System.EventHandler(Content_StatusChanged);
       base.DeregisterContentEvents();
     }
@@ -25,17 +27,16 @@
     protected override void RegisterContentEvents() {
       base.RegisterContentEvents();
-      Content.CacheSizeChanged += Content_CacheSizeChanged;
-      Content.CacheHitsChanged += Content_CacheHitsChanged;
+      Content.SizeChanged += new System.EventHandler(Content_StatusChanged);
+      Content.HitsChanged += new System.EventHandler(Content_StatusChanged);
     }
 
-
     #region Event Handlers (Content)
-    void Content_CacheSizeChanged(object sender, System.EventArgs e) {
-      sizeTextBox.Text = Content.CacheSize.ToString();
+    void Content_StatusChanged(object sender, EventArgs e) {
+      if (InvokeRequired)
+        Invoke(new EventHandler(Content_StatusChanged), sender, e);
+      else
+        hits_sizeTextBox.Text = string.Format("{0}/{1}", Content.Hits, Content.Size);
     }
 
-    void Content_CacheHitsChanged(object sender, System.EventArgs e) {
-      hitsTextBox.Text = Content.CacheHits.ToString();
-    }
     #endregion
 
@@ -43,9 +44,7 @@
       base.OnContentChanged();
       if (Content == null) {
-        sizeTextBox.Text = "";
-        hitsTextBox.Text = "";
+        hits_sizeTextBox.Text = "#/#";
       } else {
-        sizeTextBox.Text = Content.CacheSize.ToString();
-        hitsTextBox.Text = Content.CacheHits.ToString();
+        Content_StatusChanged(this, EventArgs.Empty);
       }
     }
@@ -57,9 +56,8 @@
 
     #region Event Handlers (child controls)
-    private void clearButton_Click(object sender, System.EventArgs e) {
+    private void clearButton_Click(object sender, EventArgs e) {
       Content.Reset();
     }
     #endregion
   }
-
 }
Index: /trunk/sources/HeuristicLab.Problems.ExternalEvaluation.Views/3.3/EvaluationCacheView.resx
===================================================================
--- /trunk/sources/HeuristicLab.Problems.ExternalEvaluation.Views/3.3/EvaluationCacheView.resx	(revision 6168)
+++ /trunk/sources/HeuristicLab.Problems.ExternalEvaluation.Views/3.3/EvaluationCacheView.resx	(revision 6169)
@@ -121,4 +121,7 @@
     <value>107, 17</value>
   </metadata>
+  <metadata name="errorProvider.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>107, 17</value>
+  </metadata>
   <metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>17, 17</value>
Index: /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.3/CachedExternalEvaluator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.3/CachedExternalEvaluator.cs	(revision 6168)
+++ /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.3/CachedExternalEvaluator.cs	(revision 6169)
@@ -43,9 +43,9 @@
       set { CacheParameter.Value = value; }
     }
-    public DoubleValue Quality {
+    protected DoubleValue Quality {
       get { return QualityParameter.ActualValue; }
       set { QualityParameter.ActualValue = value; }
     }
-    public IEvaluationServiceClient Client {
+    protected IEvaluationServiceClient Client {
       get { return ClientParameter.ActualValue; }
     }
Index: /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.3/EvaluationCache.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.3/EvaluationCache.cs	(revision 6168)
+++ /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.3/EvaluationCache.cs	(revision 6169)
@@ -17,7 +17,9 @@
  * You should have received a copy of the GNU General Public License
  * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ * 
+ * The LRU cache is based on an idea by Robert Rossney see 
+ * <http://csharp-lru-cache.googlecode.com>.
  */
 #endregion
-
 
 using System;
@@ -27,4 +29,6 @@
 using HeuristicLab.Common.Resources;
 using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 namespace HeuristicLab.Problems.ExternalEvaluation {
@@ -32,36 +36,65 @@
   [Item("EvaluationCache", "Cache for external evaluation values")]
   [StorableClass]
-  public class EvaluationCache : NamedItem {
+  public class EvaluationCache : ParameterizedNamedItem {
+
+    #region Types
+    private class CacheEntry {
+
+      public string Key { get; private set; }
+      public double Value { get; set; }
+
+      public CacheEntry(string key, double value) {
+        Key = key;
+        Value = value;
+      }
+
+      public CacheEntry(string key) : this(key, 0) { }
+
+      public override bool Equals(object obj) {
+        CacheEntry other = obj as CacheEntry;
+        if (other == null)
+          return false;
+        return Key.Equals(other.Key);
+      }
+
+      public override int GetHashCode() {
+        return Key.GetHashCode();
+      }
+
+      public override string ToString() {
+        return string.Format("{{{0} : {1}}}", Key, Value);
+      }
+    }
 
     public delegate double Evaluator(SolutionMessage message);
-
+    #endregion
+
+    #region Fields
+    private LinkedList<CacheEntry> list;
+    private Dictionary<CacheEntry, LinkedListNode<CacheEntry>> index;
+    #endregion
+
+    #region Properties
     public override System.Drawing.Image ItemImage {
       get { return VSImageLibrary.Database; }
     }
-
-    #region Fields & Properties
+    public int Size {
+      get { return index.Count; }
+    }
     [Storable]
-    private Dictionary<string, double> cache;
-
-    [Storable]
-    private int cacheHits;
-
-    public int CacheSize { get { return cache.Count; } }
-
-    public int CacheHits { get { return cacheHits; } }
-    #endregion
-
-    #region Events
-    public event EventHandler CacheSizeChanged;
-    public event EventHandler CacheHitsChanged;
-
-    protected virtual void OnCacheSizeChanged() {
-      EventHandler handler = CacheSizeChanged;
+    public int Hits { get; private set; }
+    #endregion
+
+    #region events
+    public event EventHandler SizeChanged;
+    public event EventHandler HitsChanged;
+
+    protected virtual void OnSizeChanged() {
+      EventHandler handler = SizeChanged;
       if (handler != null)
         handler(this, EventArgs.Empty);
     }
-
-    protected virtual void OnCacheHitsChanged() {
-      EventHandler handler = CacheHitsChanged;
+    protected virtual void OnHitsChanged() {
+      EventHandler handler = HitsChanged;
       if (handler != null)
         handler(this, EventArgs.Empty);
@@ -69,5 +102,38 @@
     #endregion
 
-
+    #region Parameters
+    public FixedValueParameter<IntValue> CapacityParameter {
+      get { return (FixedValueParameter<IntValue>)Parameters["Capacity"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public int Capacity {
+      get { return CapacityParameter.Value.Value; }
+      set { CapacityParameter.Value.Value = value; }
+    }
+    #endregion
+
+    #region Persistence
+    [Storable(Name="Cache")]
+    private IEnumerable<KeyValuePair<string, double>> Cache_Persistence {
+      get {
+        return index.ToDictionary(kvp => kvp.Key.Key, kvp => kvp.Key.Value);
+      }
+      set {
+        list = new LinkedList<CacheEntry>();
+        index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
+        foreach (var kvp in value) {
+          var entry = new CacheEntry(kvp.Key);
+          entry.Value = kvp.Value;
+          index[entry] = list.AddLast(entry);
+        }
+      }
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEvents();
+    }
+    #endregion
 
     #region Construction & Cloning
@@ -76,8 +142,12 @@
     protected EvaluationCache(EvaluationCache original, Cloner cloner)
       : base(original, cloner) {
-      cache = original.cache.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
+      Cache_Persistence = original.Cache_Persistence;
+      RegisterEvents();
     }
     public EvaluationCache() {
-      cache = new Dictionary<string, double>();
+      list = new LinkedList<CacheEntry>();
+      index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
+      Parameters.Add(new FixedValueParameter<IntValue>("Capacity", "Maximum number of cache entries.", new IntValue(10000)));
+      RegisterEvents();
     }
     public override IDeepCloneable Clone(Cloner cloner) {
@@ -86,24 +156,52 @@
     #endregion
 
+    #region Event Handling
+    private void RegisterEvents() {
+      CapacityParameter.Value.ValueChanged += new EventHandler(Value_ValueChanged);
+    }
+
+    void Value_ValueChanged(object sender, EventArgs e) {
+      if (Capacity < 0)
+        throw new ArgumentOutOfRangeException("Cache capacity cannot be less than zero");
+      Trim();
+    }
+    #endregion
+
+    #region Methods
+    public void Reset() {
+      list = new LinkedList<CacheEntry>();
+      index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
+      Hits = 0;
+      OnSizeChanged();
+      OnHitsChanged();
+    }
+
     public double GetValue(SolutionMessage message, Evaluator evaluate) {
-      string s = message.ToString();
-      double value;
-      if (cache.TryGetValue(s, out value)) {
-        cacheHits++;
-        OnCacheHitsChanged();
+      CacheEntry entry = new CacheEntry(message.ToString());
+      LinkedListNode<CacheEntry> node;
+      if (index.TryGetValue(entry, out node)) {
+        list.Remove(node);
+        list.AddLast(node);
+        Hits++;
+        OnHitsChanged();
+        return node.Value.Value;
       } else {
-        value = evaluate(message);
-        cache[s] = value;
-        OnCacheSizeChanged();
-      }
-      return value;
-    }
-
-    public void Reset() {
-      cache = new Dictionary<string, double>();
-      OnCacheSizeChanged();
-      cacheHits = 0;
-      OnCacheHitsChanged();
-    }
+        entry.Value = evaluate(message);
+        index[entry] = list.AddLast(entry);
+        Trim();
+        return entry.Value;
+      }
+    }
+
+    private void Trim() {
+      while (list.Count > Capacity) {
+        LinkedListNode<CacheEntry> item = list.First;
+        list.Remove(item);
+        index.Remove(item.Value);
+      }
+      OnSizeChanged();
+    }
+    #endregion
+
   }
 }
