source: trunk/CrypPlugins/FrequencyTest/FrequencyTest.cs @ 738

Last change on this file since 738 was 738, checked in by Arno Wacker, 12 years ago
  • Fixed autozoom feature of frequency test; finally seems to work in all cases - this closes #97, after all it was not an editor bug, but a missing "Stretch" in the FrequencyTest-presentation.
  • Removed the zoom-slider from presentation. Zoom/Scale is now accessible only in the settings (usually not needed, since autozoom is default)
  • Re-introduced ProgressChanged (faked, it just become fully green when done)
  • Changed Background to LightYellow in Run-mode and LightGray when stopped. This way it does not interfere with the progress-green.
  • Updated samples using FrequencyTest to avoid loading warnings.
File size: 13.4 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Linq;
5using System.Text;
6using System.Windows.Controls;
7using Cryptool.PluginBase;
8using Cryptool.PluginBase.Analysis;
9using Cryptool.PluginBase.Miscellaneous;
10using System.Windows.Media;
11
12namespace Cryptool.FrequencyTest
13{
14    [Author("Georgi Angelov & Danail Vazov & Matthäus Wander", "angelov@cryptool.org", "Uni Duisburg", "http://www.uni-duisburg-essen.de")]
15    [PluginInfo(false,
16    "Frequency Test",
17    "Calculates the frequency of letters or groups of letters in a string.",
18    "FrequencyTest/DetailedDescription/Description.xaml",
19    "FrequencyTest/icon.png")]
20    public class FrequencyTest : IStatistic
21    {
22        #region Const and variable definition
23
24        public const int ABSOLUTE = 0;
25        public const int PERCENTAGED = 1;
26        public const int LOG2 = 2;
27        public const int SINKOV = 3;
28
29        private string stringInput;
30
31        private string stringOutput = "";
32        private int[] arrayOutput = new int[0];
33        private IDictionary<string, double[]> grams = new SortedDictionary<string, double[]>();
34        private DataSource data = new DataSource();
35        private double presentationScaler = 1.0; // the initial zoom value
36        private double presentationBarWidth = 24.7; // the width in pixel of a single chart bar
37        private double presentationBarHeightAdd = 8.0 + 2.0 * 26.0; // the additional heigth to a chart bar, comprised of two rectangles (3px, 5px) and two textblocks
38
39        // TODO: this shall be an algorithm setting or an optional word
40        private const string validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
41
42       
43
44        #endregion
45
46        #region Properties (Inputs/Outputs)
47
48        [PropertyInfo(Direction.InputData, "The string to be analyzed", "Text Input", "",true, true, DisplayLevel.Beginner, QuickWatchFormat.Text, null)]
49        public string StringInput
50        {
51            get
52            {
53                return stringInput;
54            }
55            set
56            {
57                stringInput = value;
58                OnPropertyChanged("StringInput");
59            }
60        }
61
62        [PropertyInfo(Direction.OutputData, "Text output", "letter:absolute frequency of the letter:relative frequency of the letter (in %)", "", false, false, DisplayLevel.Beginner, QuickWatchFormat.Text, null)]
63        public string StringOutput
64        {
65            get { return stringOutput; }
66        }
67
68        [PropertyInfo(Direction.OutputData , "List output", "absolute frequency of a letter", "", false, false, DisplayLevel.Beginner, QuickWatchFormat.None, "QuickWatchArray")]
69        public int[] ArrayOutput
70        {
71            get { return arrayOutput; }
72        }
73
74        public object QuickWatchArray(string propertyNameToConvert)
75        {
76            StringBuilder sb = new StringBuilder();
77            foreach (int i in arrayOutput)
78            {
79                sb.Append(i);
80                sb.AppendLine();
81            }
82            return sb.ToString();
83        }
84
85        [PropertyInfo(Direction.OutputData, "Dictionary output", "Found grams and their quantities in different scalings", "", false, false, DisplayLevel.Experienced, QuickWatchFormat.None, "QuickWatchDictionary")]
86        public IDictionary<string, double[]> DictionaryOutput
87        {
88            get { return grams; }
89       
90        }
91
92        public object QuickWatchDictionary(string propertyNameToConvert)
93        {
94            lock (grams)
95            {
96                StringBuilder sb = new StringBuilder();
97                foreach (KeyValuePair<string, double[]> item in grams)
98                {
99                    sb.Append(item.Key);
100                    for (int i = 0; i < item.Value.Length; i++)
101                    {
102                        sb.Append(";" + item.Value[i]);
103                    }
104                    sb.AppendLine();
105                }
106                return sb.ToString();
107            }
108        }
109        #endregion
110
111        #region IPlugin Members
112
113        private FrequencyTestSettings settings;
114        public ISettings Settings
115        {
116            get { return settings; }
117            set { settings = (FrequencyTestSettings)value; }
118        }
119        private FrequencyTestPresentation presentation;
120        public FrequencyTest()
121        {
122            settings = new FrequencyTestSettings();
123            presentation = new FrequencyTestPresentation();
124            Presentation = presentation;
125            QuickWatchPresentation = presentation;
126
127            presentation.SizeChanged += new System.Windows.SizeChangedEventHandler(presentation_SizeChanged);
128
129            settings.PropertyChanged += new PropertyChangedEventHandler(settings_PropertyChanged);
130        }
131
132       
133
134       
135        public UserControl Presentation { get; private set; }
136
137        public UserControl QuickWatchPresentation { get; private set; }
138
139        public void PreExecution()
140        {
141            //throw new NotImplementedException();
142        }
143
144        public void Execute()
145        {
146            if (stringInput == null)
147            {
148                return;
149            }
150
151            presentation.SetBackground(Brushes.LightYellow);
152
153            string workstring = stringInput;
154
155            // Any change in the word discards and recalculates the output. This is not that effective.
156            lock (grams)
157            {
158                grams.Clear();
159
160                if (settings.BoundaryFragments == 1)
161                {
162                    foreach (string word in WordTokenizer.tokenize(workstring))
163                    {
164                        ProcessWord(word);
165                    }
166                }
167                else
168                {
169                    ProcessWord(workstring);
170                }
171
172                double sum = grams.Values.Sum(item => item[ABSOLUTE]);
173                GuiLogMessage("Sum of all n-gram counts is: " + sum, NotificationLevel.Debug);
174
175                // calculate scaled values
176                foreach (double[] g in grams.Values)
177                {
178                    g[PERCENTAGED] = g[ABSOLUTE] / sum;
179                    g[LOG2] = Math.Log(g[ABSOLUTE], 2);
180                    g[SINKOV] = Math.Log(g[PERCENTAGED], Math.E);
181                }
182
183                // OUTPUT
184                StringBuilder sb = new StringBuilder();
185                arrayOutput = new int[grams.Count];
186                for (int i = 0; i < grams.Count; i++)
187                {
188                    KeyValuePair<string, double[]> item = grams.ElementAt(i);
189
190                    sb.Append(item.Key + ":");
191                    sb.Append(item.Value[ABSOLUTE] + ":");
192                    sb.Append((item.Value[PERCENTAGED]) + Environment.NewLine);
193
194                    arrayOutput[i] = (int)item.Value[ABSOLUTE];
195                }
196                stringOutput = sb.ToString();
197
198                // update the presentation data
199                updatePresentation();
200            }
201
202            // Show progress finished.
203            EventsHelper.ProgressChanged(OnPluginProgressChanged, this, new PluginProgressEventArgs(1.0, 1.0));
204
205            OnPropertyChanged("StringOutput");
206            OnPropertyChanged("ArrayOutput");
207            OnPropertyChanged("DictionaryOutput");
208           
209           
210        }
211
212        private void ProcessWord(string workstring)
213        {
214            if (settings.ProcessUnknownSymbols == 0)
215            {
216                workstring = StringUtil.StripUnknownSymbols(validChars, workstring);
217            }
218
219            if (workstring.Length == 0)
220            {
221                return;
222            }
223
224            if (settings.CaseSensitivity == 0)
225            {
226                workstring = workstring.ToUpper();
227            }
228
229            foreach (string g in GramTokenizer.tokenize(workstring, settings.GrammLength, settings.BoundaryFragments == 1))
230            {
231                if (!grams.ContainsKey(g))
232                {
233                    grams[g] = new double[] { 1, 0, 0, 0 };
234                }
235                else
236                {
237                    grams[g][ABSOLUTE]++;
238                }
239            }
240        }
241
242
243        private void updatePresentation()
244        {
245            if (grams.Count > 0 && presentation.ActualWidth > 0)
246            {
247                // retrieve the maximum value from all grams
248                double max = grams.Values.Max(item => item[PERCENTAGED]);
249                GuiLogMessage("Max n-gram percentage is: " + max, NotificationLevel.Debug);
250
251                // calculate the needed width for the chart (unscaled) in pixel
252                double unscaledChartWidth = (double)grams.Count * presentationBarWidth;
253
254                // retrieve the maximum bar height from settings in pixel
255                double maxBarHeight = (double) settings.ChartHeight;
256
257
258                if (settings.Autozoom)
259                {
260                    // calculate the scaling-value depeding on the needed width ad the current presetnation width
261                    presentationScaler = presentation.ActualWidth / unscaledChartWidth;
262                    settings.Scale = (int)(presentationScaler * 10000.0);
263
264                    //set the maximum bar height to the current heigth of chart-area in presentation (best fill)
265                    //maxBarHeight = presentation.chartBars.ActualHeight - presentationBarHeightAdd;
266                    maxBarHeight = (presentation.ActualHeight / presentationScaler) - (presentation.chartHeadline.ActualHeight + presentationBarHeightAdd);
267                }
268
269                // remove all entries
270                data.ValueCollection.Clear();
271
272                // calculate presentation bars height and add the to our local DataSource
273                foreach (KeyValuePair<string, double[]> item in grams)
274                {
275                    double height = item.Value[PERCENTAGED] * (maxBarHeight / max);
276                    CollectionElement row = new CollectionElement(height, Math.Round(item.Value[PERCENTAGED] * 100, 2), item.Key);
277                    data.ValueCollection.Add(row);
278                }
279
280                switch (settings.GrammLength)
281                {
282                    case 1:
283                        presentation.SetHeadline("Character (unigram) frequency (in %)");
284                        break;
285                    case 2:
286                        presentation.SetHeadline("Bigram frequency (in %)");
287                        break;
288                    case 3:
289                        presentation.SetHeadline("Trigram frequency (in %)");
290                        break;
291                    default:
292                        presentation.SetHeadline(settings.GrammLength + "-gram frequency (in %)");
293                        break;
294                }
295               
296
297                presentation.ShowData(data);
298            }
299        }
300
301        private void presentation_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
302        {
303            // Just for debugging
304            //if (e.HeightChanged)
305            //{
306            //    GuiLogMessage("Height changed from " + e.PreviousSize.Height + " to " + e.NewSize.Height, NotificationLevel.Info);
307            //}
308
309            //if (e.WidthChanged)
310            //{
311            //    GuiLogMessage("Width changed from " + e.PreviousSize.Width + " to " + e.NewSize.Width, NotificationLevel.Info);
312            //}
313
314            updatePresentation();
315        }
316
317        private void settings_PropertyChanged(object sender, PropertyChangedEventArgs e)
318        {
319            switch (e.PropertyName)
320            {
321                case "Autozoom":
322                case "ChartHeight":
323                    updatePresentation();
324                    break;
325
326                case "Scale":
327                    presentation.SetScaler( (double)settings.Scale / 10000.0);
328                    break;
329            }
330        }
331
332
333        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
334        private void GuiLogMessage(string p, NotificationLevel notificationLevel)
335        {
336            EventsHelper.GuiLogMessage(OnGuiLogNotificationOccured, this, new GuiLogEventArgs(p, this, notificationLevel));
337        }
338
339        public void PostExecution()
340        {
341            //throw new NotImplementedException();
342        }
343
344        public void Pause()
345        {
346            //throw new NotImplementedException();
347        }
348
349        public void Stop()
350        {
351            presentation.SetBackground(Brushes.LightGray);
352        }
353
354        public void Initialize()
355        {
356            //throw new NotImplementedException();
357        }
358
359        public void Dispose()
360        {
361            //throw new NotImplementedException();
362        }
363
364       
365        #endregion
366
367        #region INotifyPropertyChanged Members
368
369        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
370
371        protected void OnPropertyChanged(string name)
372        {
373            if (PropertyChanged != null)
374            {
375                PropertyChanged(this, new PropertyChangedEventArgs(name));
376            }
377        }
378
379        public event StatusChangedEventHandler OnPluginStatusChanged;
380
381        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
382
383        #endregion
384
385    }
386   
387 
388}
389
390
391
392
393
Note: See TracBrowser for help on using the repository browser.