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

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