Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.3/EvaluationCache.cs @ 6173

Last change on this file since 6173 was 6169, checked in by epitzer, 14 years ago

Add maximum capacity parameter and a least recently used replacement strategy to the evaluation cache (#1516)

File size: 6.2 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * The LRU cache is based on an idea by Robert Rossney see
21 * <http://csharp-lru-cache.googlecode.com>.
22 */
23#endregion
24
25using System;
26using System.Collections.Generic;
27using System.Linq;
28using HeuristicLab.Common;
29using HeuristicLab.Common.Resources;
30using HeuristicLab.Core;
31using HeuristicLab.Data;
32using HeuristicLab.Parameters;
33using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
34namespace HeuristicLab.Problems.ExternalEvaluation {
35
36  [Item("EvaluationCache", "Cache for external evaluation values")]
37  [StorableClass]
38  public class EvaluationCache : ParameterizedNamedItem {
39
40    #region Types
41    private class CacheEntry {
42
43      public string Key { get; private set; }
44      public double Value { get; set; }
45
46      public CacheEntry(string key, double value) {
47        Key = key;
48        Value = value;
49      }
50
51      public CacheEntry(string key) : this(key, 0) { }
52
53      public override bool Equals(object obj) {
54        CacheEntry other = obj as CacheEntry;
55        if (other == null)
56          return false;
57        return Key.Equals(other.Key);
58      }
59
60      public override int GetHashCode() {
61        return Key.GetHashCode();
62      }
63
64      public override string ToString() {
65        return string.Format("{{{0} : {1}}}", Key, Value);
66      }
67    }
68
69    public delegate double Evaluator(SolutionMessage message);
70    #endregion
71
72    #region Fields
73    private LinkedList<CacheEntry> list;
74    private Dictionary<CacheEntry, LinkedListNode<CacheEntry>> index;
75    #endregion
76
77    #region Properties
78    public override System.Drawing.Image ItemImage {
79      get { return VSImageLibrary.Database; }
80    }
81    public int Size {
82      get { return index.Count; }
83    }
84    [Storable]
85    public int Hits { get; private set; }
86    #endregion
87
88    #region events
89    public event EventHandler SizeChanged;
90    public event EventHandler HitsChanged;
91
92    protected virtual void OnSizeChanged() {
93      EventHandler handler = SizeChanged;
94      if (handler != null)
95        handler(this, EventArgs.Empty);
96    }
97    protected virtual void OnHitsChanged() {
98      EventHandler handler = HitsChanged;
99      if (handler != null)
100        handler(this, EventArgs.Empty);
101    }
102    #endregion
103
104    #region Parameters
105    public FixedValueParameter<IntValue> CapacityParameter {
106      get { return (FixedValueParameter<IntValue>)Parameters["Capacity"]; }
107    }
108    #endregion
109
110    #region Parameter Values
111    public int Capacity {
112      get { return CapacityParameter.Value.Value; }
113      set { CapacityParameter.Value.Value = value; }
114    }
115    #endregion
116
117    #region Persistence
118    [Storable(Name="Cache")]
119    private IEnumerable<KeyValuePair<string, double>> Cache_Persistence {
120      get {
121        return index.ToDictionary(kvp => kvp.Key.Key, kvp => kvp.Key.Value);
122      }
123      set {
124        list = new LinkedList<CacheEntry>();
125        index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
126        foreach (var kvp in value) {
127          var entry = new CacheEntry(kvp.Key);
128          entry.Value = kvp.Value;
129          index[entry] = list.AddLast(entry);
130        }
131      }
132    }
133    [StorableHook(HookType.AfterDeserialization)]
134    private void AfterDeserialization() {
135      RegisterEvents();
136    }
137    #endregion
138
139    #region Construction & Cloning
140    [StorableConstructor]
141    protected EvaluationCache(bool deserializing) : base(deserializing) { }
142    protected EvaluationCache(EvaluationCache original, Cloner cloner)
143      : base(original, cloner) {
144      Cache_Persistence = original.Cache_Persistence;
145      RegisterEvents();
146    }
147    public EvaluationCache() {
148      list = new LinkedList<CacheEntry>();
149      index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
150      Parameters.Add(new FixedValueParameter<IntValue>("Capacity", "Maximum number of cache entries.", new IntValue(10000)));
151      RegisterEvents();
152    }
153    public override IDeepCloneable Clone(Cloner cloner) {
154      return new EvaluationCache(this, cloner);
155    }
156    #endregion
157
158    #region Event Handling
159    private void RegisterEvents() {
160      CapacityParameter.Value.ValueChanged += new EventHandler(Value_ValueChanged);
161    }
162
163    void Value_ValueChanged(object sender, EventArgs e) {
164      if (Capacity < 0)
165        throw new ArgumentOutOfRangeException("Cache capacity cannot be less than zero");
166      Trim();
167    }
168    #endregion
169
170    #region Methods
171    public void Reset() {
172      list = new LinkedList<CacheEntry>();
173      index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
174      Hits = 0;
175      OnSizeChanged();
176      OnHitsChanged();
177    }
178
179    public double GetValue(SolutionMessage message, Evaluator evaluate) {
180      CacheEntry entry = new CacheEntry(message.ToString());
181      LinkedListNode<CacheEntry> node;
182      if (index.TryGetValue(entry, out node)) {
183        list.Remove(node);
184        list.AddLast(node);
185        Hits++;
186        OnHitsChanged();
187        return node.Value.Value;
188      } else {
189        entry.Value = evaluate(message);
190        index[entry] = list.AddLast(entry);
191        Trim();
192        return entry.Value;
193      }
194    }
195
196    private void Trim() {
197      while (list.Count > Capacity) {
198        LinkedListNode<CacheEntry> item = list.First;
199        list.Remove(item);
200        index.Remove(item.Value);
201      }
202      OnSizeChanged();
203    }
204    #endregion
205
206  }
207}
Note: See TracBrowser for help on using the repository browser.