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

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

quadratic sieve terminology change:
"yield" is called "relation package" now.

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