1/*==============================================================================
  2| 
  3|  NAME     
  4|
  5|     ppFactor.hpp
  6|
  7|  DESCRIPTION   
  8|
  9|     Header for integer factoring classes.
 10|
 11|     User manual and technical documentation are described in detail in my web page at
 12|     http://seanerikoconnor.freeservers.com/Mathematics/AbstractAlgebra/PrimitivePolynomials/overview.html
 13|
 14|  LEGAL
 15|
 16|     Primpoly Version 16.3 - A Program for Computing Primitive Polynomials.
 17|     Copyright (C) 1999-2024 by Sean Erik O'Connor.  All Rights Reserved.
 18|
 19|     This program is free software: you can redistribute it and/or modify
 20|     it under the terms of the GNU General Public License as published by
 21|     the Free Software Foundation, either version 3 of the License, or
 22|     (at your option) any later version.
 23|
 24|     This program is distributed in the hope that it will be useful,
 25|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 26|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 27|     GNU General Public License for more details.
 28|
 29|     You should have received a copy of the GNU General Public License
 30|     along with this program.  If not, see http://www.gnu.org/licenses/.
 31|     
 32|     The author's address is seanerikoconnor!AT!gmail!DOT!com
 33|     with the !DOT! replaced by . and the !AT! replaced by @
 34|
 35==============================================================================*/
 36
 37// Wrap this header file to prevent duplication if it is included
 38// accidentally more than once.
 39#ifndef __PPFACTOR_H__
 40#define __PPFACTOR_H__
 41
 42
 43/*=============================================================================
 44|
 45| NAME
 46|
 47|     FactorError           General factor error, including internal memory errors.
 48|     FactorRangeError      Input range error.
 49|
 50| DESCRIPTION
 51|
 52|     Exception classes for the Factor class
 53|     derived from the STL exception class runtime_error.
 54|
 55+============================================================================*/
 56
 57class FactorError : public runtime_error
 58{
 59    public:
 60        // Throw with error message, file name and line number.
 61         FactorError( const string & description, const string & file, const int & line )
 62         : runtime_error( description + " in file " + file + " at line " + to_string(line) )
 63         {
 64         } ;
 65
 66        // Throw with an error message.
 67        FactorError( const string & description )
 68			: runtime_error( description )
 69        {
 70        } ;
 71
 72        // Default throw with no error message.
 73        FactorError()
 74			: runtime_error( "Factor error:  " )
 75        {
 76        } ;
 77
 78} ; // end class BigIntMathError
 79
 80
 81class FactorRangeError : public FactorError
 82{
 83    public:
 84        // Throw with error message, file name and line number.
 85        FactorRangeError( const string & description, const string & file, const int & line )
 86        : FactorError( description + " in file " + file + " at line " + to_string(line) )
 87        {
 88        };
 89    
 90        // Throw with an error message.
 91        FactorRangeError( const string & description )
 92			: FactorError( description )
 93        {
 94        } ;
 95
 96        // Default throw with no error message.
 97        FactorRangeError()
 98			: FactorError( "Factor range error:  " )
 99        {
100        } ;
101
102} ; // end class FactorRangeError
103
104
105/*=============================================================================
106 |
107 | NAME
108 |
109 |     PrimeFactor
110 |
111 | DESCRIPTION
112 |
113 |     Class to neatly package up unique prime factors to powers.
114 |
115 +============================================================================*/
116
117template <typename IntType>
118class PrimeFactor
119{
120    public:
121        explicit PrimeFactor( IntType prime = static_cast<IntType>( 0u ), int count = 0 )
122            : prime_( prime )
123            , count_( count )
124        {
125        } ;
126
127        ~PrimeFactor()
128        {
129        } ;
130
131        PrimeFactor( const PrimeFactor & factor )
132            : prime_( factor.prime_ )
133            , count_( factor.count_ )
134        {
135        }
136
137        PrimeFactor & operator=( const PrimeFactor & factor )
138        {
139            // Check for assigning to oneself:  just pass back a reference to the unchanged object.
140            if (this == &factor)
141                return *this ;
142
143            prime_ = factor.prime_ ;
144            count_ = factor.count_ ;
145			
146			return *this ;
147        } ;
148    
149        // Print function for a factor.
150        friend ostream & operator<<( ostream & out, const PrimeFactor & factor )
151        {
152            out << factor.prime_ << " ^ " << factor.count_ << " " ;
153        
154            return out ;
155        }
156
157    // Allow direct access to this simple data type for convenience.
158    public:
159        IntType prime_ ;
160        int     count_ ;
161} ;
162
163
164/*=============================================================================
165 |
166 | NAME
167 |
168 |     CompareFactor
169 |
170 | DESCRIPTION
171 |
172 |     Class to sort unique prime factors to powers into order by prime size.
173 |
174 +============================================================================*/
175
176template <typename IntType>
177class CompareFactor
178{
179    public:
180        bool operator()( const PrimeFactor<IntType> & s1, const PrimeFactor<IntType> & s2 )
181        {
182            return s1.prime_ < s2.prime_ ;
183        }
184} ;
185
186
187/*=============================================================================
188 |
189 | NAME
190 |
191 |     Unit
192 |
193 | DESCRIPTION
194 |                                                  0     e
195 |     Class to check for unit factors of the form p  or 1  = 1
196 |
197 +============================================================================*/
198
199template <typename IntType>
200class Unit
201{
202    public:
203        bool operator()( const PrimeFactor<IntType> & s )
204        {
205            return s.count_ == 0u || s.prime_ == static_cast<IntType>( 1u ) ;
206        }
207} ;
208
209
210/*=============================================================================
211|
212| NAME
213|
214|     Factorization
215|
216| DESCRIPTION
217|
218|     Class for single and multiprecision factoring.
219|
220| EXAMPLE
221|
222|     ppuint p{ 2 } ;
223|     ppuint n{ 4 } ;
224|     BigInt p_to_n_minus_1 { power( p, 4 ) - 1 } ;
225|
226|                                       n                                         n
227|     This will give us the factors of p - 1.  We can pass in either p and n or (p  - 1), but p and n might be
228|     the better choice for really large numbers because then we can look up the factorization in a table instead
229|     of computing it.
230|
231|     Factorization<BigInt> factors_of_p_to_n_minus_1( p_to_n_minus_1, FactoringAlgorithm::Automatic, p, n ) ;
232|
233|     And so will this for a smaller sized integer.
234|
235|     Factorization<ppuint> fact( power( p, 4 ) - 1 ) ;
236|
237|     int numDistinctFactors = fact.num() ;
238|     for (int i = 0 ;  i < numDistinctFactors ;  ++i)
239|     {
240|         BigInt primeFactor  = fact[ i ] ;
241|         int    multiplicity = fact.multiplicity( i ) ;
242|     }
243|
244| NOTES
245|
246|     The member functions and friends are documented in detail ppBigInt.cpp
247|
248+============================================================================*/
249
250// Different flavors of factoring algorithm.
251enum class FactoringAlgorithm
252{ 
253    Automatic,
254    TrialDivisionAlgorithm,
255    pollardRhoAlgorithm,
256    FactorTable
257} ;
258
259
260// We need both single precision and multi-precision factoring, so use
261// a template with an integer type.
262template <typename IntType>
263class Factorization
264{
265    public:
266		// Factor n into distinct primes.  Default constructor factors nothing.
267        Factorization( const IntType num = static_cast<IntType>( 1u ),
268                       FactoringAlgorithm type = FactoringAlgorithm::Automatic, ppuint p = 0, ppuint m = 0 ) ;
269
270       ~Factorization() ;
271	   
272        // Copy constructor.
273        Factorization( const Factorization<IntType> & f ) ;
274		
275        // Assignment operator.
276        Factorization<IntType> & operator=( const Factorization<IntType> & g ) ;
277
278	    // Return the number of distinct factors.
279		ppuint numDistinctFactors() const ;
280
281        // Return the ith prime factor along with its multiplicity as an lvalue so we can change either.
282		PrimeFactor<IntType> & operator[]( int i ) ;
283    
284        // Return the ith prime factor.
285        IntType primeFactor( int i ) const ;
286
287        // Return the multiplicity of the ith prime factor.
288        int multiplicity( int i ) const ;
289        
290        // True if p  | (p - 1).
291        //          i
292        bool skipTest( ppuint p, int i ) const ;
293
294        // Factoring with tables.
295        bool factorTable( ppuint p, ppuint n ) ;
296
297        //                                     ---
298        // Factoring by trial division up to \/ n
299        void trialDivision() ;
300
301        // Fast probabilistic factoring method.
302        bool pollardRho( const IntType & c = static_cast<IntType>( 2u )) ;
303
304        // Return a vector of only the distinct prime factors.
305        vector<IntType> getDistinctPrimeFactors() ;
306        
307    // Allow direct access to this simple data type for convenience.
308    public:
309        OperationCount statistics_ ;
310
311    private:
312        // The unfactored remainder.
313        IntType n_ ;
314
315		// Total number of distinct factors.
316		ppuint numFactors_ ;
317
318        // Array of distinct prime factors of n with their multiplicities.
319		vector< PrimeFactor<IntType> > factor_ ;
320
321        // Distinct prime factors.
322        vector<IntType> distinctPrimeFactors_ ;
323} ;
324
325
326/*=============================================================================
327|
328| NAME
329|
330|     Primality
331|
332| DESCRIPTION
333|
334|     What confidence a number is prime?
335|
336+============================================================================*/
337
338enum class Primality
339{
340    Prime = 0,
341    Composite,
342    ProbablyPrime, 
343    Undefined
344
345}  ;
346
347
348/*=============================================================================
349 |
350 | NAME
351 |
352 |     isProbablyPrime
353 |
354 | DESCRIPTION
355 |
356 |     True if n is likely to be prime.  Tests on a random integer x.
357 |
358 +============================================================================*/
359
360template <typename IntType>
361Primality isProbablyPrime( const IntType & n, const IntType & x ) ;
362
363
364/*=============================================================================
365 |
366 | NAME
367 |
368 |     UniformRandomNumber
369 |
370 | DESCRIPTION
371 |
372 |     Return a uniform random integer in [0, range).
373 |
374 | NOTES
375 |
376 |     Use the JKISS random number generator from the article,
377 |         Good Practice in (Pseudo) Random Number Generation for Bioinformatics Applications 
378 |         by David Jones, UCL Bioinformatics Group (E-mail: d.jones@cs.ucl.ac.uk) 
379 |         (Last revised May 7th 2010)
380 |
381 +============================================================================*/
382
383template <typename IntType>
384class UniformRandomIntegers
385{
386    public:
387        // Seed the JKISS generator parameters x, y, z, c, and set up the range of the generator [0, range)
388        explicit UniformRandomIntegers( const IntType range )
389        : range( range )
390        {
391            ++num_of_initializations ;
392            
393            // Reseed at the first call to this class and only occasionally thereafter because it's slow.
394            if (num_of_initializations % how_often_to_reseed == 0)
395            {
396                x = trueRandomNumberFromDevice() ;
397
398                // Seed y must not be zero!
399                while ( !(y = trueRandomNumberFromDevice()) ) ;
400                
401                z = trueRandomNumberFromDevice() ;
402
403                // We don’t really need to set c as well but let's anyway...
404                // NOTE: offset c by 1 to avoid z = c = 0
405                c = trueRandomNumberFromDevice() % JKISS_MAGIC_NUM + 1 ; // Should be less than 698769069
406            }
407         }
408
409        // Destructor has nothing to do.
410        UniformRandomIntegers()
411        {
412        } ;
413
414        IntType rand()
415        {
416            ppuint32 kiss = jKiss() ;
417            
418            // [0, range) falls within our generator's range [0, JKISSMAX).
419            // To preserve a uniform distribution, map numbers in [0, JKISSMAX) down to [0, range) in the following way:
420            // Map [0, range), => [0, range)
421            // Map [range+1, 2 range) => [0, range)
422            // ...
423            // Map [(n-1) range + 1, n range) => [0, range)
424            // Discard numbers in [n range + 1, JKISSMAX) because mapping numbers in this interval < range would inject a non-uniform bias.
425            if (range < IntType( JKISSMAX ))
426            {
427                // It's safe to down convert the integer type.
428                ppuint32 range2{ static_cast<ppuint32>( range ) } ;
429                
430                // Discard the random number unless it falls in a multiple of the range.
431                // Retry with a new random number.  I hope we don't get an infinite loop!
432                ppuint32 within_multiple_of_range{ JKISSMAX - (JKISSMAX % static_cast<ppuint32>(range)) } ;
433                while (kiss > within_multiple_of_range)
434                    kiss = jKiss() ;
435                kiss = jKiss() % range2 ;
436            }
437            // If the range is larger than the maximum of our generator, do nothing.  We don't want to scale up
438            // and have a non-uniform distribution.
439            return static_cast<IntType>( kiss ) ;
440        } ;
441
442        private:
443            static int num_of_initializations ;
444            static const int how_often_to_reseed = 10000 ;
445            static const int JKISS_MAGIC_NUM = 698769068 ;
446    
447            // Default seeds for JKISS.
448            ppuint32 x{ 123456789 } ;
449            ppuint32 y{ 987654321 } ;
450            ppuint32 z{  43219876 } ;
451            ppuint32 c{   6543217 } ;
452
453            // Top end of the jKiss() generator range.
454            const ppuint32 JKISSMAX { numeric_limits<ppuint32>::max() } ;
455    
456            // Return uniform random numbers in the range [0, range).
457            IntType range ;
458
459            // Read from the pseudo device /dev/urandom which return true random integers.
460            unsigned int trueRandomNumberFromDevice()
461            {
462                // The device /dev/urandom only returns bytes, so grab four at a time to make on 32-bit unsigned integer.
463                union RandomDeviceByteToInteger
464                {
465                    ppuint32 integer32 ;
466                    char bytes4[ 4 ] ;
467                } ;
468                
469                RandomDeviceByteToInteger numFromRandomDev ;
470                
471                ifstream fin( "/dev/urandom", ifstream::binary ) ;
472                if (fin.good())
473                {
474                    fin.read( numFromRandomDev.bytes4, 4 ) ;
475                    
476                    if (!fin)
477                    {
478                        ostringstream os ;
479                        os << "Cannot read from random device /dev/urandom" ;
480                        throw FactorError( os.str(), __FILE__, __LINE__ ) ;
481                    }
482                }
483                else
484                {
485                    ostringstream os ;
486                    os << "Cannot open random device /dev/urandom" ;
487                    throw FactorError( os.str(), __FILE__, __LINE__ ) ;
488                }
489
490                return numFromRandomDev.integer32 ;
491            }
492
493            // 32-bit integer random number generator.
494            ppuint32 jKiss()
495            {
496                x = 314527869 * x + 1234567 ;
497
498                y ^= (y <<  5) ;
499                y ^= (y >>  7) ;
500                y ^= (y << 22) ;
501
502                ppuint t{ 4294584393ULL * z + c } ;  // This must be a 64-bit integer type.
503                c = t >> 32 ;
504                z = static_cast<ppuint32>( t ) ;
505
506                return x + y + z ;
507            }
508} ;
509
510
511/*==============================================================================
512|                     Static Class Variables Initialization                    |
513==============================================================================*/
514
515// Static class variables must be initialized outside the class.
516
517template <typename IntType> int UniformRandomIntegers<IntType>::num_of_initializations = 0 ;
518
519
520/*=============================================================================
521|
522| NAME
523|
524|     isAlmostSurelyPrime
525|
526| DESCRIPTION
527|
528|     True if n is probabilistically prime.
529|
530+============================================================================*/
531
532template <typename IntType>
533bool isAlmostSurelyPrime( const IntType & n ) ;
534
535#endif // __PPFACTOR_H__