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

Last change on this file since 1819 was 1819, checked in by Sven Rech, 11 years ago

fixed stop bug in quadratic sieve plugin

File size: 38.6 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 Cryptool.PluginBase.Miscellaneous;
24using System.ComponentModel;
25using System.Threading;
26using System.IO;
27using System.Windows.Controls;
28using System.Windows.Threading;
29using System.Windows;
30using System.Reflection;
31using System.Numerics;
32using System.Collections.Generic;
33using System.Diagnostics;
34using Cryptool.P2P;
35
36namespace Cryptool.Plugins.QuadraticSieve
37{
38    /// <summary>
39    /// This class wraps the msieve algorithm in version 1.42 which you can find at http://www.boo.net/~jasonp/qs.html
40    /// It also extends the msieve functionality to multi threading
41    /// Many thanks to the author of msieve "jasonp_sf"
42    ///
43    /// For further information on quadratic sieve or msieve please have a look at the above mentioned URL
44    /// </summary>
45    [Author("Sven Rech", "rech@cryptool.org", "Uni Duisburg-Essen", "http://www.uni-due.de")]
46    [PluginInfo(false, "Quadratic Sieve", "Sieving Primes", "QuadraticSieve/DetailedDescription/Description.xaml", "QuadraticSieve/iconqs.png")]
47    class QuadraticSieve : DependencyObject, IThroughput
48    {
49        #region private variables
50
51        private readonly string directoryName;
52        private QuadraticSieveSettings settings;
53        private BigInteger inputNumber;
54        private BigInteger[] outputFactors;
55        private bool running;
56        private Queue relationPackageQueue;
57        private AutoResetEvent newRelationPackageEvent = new AutoResetEvent(false);
58        private IntPtr obj = IntPtr.Zero;
59        private volatile int threadcount = 0;
60        private ArrayList conf_list;
61        private Mutex conf_listMutex = new Mutex();
62        private bool userStopped = false;
63        private FactorManager factorManager;
64        private PeerToPeer peerToPeer;
65        private PeerToPeerStatusUpdater peerToPeerStatusUpdater;
66        private bool usePeer2Peer;
67        private bool otherPeerFinished;
68        private bool useGnuplot = false;
69        private StreamWriter gnuplotFile;
70        private double[] relationsPerMS;
71
72        private static Assembly msieveDLL = null;
73        private static Type msieve = null;
74        private static bool alreadyInUse = false;
75        private static Mutex alreadyInUseMutex = new Mutex();
76        private AutoResetEvent waitForConnection = new AutoResetEvent(false);
77
78        #endregion
79
80        #region events
81
82        public event StatusChangedEventHandler OnPluginStatusChanged;
83        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
84        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
85        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
86        public event PluginProgressChangedEventHandler OnPluginProcessChanged;
87
88        #endregion
89
90        #region public
91
92        /// <summary>
93        /// Constructor
94        ///
95        /// constructs a new QuadraticSieve plugin
96        /// </summary>
97        public QuadraticSieve()
98        {
99            Settings = new QuadraticSieveSettings(this);
100
101            directoryName = Path.Combine(DirectoryHelper.DirectoryLocalTemp, "msieve");
102            if (!Directory.Exists(directoryName)) Directory.CreateDirectory(directoryName);
103
104            QuickWatchPresentation = new QuadraticSievePresentation();
105
106            peerToPeer = new PeerToPeer(quadraticSieveQuickWatchPresentation, newRelationPackageEvent);
107            peerToPeerStatusUpdater = new PeerToPeerStatusUpdater(peerToPeer);
108            peerToPeer.P2PWarning += new PeerToPeer.P2PWarningHandler(peerToPeer_P2PWarning);
109           
110            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
111            {
112                quadraticSieveQuickWatchPresentation.peer2peer.Visibility = settings.UsePeer2Peer ? Visibility.Visible : Visibility.Collapsed;               
113                quadraticSieveQuickWatchPresentation.timeLeft.Text = "?";
114                quadraticSieveQuickWatchPresentation.endTime.Text = "?";
115                quadraticSieveQuickWatchPresentation.logging.Text = "Currently not sieving.";
116            }
117            , null);
118        }
119
120        /// <summary>
121        /// Getter / Setter for the settings of this plugin
122        /// </summary>
123        public Cryptool.PluginBase.ISettings Settings
124        {
125            get { return this.settings; }
126            set
127            {
128                this.settings = (QuadraticSieveSettings)value;
129                this.settings.PropertyChanged += new PropertyChangedEventHandler(settings_PropertyChanged);
130            }
131        }
132
133        private void settings_PropertyChanged(object sender, PropertyChangedEventArgs e)
134        {
135            if (e.PropertyName == "UsePeer2Peer")
136            {
137                if (quadraticSieveQuickWatchPresentation != null)
138                {
139                    quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
140                    {
141                        quadraticSieveQuickWatchPresentation.peer2peer.Visibility = settings.UsePeer2Peer ? Visibility.Visible : Visibility.Collapsed;                       
142                    }, null);
143                }
144            }
145        }
146
147        /// <summary>
148        /// Called by the environment before executing this plugin
149        /// </summary>
150        public void PreExecution()
151        { 
152        }
153       
154        /// <summary>
155        /// Called by the environment to execute this plugin
156        /// </summary>
157        public void Execute()
158        {
159            if (checkInUse())
160                return;
161           
162            try
163            {
164                usePeer2Peer = settings.UsePeer2Peer;
165                if (usePeer2Peer && !P2PManager.IsConnected && P2PManager.IsConnecting)
166                {
167                    P2PManager.ConnectionManager.OnP2PConnectionStateChangeOccurred += HandleConnectionStateChange;
168                    GuiLogMessage("Connecting to Peer2Peer network... Please wait!", NotificationLevel.Info);
169                    waitForConnection.WaitOne();                   
170                    P2PManager.ConnectionManager.OnP2PConnectionStateChangeOccurred -= HandleConnectionStateChange;
171                }
172                else if (usePeer2Peer && !P2PManager.IsConnected)
173                {
174                    GuiLogMessage("No connection to Peer2Peer network. Sieving locally now but waiting for connection...", NotificationLevel.Warning);
175                    P2PManager.ConnectionManager.OnP2PConnectionStateChangeOccurred += OnP2PConnectionStateChangeOccurred;
176                    usePeer2Peer = false;
177                }
178
179                if (usePeer2Peer && settings.Channel.Trim() == "")
180                {
181                    GuiLogMessage("No channel for Peer2Peer network specified. Sieving locally now!", NotificationLevel.Warning);
182                    usePeer2Peer = false;
183                }
184                if (settings.UsePeer2Peer)
185                {
186                    peerToPeer.SetChannel(settings.Channel);
187                    peerToPeer.SetNumber(InputNumber);
188                }
189
190                if (useGnuplot)
191                    gnuplotFile = new StreamWriter(Path.Combine(directoryName, "gnuplot.dat"), false);
192
193                userStopped = false;
194                otherPeerFinished = false;
195
196                if (InputNumber != 0)
197                {
198                    if (InputNumber.ToString().Length >= 275)
199                    {
200                        GuiLogMessage("Input too big.", NotificationLevel.Error);
201                        return;
202                    }
203
204                    String timeLeft_message = "?";
205                    String endtime_message = "?";
206                    String logging_message = "Starting quadratic sieve, please wait!";
207
208                    GuiLogMessage(logging_message, NotificationLevel.Info);
209                    quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
210                    {
211                        quadraticSieveQuickWatchPresentation.ProgressRelationPackages.Clear();
212                        quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
213                        quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
214                        quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
215                        quadraticSieveQuickWatchPresentation.factorList.Items.Clear();
216                        quadraticSieveQuickWatchPresentation.factorInfo.Content = "Searching trivial factors!";
217                        if (usePeer2Peer)
218                            quadraticSieveQuickWatchPresentation.relationsInfo.Content = "";
219                        else
220                            quadraticSieveQuickWatchPresentation.relationsInfo.Content = "Only local sieving!";
221                    }
222                    , null);
223
224                    DateTime start_time = DateTime.Now;
225
226                    initMsieveDLL();
227                    factorManager = new FactorManager(msieve.GetMethod("getPrimeFactors"), msieve.GetMethod("getCompositeFactors"), InputNumber);
228                    factorManager.FactorsChanged += this.FactorsChanged;
229
230                    //Now factorize:               
231                    try
232                    {
233                        string file = Path.Combine(directoryName, "" + InputNumber + ".dat");
234                        if (settings.DeleteCache && File.Exists(file))
235                            File.Delete(file);
236                        MethodInfo start = msieve.GetMethod("start");
237                        start.Invoke(null, new object[] { InputNumber.ToString(), file });
238                        obj = IntPtr.Zero;
239                    }
240                    catch (Exception ex)
241                    {
242                        GuiLogMessage("Error using msieve. " + ex.Message, NotificationLevel.Error);
243                        stopThreads();
244                        return;
245                    }
246
247                    if (!userStopped)
248                    {
249                        timeLeft_message = "0 seconds left";
250                        endtime_message = "" + (DateTime.Now);
251                        logging_message = "Sieving finished in " + (DateTime.Now - start_time) + "!";
252
253                        GuiLogMessage(logging_message, NotificationLevel.Info);
254                        quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
255                        {
256                            quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
257                            quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
258                            quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
259                            quadraticSieveQuickWatchPresentation.factorInfo.Content = "";
260                        }
261                        , null);
262
263                        Debug.Assert(factorManager.CalculateNumber() == InputNumber);
264                        OutputFactors = factorManager.getPrimeFactors();
265
266                        ProgressChanged(1, 1);
267                    }
268                    else
269                    {
270                        timeLeft_message = "0 sec left";
271                        endtime_message = "Stopped";
272                        logging_message = "Stopped by user!";
273
274                        GuiLogMessage(logging_message, NotificationLevel.Info);
275                        quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
276                        {
277                            quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
278                            quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
279                            quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
280                            quadraticSieveQuickWatchPresentation.factorInfo.Content = "";
281                        }
282                        , null);
283                    }
284                }
285                if (useGnuplot)
286                    gnuplotFile.Close();
287            }
288            finally
289            {
290                alreadyInUse = false;
291                P2PManager.ConnectionManager.OnP2PConnectionStateChangeOccurred -= OnP2PConnectionStateChangeOccurred;
292            }
293        }
294
295        private void OnP2PConnectionStateChangeOccurred(object sender, bool newState)
296        {
297            usePeer2Peer = newState;
298            if (usePeer2Peer)
299                GuiLogMessage("Using Peer2Peer network now!", NotificationLevel.Info);
300            else
301                GuiLogMessage("Lost Peer2Peer network connection... Sieving locally now!", NotificationLevel.Info);
302        }
303
304        private void HandleConnectionStateChange(object sender, bool newState)
305        {
306            waitForConnection.Set();
307        }
308
309        private bool checkInUse()
310        {
311            try
312            {
313                alreadyInUseMutex.WaitOne();
314                if (alreadyInUse)
315                {
316                    GuiLogMessage("QuadraticSieve plugin is only allowed to execute ones at a time due to technical restrictions.", NotificationLevel.Error);
317                    return true;
318                }
319                else
320                {
321                    alreadyInUse = true;
322                    return false;
323                }
324            }
325            finally
326            {
327                alreadyInUseMutex.ReleaseMutex();
328            }
329        }
330       
331        /// <summary>
332        /// Called by the environment after execution
333        /// </summary>
334        public void PostExecution()
335        {
336        }
337
338        /// <summary>
339        /// Called by the environment to pause execution
340        /// </summary>
341        public void Pause()
342        {
343        }
344
345        /// <summary>
346        /// Called by the environment to stop execution
347        /// </summary>
348        public void Stop()
349        {           
350            if (obj != IntPtr.Zero)
351            {
352                stopThreads();
353                MethodInfo stop = msieve.GetMethod("stop");
354                stop.Invoke(null, new object[] { obj });
355            }
356            this.userStopped = true;
357        }
358
359        /// <summary>
360        /// Called by the environment to initialize this plugin
361        /// </summary>
362        public void Initialize()
363        {
364            settings.Initialize();
365        }
366
367        /// <summary>
368        /// Called by the environment to dispose this plugin
369        /// </summary>
370        public void Dispose()
371        {
372        }
373
374        /// <summary>
375        /// Getter / Setter for the input number which should be factorized
376        /// </summary>
377        [PropertyInfo(Direction.InputData, "Number input", "Enter the number you want to factorize", "", DisplayLevel.Beginner)]
378        public BigInteger InputNumber
379        {
380            get
381            {
382                return inputNumber;
383            }
384            set
385            {
386                this.inputNumber = value;
387                OnPropertyChanged("InputNumber");
388            }
389        }
390
391        /// <summary>
392        /// Getter / Setter for the factors calculated by msieve
393        /// </summary>
394        [PropertyInfo(Direction.OutputData, "Factors output", "Your factors will be sent here", "", DisplayLevel.Beginner)]
395        public BigInteger[] OutputFactors
396        {
397            get
398            {
399                return outputFactors;
400            }
401            set
402            {
403                this.outputFactors = value;
404                OnPropertyChanged("OutputFactors");
405            }
406        }
407       
408        /// <summary>
409        /// Called when a property of this plugin changes
410        /// </summary>
411        /// <param name="name">name</param>
412        public void OnPropertyChanged(string name)
413        {
414            EventsHelper.PropertyChanged(PropertyChanged, this, new PropertyChangedEventArgs(name));
415        }
416
417        /// <summary>
418        /// Getter / Setter for the presentation of this plugin
419        /// </summary>
420        public UserControl Presentation { get; private set; }
421
422        /// <summary>
423        /// Getter / Setter for the QuickWatchPresentation of this plugin
424        /// </summary>
425        public UserControl QuickWatchPresentation
426        {
427            get;
428            private set;
429        }
430
431        #endregion
432
433        #region private
434
435        /// <summary>
436        /// calculate a String which shows the timespan
437        ///
438        /// example
439        ///
440        ///     4 days
441        /// or
442        ///     2 minutes
443        /// </summary>
444        /// <param name="ts"></param>
445        /// <returns></returns>
446        private String showTimeSpan(TimeSpan ts)
447        {
448            String res = "";
449            if (ts.Days != 0)
450                res = ts.Days + " days ";
451            if (ts.Hours != 0 || res.Length != 0)
452                res += ts.Hours + " hours ";
453            if (ts.Minutes != 0)
454                res += ts.Minutes + " minutes";
455            if (res.Length == 0)
456                res += ts.Seconds + " seconds";
457            return res;
458        }
459
460        /// <summary>
461        /// Callback method to prepare sieving
462        /// Called by msieve
463        ///
464        /// </summary>       
465        /// <param name="conf">pointer to configuration</param>
466        /// <param name="update">number of relations found</param>
467        /// <param name="core_sieve_fcn">pointer to internal sieve function of msieve</param>
468        /// <returns>true if enough relations found, false if not</returns>
469        private bool prepareSieving(IntPtr conf, int update, IntPtr core_sieve_fcn, int max_relations)
470        {
471            try
472            {
473                int threads = Math.Min(settings.CoresUsed, Environment.ProcessorCount - 1);
474                MethodInfo getObjFromConf = msieve.GetMethod("getObjFromConf");
475                this.obj = (IntPtr)getObjFromConf.Invoke(null, new object[] { conf });
476                relationPackageQueue = Queue.Synchronized(new Queue());
477                conf_list = new ArrayList();
478
479                String message = "Start sieving using " + (threads + 1) + " cores!";
480                GuiLogMessage(message, NotificationLevel.Info);
481                quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
482                {
483                    quadraticSieveQuickWatchPresentation.logging.Text = message;
484                    if (usePeer2Peer)
485                        quadraticSieveQuickWatchPresentation.relationsInfo.Content = "";
486                }
487                , null);
488
489                ProgressChanged(0.1, 1.0);
490
491                running = true;
492                //start helper threads:
493                relationsPerMS = new double[threads + 1];
494                for (int i = 0; i < threads + 1; i++)
495                {
496                    MethodInfo cloneSieveConf = msieve.GetMethod("cloneSieveConf");
497                    IntPtr clone = (IntPtr)cloneSieveConf.Invoke(null, new object[] { conf });
498                    conf_list.Add(clone);
499                    WaitCallback worker = new WaitCallback(MSieveJob);
500                    ThreadPool.QueueUserWorkItem(worker, new object[] { clone, update, core_sieve_fcn, relationPackageQueue, i });
501                }
502
503                //manage the relation packages of the other threads:
504                manageRelationPackages(conf, max_relations);  //this method returns as soon as there are enough relations found
505                if (userStopped)
506                    return false;
507
508                //sieving is finished now, so give some informations and stop threads:
509                ProgressChanged(0.9, 1.0);
510                GuiLogMessage("Sieving finished", NotificationLevel.Info);
511                quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
512                {
513                    quadraticSieveQuickWatchPresentation.timeLeft.Text = "";
514                    quadraticSieveQuickWatchPresentation.endTime.Text = "";
515                    quadraticSieveQuickWatchPresentation.factorInfo.Content = "Found enough relations! Please wait...";
516                }, null);
517
518                if (relationPackageQueue != null)
519                    relationPackageQueue.Clear();
520            }
521            catch (AlreadySievedException)
522            {
523                ProgressChanged(0.9, 1.0);
524                GuiLogMessage("Another peer already finished factorization of composite factor. Sieving next one...", NotificationLevel.Info);
525                quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
526                {
527                    quadraticSieveQuickWatchPresentation.timeLeft.Text = "";
528                    quadraticSieveQuickWatchPresentation.endTime.Text = "";
529                    quadraticSieveQuickWatchPresentation.factorInfo.Content = "Other peer finished sieving!";
530                }, null);
531                otherPeerFinished = true;
532                return false;
533            }
534            finally
535            {
536                stopThreads();
537            }
538            return true;
539        }
540
541        /// <summary>
542        /// Manages the whole relation packages that are created during the sieving process by the other threads (and other peers).
543        /// Returns true, if enough relations have been found.
544        /// </summary>
545        private void manageRelationPackages(IntPtr conf, int max_relations)
546        {
547            MethodInfo serializeRelationPackage = msieve.GetMethod("serializeRelationPackage");
548            MethodInfo deserializeRelationPackage = msieve.GetMethod("deserializeRelationPackage");
549            MethodInfo getNumRelations = msieve.GetMethod("getNumRelations");
550            int num_relations = (int)getNumRelations.Invoke(null, new object[] { conf });
551            int start_relations = num_relations;
552            DateTime start_sieving_time = DateTime.Now;
553            MethodInfo saveRelationPackage = msieve.GetMethod("saveRelationPackage");
554
555            while (num_relations < max_relations)
556            {
557                double progress = (double)num_relations / max_relations * 0.8 + 0.1;
558                ProgressChanged(progress, 1.0);               
559               
560                newRelationPackageEvent.WaitOne();               //wait until there is a new relation package in the queue
561                if (userStopped)
562                    return;
563
564                while (relationPackageQueue.Count != 0)       //get all the results from the helper threads, and store them
565                {
566                    IntPtr relationPackage = (IntPtr)relationPackageQueue.Dequeue();
567
568                    if (settings.UsePeer2Peer)
569                    {
570                        byte[] serializedRelationPackage = (byte[])serializeRelationPackage.Invoke(null, new object[] { relationPackage });
571                        peerToPeer.Put(serializedRelationPackage);
572                    }
573
574                    saveRelationPackage.Invoke(null, new object[] { conf, relationPackage });
575                }
576
577                if (usePeer2Peer)
578                {
579                    Queue dhtqueue = peerToPeer.GetLoadedRelationPackagesQueue();
580                    while (dhtqueue.Count != 0)       //get all the loaded results from the DHT, and store them
581                    {
582                        byte[] relationPackage = (byte[])dhtqueue.Dequeue();
583                        IntPtr deserializedRelationPackage = (IntPtr)deserializeRelationPackage.Invoke(null, new object[] { relationPackage });
584                        saveRelationPackage.Invoke(null, new object[] { conf, deserializedRelationPackage });
585                    }
586                }
587
588                num_relations = (int)getNumRelations.Invoke(null, new object[] { conf });
589                showProgressPresentation(max_relations, num_relations, start_relations, start_sieving_time);
590
591                if (usePeer2Peer && !peerToPeer.SyncFactorManager(factorManager))   //another peer already finished sieving
592                {
593                    throw new AlreadySievedException();
594                }
595            }           
596        }
597
598        private void showProgressPresentation(int max_relations, int num_relations, int start_relations, DateTime start_sieving_time)
599        {           
600            String logging_message = "Found " + num_relations + " of " + max_relations + " relations!";
601            double msleft = 0;
602
603            //calculate global performance in relations per ms:
604            double globalPerformance = 0;
605            foreach (double r in relationsPerMS)
606                globalPerformance += r;
607            if (usePeer2Peer)
608                globalPerformance += peerToPeer.GetP2PPerformance();
609
610            //Calculate the total time assuming that we can sieve 1 minute with the same performance:
611            double relationsCalculatableIn1Minute = 1000 * 60 * 1 * globalPerformance;
612            if (relationsCalculatableIn1Minute <= max_relations)
613            {
614                double p = ApproximatedPolynom(relationsCalculatableIn1Minute / max_relations);
615                double estimatedTotalTime = 1000 * 60 * 1 / p;
616
617                //Calculate the elapsed time assuming that we sieved with the same performance the whole time:
618                p = ApproximatedPolynom((double)num_relations / max_relations);
619                double estimatedElapsedTime = estimatedTotalTime * p;
620
621                //Calculate time left:
622                msleft = estimatedTotalTime - estimatedElapsedTime;
623            }           
624           
625            String timeLeft_message = "very soon";
626            String endtime_message = "very soon";
627            if (msleft > 0 && !double.IsInfinity(msleft))
628            {
629                TimeSpan ts = new TimeSpan(0, 0, 0, 0, (int)msleft);
630                timeLeft_message = showTimeSpan(ts) + " left";
631                endtime_message = "" + DateTime.Now.AddMilliseconds((long)msleft);
632            }
633
634            if (globalPerformance == 0 || double.IsInfinity(msleft))
635            {
636                timeLeft_message = "?";
637                endtime_message = "?";
638            }
639
640            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
641            {
642                quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
643                quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
644                quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
645            }, null);
646
647            if (useGnuplot)
648            {
649                double percentage = (double)num_relations / max_relations;
650                double time = (DateTime.Now - start_sieving_time).TotalSeconds;
651                gnuplotFile.WriteLine("" + time + "\t\t" + percentage);
652            }
653        }
654
655        private static double ApproximatedPolynom(double x)
656        {
657            double a = -3.55504;
658            double b = 8.62296;
659            double c = -7.75103;
660            double d = 3.65871;
661            double progress = a * x * x * x * x + b * x * x * x + c * x * x + d * x;
662            return progress;
663        }
664
665        /// <summary>
666        /// This callback method is called by msieve. "list" is the trivial factor list (i.e. it consists of the factors that have been found without
667        /// using the quadratic sieve algorithm).
668        /// The method then factors all the factors that are still composite by using the quadratic sieve.
669        /// </summary>
670        private void putTrivialFactorlist(IntPtr list, IntPtr obj)
671        {
672            if (userStopped)
673                return;
674
675            //add the trivial factors to the factor list:
676            factorManager.AddFactors(list);
677
678            if (usePeer2Peer)
679                peerToPeer.SyncFactorManager(factorManager);
680           
681            MethodInfo msieve_run_core = msieve.GetMethod("msieve_run_core");
682
683            try
684            {
685                //Now factorize as often as needed:
686                while (!factorManager.OnlyPrimes())
687                {
688                    //get one composite factor, which we want to sieve now:
689                    BigInteger compositeFactor = factorManager.GetCompositeFactor();
690                    showFactorInformations(compositeFactor);
691                    if (settings.UsePeer2Peer)
692                        peerToPeer.SetFactor(compositeFactor);
693
694                    //now start quadratic sieve on it:               
695                    IntPtr resultList = (IntPtr)msieve_run_core.Invoke(null, new object[2] { obj, compositeFactor.ToString() });
696                    if (otherPeerFinished)
697                    {
698                        otherPeerFinished = false;
699                        continue;
700                    }
701
702                    if (resultList == IntPtr.Zero)
703                        throw new NotSievableException();
704
705                    if (userStopped)
706                        return;
707
708                    factorManager.ReplaceCompositeByFactors(compositeFactor, resultList);   //add the result list to factorManager
709
710                    if (usePeer2Peer)
711                        peerToPeer.SyncFactorManager(factorManager);
712                }
713            }
714            catch (NotSievableException)
715            {
716                GuiLogMessage("This number is not sievable by msieve (maybe input too long?)", NotificationLevel.Error);
717            }
718        }
719
720        private void showFactorInformations(BigInteger compositeFactor)
721        {
722            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
723            {
724                String compRep;
725                if (compositeFactor.ToString().Length < 6)
726                    compRep = compositeFactor.ToString();
727                else
728                    compRep = compositeFactor.ToString().Substring(0, 4) + "...";
729                quadraticSieveQuickWatchPresentation.factorInfo.Content = "Now sieving first composite factor! (" + compRep + ")";
730            }, null);
731        }
732
733        /// <summary>
734        /// Helper Thread for msieve, which sieves for relations:
735        /// </summary>
736        /// <param name="param">params</param>
737        private void MSieveJob(object param)
738        {
739            threadcount++;
740            object[] parameters = (object[])param;
741            IntPtr clone = (IntPtr)parameters[0];
742            int update = (int)parameters[1];
743            IntPtr core_sieve_fcn = (IntPtr)parameters[2];
744            Queue relationPackageQueue = (Queue)parameters[3];
745            int threadNR = (int)parameters[4];
746
747            try
748            {
749                MethodInfo collectRelations = msieve.GetMethod("collectRelations");
750                MethodInfo getRelationPackage = msieve.GetMethod("getRelationPackage");
751                MethodInfo getAmountOfRelationsInRelationPackage = msieve.GetMethod("getAmountOfRelationsInRelationPackage");
752
753                Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
754
755                while (running)
756                {
757                    try
758                    {
759                        //Calculate the performance of this thread:
760                        DateTime beginning = DateTime.Now;
761                        collectRelations.Invoke(null, new object[] { clone, update, core_sieve_fcn });
762                        IntPtr relationPackage = (IntPtr)getRelationPackage.Invoke(null, new object[] { clone });
763
764                        int amountOfFullRelations = (int)getAmountOfRelationsInRelationPackage.Invoke(null, new object[] { relationPackage });
765                        relationsPerMS[threadNR] = amountOfFullRelations / (DateTime.Now - beginning).TotalMilliseconds;
766
767                        if (usePeer2Peer)
768                            peerToPeer.SetOurPerformance(relationsPerMS);
769
770                        relationPackageQueue.Enqueue(relationPackage);
771                        newRelationPackageEvent.Set();
772                    }
773                    catch (Exception ex)
774                    {
775                        GuiLogMessage("Error using msieve." + ex.Message, NotificationLevel.Error);
776                        threadcount = 0;
777                        return;
778                    }
779                }
780
781                conf_listMutex.WaitOne();
782                if (conf_list != null)
783                    conf_list[threadNR] = null;
784                MethodInfo freeSieveConf = msieve.GetMethod("freeSieveConf");
785                freeSieveConf.Invoke(null, new object[] { clone });
786                conf_listMutex.ReleaseMutex();
787            }
788            finally
789            {
790                threadcount--;
791            }
792        }       
793
794        /// <summary>
795        /// Stop all running threads
796        /// </summary>
797        private void stopThreads()
798        {
799            if (settings.UsePeer2Peer)
800                peerToPeer.StopLoadStoreThread();
801
802            if (conf_list != null)
803            {
804                MethodInfo stop = msieve.GetMethod("stop");
805                MethodInfo getObjFromConf = msieve.GetMethod("getObjFromConf");
806
807                conf_listMutex.WaitOne();
808                foreach (Object conf in conf_list)
809                    if (conf != null)
810                        stop.Invoke(null, new object[] { getObjFromConf.Invoke(null, new object[] { (IntPtr)conf }) });
811               
812                running = false;
813
814                conf_list = null;
815                conf_listMutex.ReleaseMutex();
816
817                GuiLogMessage("Waiting for threads to stop!", NotificationLevel.Debug);
818                while (threadcount > 0)
819                {
820                    Thread.Sleep(0);
821                }
822                GuiLogMessage("Threads stopped!", NotificationLevel.Debug);
823            }
824        }   
825
826        /// <summary>
827        /// Change the progress of this plugin
828        /// </summary>
829        /// <param name="value">value</param>
830        /// <param name="max">max</param>
831        private void ProgressChanged(double value, double max)
832        {
833            EventsHelper.ProgressChanged(OnPluginProgressChanged, this, new PluginProgressEventArgs(value, max));
834            peerToPeerStatusUpdater.UpdateStatus(value/max);
835        }
836
837        private void FactorsChanged(List<BigInteger> primeFactors, List<BigInteger> compositeFactors)
838        {
839            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
840            {
841                quadraticSieveQuickWatchPresentation.factorList.Items.Clear();
842
843                foreach (BigInteger pf in primeFactors)         
844                    quadraticSieveQuickWatchPresentation.factorList.Items.Add("Prime Factor: " + pf.ToString());           
845
846                foreach (BigInteger cf in compositeFactors)
847                    quadraticSieveQuickWatchPresentation.factorList.Items.Add("Composite Factor: " + cf.ToString());
848            }, null);
849        }
850
851        /// <summary>
852        /// Getter / Setter for the QuickWatchPresentation
853        /// </summary>
854        private QuadraticSievePresentation quadraticSieveQuickWatchPresentation
855        {
856            get { return QuickWatchPresentation as QuadraticSievePresentation; }
857        }
858
859        /// <summary>
860        /// dynamically loads the msieve dll file and sets the callbacks
861        /// </summary>
862        private void initMsieveDLL()
863        {
864            msieveDLL = Msieve.GetMsieveDLL();
865            msieve = msieveDLL.GetType("Msieve.msieve");
866
867            //init msieve with callbacks:
868            MethodInfo initMsieve = msieve.GetMethod("initMsieve");
869            Object callback_struct = Activator.CreateInstance(msieveDLL.GetType("Msieve.callback_struct"));           
870            FieldInfo prepareSievingField = msieveDLL.GetType("Msieve.callback_struct").GetField("prepareSieving");
871            FieldInfo putTrivialFactorlistField = msieveDLL.GetType("Msieve.callback_struct").GetField("putTrivialFactorlist");           
872            Delegate prepareSievingDel = MulticastDelegate.CreateDelegate(msieveDLL.GetType("Msieve.prepareSievingDelegate"), this, "prepareSieving");
873            Delegate putTrivialFactorlistDel = MulticastDelegate.CreateDelegate(msieveDLL.GetType("Msieve.putTrivialFactorlistDelegate"), this, "putTrivialFactorlist");           
874            prepareSievingField.SetValue(callback_struct, prepareSievingDel);
875            putTrivialFactorlistField.SetValue(callback_struct, putTrivialFactorlistDel);
876            initMsieve.Invoke(null, new object[1] { callback_struct });
877        }
878
879        private void peerToPeer_P2PWarning(string warning)
880        {
881            GuiLogMessage(warning, NotificationLevel.Warning);
882        }
883
884        #endregion
885
886        #region internal
887
888        internal PeerToPeer PeerToPeer
889        {
890            get { return peerToPeer; }
891        }
892
893        internal bool Running
894        {
895            get { return running; }
896        }
897
898        /// <summary>
899        /// Logs a message to the CrypTool gui
900        /// </summary>
901        /// <param name="p">p</param>
902        /// <param name="notificationLevel">notificationLevel</param>
903        internal void GuiLogMessage(string p, NotificationLevel notificationLevel)
904        {
905            EventsHelper.GuiLogMessage(OnGuiLogNotificationOccured, this, new GuiLogEventArgs(p, this, notificationLevel));
906        }
907
908        #endregion
909
910    }
911}
Note: See TracBrowser for help on using the repository browser.