generate_carmichael_of_second_order_3.pl 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #!/usr/bin/perl
  2. # Erdos construction method for Carmichael numbers:
  3. # 1. Choose an even integer L with many prime factors.
  4. # 2. Let P be the set of primes d+1, where d|L and d+1 does not divide L.
  5. # 3. Find a subset S of P such that prod(S) == 1 (mod L). Then prod(S) is a Carmichael number.
  6. # Alternatively:
  7. # 3. Find a subset S of P such that prod(S) == prod(P) (mod L). Then prod(P) / prod(S) is a Carmichael number.
  8. use 5.020;
  9. use warnings;
  10. use ntheory qw(:all);
  11. use experimental qw(signatures);
  12. use Math::GMPz;
  13. # Modular product of a list of integers
  14. sub vecprodmod ($arr, $mod) {
  15. my $prod = 1;
  16. foreach my $k (@$arr) {
  17. $prod = mulmod($prod, $k, $mod);
  18. }
  19. $prod;
  20. }
  21. #p^2 - 1 | n-1
  22. # Primes p such that p-1 divides L and p does not divide L
  23. sub lambda_primes ($L) {
  24. grep { $L % $_ != 0 } grep { $_ > 2 and is_prime($_) } map { sqrtint($_) } grep { is_square($_) } map { $_ + 1 } divisors($L);
  25. #grep { $L % $_ != 0 } grep { $_ > 2 and is_prime($_) } map { $_ + 1 } divisors($L2);
  26. }
  27. #~ # Primes p such that p-1 divides L and p does not divide L
  28. #~ sub lambda_primes ($L) {
  29. #~ #grep { $L % $_ != 0 } grep { $_ > 2 } map { sqrtint($_) } grep { is_square($_) && is_prime(sqrtint($_)) } map { $_ + 1 } divisors($L);
  30. #~ grep { $L % $_ != 0 } grep { $_ > 2 and is_prime($_) } map { $_ + 1 } divisors($L);
  31. #~ }
  32. #~ sub method_2 ($L) { # largest numbers first
  33. #~ my @P = lambda_primes($L);
  34. #~ my $B = vecprodmod(\@P, $L);
  35. #~ my $T = vecprod(@P);
  36. #~ #say "@P";
  37. #~ foreach my $k (1 .. (@P-3)) {
  38. #~ #say "Testing: $k -- ", binomial(scalar(@P), $k);
  39. #~ my $count = 0;
  40. #~ forcomb {
  41. #~ if (vecprodmod([@P[@_]], $L) == $B) {
  42. #~ my $S = vecprod(@P[@_]);
  43. #~ say ($T / $S) if ($T != $S);
  44. #~ }
  45. #~ lastfor if (++$count > 1e6);
  46. #~ } scalar(@P), $k;
  47. #~ }
  48. #~ }
  49. sub method_1 ($L) { # smallest numbers first
  50. my @P = lambda_primes($L);
  51. @P = grep {$_ >= 17 and $_ <= 1000 } @P;
  52. foreach my $k (3 .. @P) {
  53. say "k = $k";
  54. forcomb {
  55. if (vecprodmod([@P[@_]], $L) == 1) {
  56. say vecprod(@P[@_]);
  57. }
  58. } scalar(@P), $k;
  59. }
  60. }
  61. sub method_2($L, $L2) {
  62. #my @P = grep { ($_ < 5e5) and ($_ >= 3) } lambda_primes($L2);
  63. my @P = grep { ($_ < 1e3) and ($_ >= 17) } lambda_primes($L2);
  64. #say "@P";
  65. return if (vecprod(@P) < ~0);
  66. my $n = scalar(@P);
  67. my @orig = @P;
  68. my $max = 1e5;
  69. my $max_k = 10;
  70. foreach my $k (7 .. @P>>1) {
  71. #next if (binomial($n, $k) > 1e6);
  72. next if ($k > $max_k);
  73. @P = @orig;
  74. my $count = 0;
  75. forcomb {
  76. if (vecprodmod([@P[@_]], $L) == 1) {
  77. say vecprod(@P[@_]);
  78. }
  79. lastfor if (++$count > $max);
  80. } $n, $k;
  81. next if (binomial($n, $k) < $max);
  82. #~ @P = reverse(@P);
  83. #~ $count = 0;
  84. #~ forcomb {
  85. #~ if (vecprodmod([@P[@_]], $L) == 1) {
  86. #~ say vecprod(@P[@_]);
  87. #~ }
  88. #~ lastfor if (++$count > $max);
  89. #~ } $n, $k;
  90. @P = shuffle(@P);
  91. $count = 0;
  92. forcomb {
  93. if (vecprodmod([@P[@_]], $L) == 1) {
  94. say vecprod(@P[@_]);
  95. }
  96. lastfor if (++$count > $max);
  97. } $n, $k;
  98. }
  99. my $B = vecprodmod(\@P, $L);
  100. my $T = Math::GMPz->new(vecprod(@P));
  101. foreach my $k (1 .. @P>>1) {
  102. #next if (binomial($n, $k) > 1e6);
  103. last if ($k > $max_k);
  104. @P = @orig;
  105. my $count = 0;
  106. forcomb {
  107. if (vecprodmod([@P[@_]], $L) == $B) {
  108. my $S = vecprod(@P[@_]);
  109. say ($T / $S) if ($T != $S);
  110. }
  111. lastfor if (++$count > $max);
  112. } $n, $k;
  113. next if (binomial($n, $k) < $max);
  114. #~ @P = reverse(@P);
  115. #~ $count = 0;
  116. #~ forcomb {
  117. #~ if (vecprodmod([@P[@_]], $L) == $B) {
  118. #~ my $S = vecprod(@P[@_]);
  119. #~ say ($T / $S) if ($T != $S);
  120. #~ }
  121. #~ lastfor if (++$count > $max);
  122. #~ } $n, $k;
  123. @P = shuffle(@P);
  124. $count = 0;
  125. forcomb {
  126. if (vecprodmod([@P[@_]], $L) == $B) {
  127. my $S = vecprod(@P[@_]);
  128. say ($T / $S) if ($T != $S);
  129. }
  130. lastfor if (++$count > $max);
  131. } $n, $k;
  132. }
  133. }
  134. #method_1(720);
  135. #method_2(720);
  136. foreach my $L(
  137. #60720, 221760, 831600, 2489760, 3067680, 3160080, 5544000, 15477000, 38427480, 64162560, 74646000, 79944480, 96238800, 149385600, 212186520, 273873600, 357033600, 910435680, 3749786040, 5069705760
  138. #221760, 2489760, 3067680, 64162560, 149385600
  139. #128842560, 137491200, 298771200, 766846080, 5004679680
  140. #4007520, 128842560, 137491200, 155232000, 278586000, 298771200, 547747200, 766846080, 848746080, 1690809120, 1820871360, 2090088000, 5004679680, 5756002560, 6035752800, 6857373600, 62747697600, 67496148720, 1298888236800, 1449935847360
  141. #1440, 1680, 2016, 5040, 6720, 10080, 18480, 20160, 95760, 106560, 134640, 142800, 166320, 186480, 191520, 208320, 364320, 376992, 536256, 929880, 1177488, 1484280, 3800160, 4426800, 4553280, 11040960, 16703280, 23173920, 38641680, 46060560, 72913680, 171004680
  142. #276480, 1161216, 2903040, 5806080, 7741440, 42577920, 77552640, 107412480, 245514240, 854945280, 1625702400, 2162184192, 2712932352, 3357573120, 3971358720, 5573836800, 9870336000, 13348177920, 15467397120, 26266705920, 28798156800, 34488115200, 63745920000, 74132029440, 86589803520, 98498695680, 111288038400, 114653822976, 158989824000, 167993118720, 192819916800, 238777943040, 262268928000
  143. #128842560, 137491200, 155232000, 298771200, 547747200, 766846080, 848746080, 1690809120, 5004679680, 6857373600
  144. #50227322745600
  145. #59192848915200
  146. #24404583472315200
  147. #3286483200
  148. #[821620800, 3286483200]
  149. [221760, 137491200], [2489760, 766846080], [3067680, 128842560], [64162560, 5004679680], [149385600, 298771200],
  150. #[60720, 4007520], [221760, 137491200], [831600, 6035752800], [2489760, 766846080], [3067680, 128842560], [3160080, 6857373600], [5544000, 155232000], [15477000, 278586000], [38427480, 1690809120], [64162560, 5004679680], [74646000, 2090088000], [79944480, 5756002560], [96238800, 62747697600], [149385600, 298771200], [212186520, 848746080], [273873600, 547747200], [357033600, 1298888236800], [910435680, 1820871360], [3749786040, 67496148720], [5069705760, 1449935847360],
  151. #[36, 5040], [36, 95760], [48, 2016], [60, 6720], [60, 208320], [72, 186480], [80, 1440], [108, 166320], [112, 10080], [112, 191520], [120, 1680], [180, 1484280], [198, 134640], [216, 16703280], [240, 20160], [288, 536256], [300, 142800], [360, 106560], [360, 46060560], [420, 11040960], [504, 186480], [528, 376992], [540, 4553280], [600, 4426800], [720, 23173920], [1224, 1177488], [1320, 18480], [1980, 171004680], [2024, 364320], [2268, 929880], [2320, 3800160], [6120, 72913680], [8568, 38641680]
  152. ) {
  153. #foreach my $k(2..100) {
  154. method_2($L->[0], $L->[1]);
  155. #}
  156. #method_1($L);
  157. }