source: trunk/CrypPlugins/QuadraticSieve/QuadraticSieve.cs @ 751

Last change on this file since 751 was 751, checked in by Sven Rech, 12 years ago

fixed msieve dll stuff

File size: 18.1 KB
Line 
1/*                             
2   Copyright 2009 Team CrypTool (Sven Rech,Dennis Nolte,Raoul Falk,Nils Kopal), Uni Duisburg-Essen
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17using System;
18using System.Collections;
19using System.Linq;
20using System.Text;
21using Cryptool.PluginBase;
22using Cryptool.PluginBase.IO;
23using QuadraticSieve;
24using Cryptool.PluginBase.Miscellaneous;
25using System.ComponentModel;
26using System.Threading;
27using System.IO;
28using System.Windows.Controls;
29using System.Windows.Threading;
30using System.Windows;
31using System.Reflection;
32
33namespace Cryptool.Plugins.QuadraticSieve
34{
35    [Author("Sven Rech", "rech@cryptool.org", "Uni Duisburg-Essen", "http://www.uni-due.de")]
36    [PluginInfo(false, "Quadratic Sieve", "Sieving Primes", "", "QuadraticSieve/iconqs.png")]
37    class QuadraticSieve : DependencyObject, IThroughput
38    {
39        #region IPlugin Members
40
41        private const string TempDirectoryName = "CrypTool Temp Files";
42        private static readonly string directoryName;
43        private QuadraticSieveSettings settings = new QuadraticSieveSettings();
44        private BigInteger inputNumber;
45        private BigInteger[] outputFactors;
46        private bool running;
47        private Queue yieldqueue;
48        private IntPtr obj = IntPtr.Zero;
49        private volatile int threadcount = 0;
50        private DateTime start_sieving_time;
51        private bool sieving_started;
52        private int start_relations;
53        private ArrayList conf_list;
54        private static Assembly msieveDLL;
55        private static Type msieve;
56        private bool userStopped = false;
57
58        static QuadraticSieve()
59        {
60            directoryName = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), TempDirectoryName), "msieve");
61            if (!Directory.Exists(directoryName)) Directory.CreateDirectory(directoryName);
62
63            //Load msieve.dll:
64            string s = Directory.GetCurrentDirectory();
65            string dllname;
66            if (IntPtr.Size == 4)
67                dllname = "msieve.dll";
68            else
69                dllname = "msieve64.dll";
70            msieveDLL = Assembly.LoadFile(Directory.GetCurrentDirectory() + "\\" + dllname);
71            msieve = msieveDLL.GetType("Msieve.msieve");
72        }
73
74        public QuadraticSieve()
75        {
76            QuickWatchPresentation = new QuadraticSievePresentation();
77           
78            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
79            {
80                quadraticSieveQuickWatchPresentation.timeLeft.Text = "?";
81                quadraticSieveQuickWatchPresentation.endTime.Text = "?";
82                quadraticSieveQuickWatchPresentation.logging.Text = "Currently not sieving.";
83            }
84            , null);
85        }               
86
87        public event StatusChangedEventHandler OnPluginStatusChanged;
88
89        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
90
91        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
92
93        public Cryptool.PluginBase.ISettings Settings
94        {
95            get { return this.settings; }
96            set { this.settings = (QuadraticSieveSettings)value; } 
97        }           
98
99        public void PreExecution()
100        { 
101        }
102
103        public void Execute()
104        {
105            userStopped = false;
106
107            if (InputNumber is Object)
108            {
109                if (InputNumber.ToString().Length >= 275)
110                {
111                    GuiLogMessage("Input too big.", NotificationLevel.Error);
112                    return;
113                }
114
115                String timeLeft_message = "?";
116                String endtime_message = "?";
117                String logging_message = "Starting quadratic sieve, please wait!";
118
119                GuiLogMessage(logging_message, NotificationLevel.Info);
120                quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
121                {
122                    quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
123                    quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
124                    quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
125                }
126                , null);   
127
128                DateTime start_time = DateTime.Now;
129
130                //init msieve with callbacks:
131                MethodInfo initMsieve = msieve.GetMethod("initMsieve");
132                Object callback_struct = Activator.CreateInstance(msieveDLL.GetType("Msieve.callback_struct"));
133                FieldInfo showProgressField = msieveDLL.GetType("Msieve.callback_struct").GetField("showProgress");
134                FieldInfo prepareSievingField = msieveDLL.GetType("Msieve.callback_struct").GetField("prepareSieving");
135                Delegate showProgressDel = MulticastDelegate.CreateDelegate(msieveDLL.GetType("Msieve.showProgressDelegate"), this, "showProgress");
136                Delegate prepareSievingDel = MulticastDelegate.CreateDelegate(msieveDLL.GetType("Msieve.prepareSievingDelegate"), this, "prepareSieving");
137                showProgressField.SetValue(callback_struct, showProgressDel);
138                prepareSievingField.SetValue(callback_struct, prepareSievingDel);
139                initMsieve.Invoke(null, new object[1] { callback_struct });
140
141                //Now factorize:
142                ArrayList factors;
143                try
144                {
145                    string file = Path.Combine(directoryName, "" + InputNumber + ".dat");
146                    if (settings.DeleteCache && File.Exists(file))
147                        File.Delete(file);
148                    MethodInfo factorize = msieve.GetMethod("factorize");
149                    factors = (ArrayList)factorize.Invoke(null, new object[] { InputNumber.ToString(), file });                   
150                    obj = IntPtr.Zero;
151                }
152                catch (Exception ex)
153                {
154                    GuiLogMessage("Error using msieve. " + ex.Message, NotificationLevel.Error);
155                    stopThreads();
156                    return;
157                }
158
159                if (factors != null && !userStopped)
160                {
161                    timeLeft_message = "0 seconds left";
162                    endtime_message = "" + (DateTime.Now);
163                    logging_message = "Sieving finished in " + (DateTime.Now - start_time) + "!";
164
165                    GuiLogMessage(logging_message, NotificationLevel.Info);
166                    quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
167                    {
168                        quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
169                        quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
170                        quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
171                    }
172                    , null);
173                    BigInteger[] outs = new BigInteger[factors.Count];
174                    for (int i = 0; i < factors.Count; i++)
175                    {
176                        outs[i] = new BigInteger((string)factors[i], 10);
177                    }
178                    OutputFactors = outs;
179                }
180                else
181                {
182                    timeLeft_message = "0 sec left";
183                    endtime_message = "Stopped";
184                    logging_message = "Stopped by user!";
185
186                    GuiLogMessage(logging_message, NotificationLevel.Info);
187                    quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
188                    {
189                        quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
190                        quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
191                        quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
192                    }
193                    , null);
194                }
195                   
196                ProgressChanged(1, 1);
197               
198            }
199        }
200
201        private String showTimeSpan(TimeSpan ts)
202        {
203            String res = "";
204            if (ts.Days != 0)
205                res = ts.Days + " days ";
206            if (ts.Hours != 0 || res.Length != 0)
207                res += ts.Hours + " hours ";
208            if (ts.Minutes != 0)
209                res += ts.Minutes + " minutes";
210            if (res.Length == 0)
211                res += ts.Seconds + " seconds";
212            return res;
213        }
214
215        private void showProgress(IntPtr conf, int num_relations, int max_relations)
216        {
217            if (num_relations == -1)    //sieving finished
218            {
219                ProgressChanged(0.9, 1.0);
220                GuiLogMessage("Sieving finished", NotificationLevel.Info);
221                stopThreads();
222                yieldqueue.Clear();               
223            }
224            else
225            {
226                if (sieving_started)
227                {
228                    TimeSpan diff = DateTime.Now - start_sieving_time;
229                    double msleft = (diff.TotalMilliseconds / (num_relations - start_relations)) * (max_relations - num_relations);
230                    if (msleft > 0)
231                    {
232                        TimeSpan ts = new TimeSpan(0, 0, 0, 0, (int)msleft);
233                        String logging_message = "Found " + num_relations + " of " + max_relations + " relations!";
234                        String timeLeft_message = showTimeSpan(ts) + " left";
235                        String endtime_message = "" + DateTime.Now.AddMilliseconds((long)msleft);
236                       
237                        GuiLogMessage(logging_message + " " + timeLeft_message + ".", NotificationLevel.Debug);
238                        quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
239                        {
240                            quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
241                            quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
242                            quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
243                        }
244                        , null);
245
246                    }
247                }
248
249                if (!sieving_started)
250                {
251                    start_relations = num_relations;
252                    start_sieving_time = DateTime.Now;
253                    sieving_started = true;
254                }
255
256                ProgressChanged((double)num_relations / max_relations * 0.8 + 0.1, 1.0);               
257
258                while (yieldqueue.Count != 0)       //get all the results from the helper threads, and store them
259                {
260                    MethodInfo saveYield = msieve.GetMethod("saveYield");
261                    saveYield.Invoke(null, new object[] { conf, (IntPtr)yieldqueue.Dequeue() });                   
262                }               
263            }
264        }
265
266        private void prepareSieving (IntPtr conf, int update, IntPtr core_sieve_fcn)
267        {
268            int threads = Math.Min(settings.CoresUsed, Environment.ProcessorCount-1);
269            MethodInfo getObjFromConf = msieve.GetMethod("getObjFromConf");
270            this.obj = (IntPtr)getObjFromConf.Invoke(null, new object[] { conf });           
271            yieldqueue = Queue.Synchronized(new Queue());
272            sieving_started = false;
273            conf_list = new ArrayList();
274
275            String message = "Start sieving using " + (threads + 1) + " cores!";
276            GuiLogMessage(message, NotificationLevel.Info);
277            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
278            {
279                quadraticSieveQuickWatchPresentation.logging.Text = message;
280            }
281            , null);         
282
283            ProgressChanged(0.1, 1.0);
284
285            running = true;
286            //start helper threads:
287            for (int i = 0; i < threads; i++)
288            {
289                MethodInfo cloneSieveConf = msieve.GetMethod("cloneSieveConf");
290                IntPtr clone = (IntPtr)cloneSieveConf.Invoke(null, new object[] { conf });               
291                conf_list.Add(clone);
292                WaitCallback worker = new WaitCallback(MSieveJob);
293                ThreadPool.QueueUserWorkItem(worker, new object[] { clone, update, core_sieve_fcn, yieldqueue });
294            }
295        }
296
297        //Helper Thread for msieve, which sieves for relations:
298        private void MSieveJob(object param)
299        {
300            threadcount++;
301            object[] parameters = (object[])param;
302            IntPtr clone = (IntPtr)parameters[0];
303            int update = (int)parameters[1];
304            IntPtr core_sieve_fcn = (IntPtr)parameters[2];
305            Queue yieldqueue = (Queue)parameters[3];
306
307            while (running)
308            {
309                try
310                {
311                    MethodInfo collectRelations = msieve.GetMethod("collectRelations");
312                    collectRelations.Invoke(null, new object[] { clone, update, core_sieve_fcn });
313                    MethodInfo getYield = msieve.GetMethod("getYield");
314                    IntPtr yield = (IntPtr)getYield.Invoke(null, new object[] { clone });                   
315                    yieldqueue.Enqueue(yield);
316                }
317                catch (Exception ex)
318                {
319                    GuiLogMessage("Error using msieve." + ex.Message, NotificationLevel.Error);
320                    threadcount = 0;
321                    return;
322                }               
323            }
324            MethodInfo freeSieveConf = msieve.GetMethod("freeSieveConf");
325            freeSieveConf.Invoke(null, new object[] { clone });           
326            threadcount--;
327        }
328
329        public void PostExecution()
330        {           
331        }
332
333        public void Pause()
334        {           
335        }
336
337        public void Stop()
338        {
339            this.userStopped = true;
340            if (obj != IntPtr.Zero)
341            {
342                stopThreads();
343                MethodInfo stop = msieve.GetMethod("stop");
344                stop.Invoke(null, new object[] { obj });
345            }
346           
347        }
348
349        private void stopThreads()
350        {
351            if (conf_list != null)
352            {
353                running = false;
354                MethodInfo stop = msieve.GetMethod("stop");
355                MethodInfo getObjFromConf = msieve.GetMethod("getObjFromConf");
356                foreach (IntPtr conf in conf_list)
357                    stop.Invoke(null, new object[] { getObjFromConf.Invoke(null, new object[] {conf}) });
358                GuiLogMessage("Waiting for threads to stop!", NotificationLevel.Debug);
359                while (threadcount > 0)
360                {
361                    Thread.Sleep(0);
362                }
363                GuiLogMessage("Threads stopped!", NotificationLevel.Debug);
364                conf_list.Clear();
365            }
366        }
367
368        public void Initialize()
369        {           
370        }
371
372        public void Dispose()
373        {
374        }
375
376        #endregion
377
378        #region QuadraticSieveInOut
379
380        [PropertyInfo(Direction.InputData, "Number Input", "Put the number you want to factorize here", "", DisplayLevel.Beginner)]
381        public BigInteger InputNumber
382        {
383            get
384            {
385                return inputNumber;
386            }
387            set
388            {
389                this.inputNumber = value;
390                OnPropertyChanged("InputNumber");
391            }
392        }
393
394
395        [PropertyInfo(Direction.OutputData, "Factors Output", "Your factors will be sent here", "", DisplayLevel.Beginner)]
396        public BigInteger[] OutputFactors
397        {
398            get
399            {
400                return outputFactors;
401            }
402            set
403            {
404                this.outputFactors = value;
405                OnPropertyChanged("OutputFactors");
406            }
407        }
408
409        #endregion
410
411        #region INotifyPropertyChanged Members
412
413        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
414
415        public void OnPropertyChanged(string name)
416        {
417            EventsHelper.PropertyChanged(PropertyChanged, this, new PropertyChangedEventArgs(name));
418        }
419
420        public event PluginProgressChangedEventHandler OnPluginProcessChanged;
421
422        private void ProgressChanged(double value, double max)
423        {
424            EventsHelper.ProgressChanged(OnPluginProgressChanged, this, new PluginProgressEventArgs(value, max));
425        }
426
427        private void GuiLogMessage(string p, NotificationLevel notificationLevel)
428        {
429            EventsHelper.GuiLogMessage(OnGuiLogNotificationOccured, this, new GuiLogEventArgs(p, this, notificationLevel));
430        }
431
432        #endregion
433
434        #region IPlugin Members
435
436        private QuadraticSievePresentation quadraticSieveQuickWatchPresentation
437        {
438            get { return QuickWatchPresentation as QuadraticSievePresentation; }
439        }
440
441        public UserControl Presentation { get; private set; }
442
443        public UserControl QuickWatchPresentation
444        {
445            get;
446            private set;
447        }
448
449        #endregion
450    }
451}
Note: See TracBrowser for help on using the repository browser.