Advanced.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. <?php
  2. namespace MathPHP\Sequence;
  3. use MathPHP\Exception\OutOfBoundsException;
  4. use MathPHP\NumberTheory\Integer;
  5. /**
  6. * Advanced integer sequences
  7. * - Fibonacci
  8. * - Lucas numbers
  9. * - Pell numbers
  10. * - Triangular numbers
  11. * - Pentagonal numbers
  12. * - Hexagonal numbers
  13. * - Heptagonal numbers
  14. * - Look-and-say sequence
  15. * - Lazy caterer's sequence
  16. * - Magic squares sequence
  17. * - Perfect powers
  18. * - Not perfect powers
  19. *
  20. * All sequences return an array of numbers in the sequence.
  21. * The array index starting point depends on the sequence type.
  22. */
  23. class Advanced
  24. {
  25. /**
  26. * Fibonacci numbers
  27. * Every number is the sum of the two preceding ones.
  28. * https://en.wikipedia.org/wiki/Fibonacci_number
  29. *
  30. * F₀ = 0
  31. * F₁ = 1
  32. * Fᵢ = Fᵢ₋₁ + Fᵢ₋₂
  33. *
  34. * Example:
  35. * n = 6
  36. * Sequence: 0, 1, 1, 2, 3, 5
  37. * Array index: 0, 1, 2, 3, 4, 5
  38. *
  39. * @param int $n How many numbers in the sequence
  40. *
  41. * @return array<int> Indexed from 0
  42. */
  43. public static function fibonacci(int $n): array
  44. {
  45. $fibonacci = [];
  46. // Bad input; return empty list
  47. if ($n <= 0) {
  48. return $fibonacci;
  49. }
  50. // Base case (n = 1): F₀ = 0
  51. $fibonacci[] = 0;
  52. if ($n === 1) {
  53. return $fibonacci;
  54. }
  55. // Base case (n = 2): F₀ = 0, F₁ = 1
  56. $fibonacci[] = 1;
  57. if ($n === 2) {
  58. return $fibonacci;
  59. }
  60. // Standard iterative case (n > 1): Fᵢ = Fᵢ₋₁ + Fᵢ₋₂
  61. for ($i = 2; $i < $n; $i++) {
  62. $fibonacci[] = $fibonacci[$i - 1] + $fibonacci[$i - 2];
  63. }
  64. return $fibonacci;
  65. }
  66. /**
  67. * Lucas numbers
  68. * Every number is the sum of its two immediate previous terms.
  69. * Similar to Fibonacci numbers except the base cases differ.
  70. * https://en.wikipedia.org/wiki/Lucas_number
  71. *
  72. * L₀ = 2
  73. * L₁ = 1
  74. * Lᵢ = Lᵢ₋₁ + Lᵢ₋₂
  75. *
  76. * Example:
  77. * n = 6
  78. * Sequence: 2, 1, 3, 4, 7, 11
  79. * Array index: 0, 1, 2, 3, 4, 5
  80. *
  81. * @param int $n How many numbers in the sequence
  82. *
  83. * @return array<int> Indexed from 0
  84. */
  85. public static function lucasNumber(int $n): array
  86. {
  87. $lucas = [];
  88. // Bad input; return empty list
  89. if ($n <= 0) {
  90. return $lucas;
  91. }
  92. // Base case (n = 1): L₀ = 2
  93. $lucas[] = 2;
  94. if ($n === 1) {
  95. return $lucas;
  96. }
  97. // Base case (n = 2): , L₀ = 2L₁ = 1
  98. $lucas[] = 1;
  99. if ($n === 2) {
  100. return $lucas;
  101. }
  102. // Standard iterative case: Lᵢ = Lᵢ₋₁ + Lᵢ₋₂
  103. for ($i = 2; $i < $n; $i++) {
  104. $lucas[$i] = $lucas[$i - 1] + $lucas[$i - 2];
  105. }
  106. return $lucas;
  107. }
  108. /**
  109. * Pell numbers
  110. * The denominators of the closest rational approximations to the square root of 2.
  111. * https://en.wikipedia.org/wiki/Pell_number
  112. *
  113. * P₀ = 0
  114. * P₁ = 1
  115. * Pᵢ = 2Pᵢ₋₁ + Pᵢ₋₂
  116. *
  117. * Example:
  118. * n = 6
  119. * Sequence: 0, 1, 2, 5, 12, 29
  120. * Array index: 0, 1, 2, 3, 4, 5
  121. *
  122. * @param int $n How many numbers in the sequence
  123. *
  124. * @return array<int> Indexed from 0
  125. */
  126. public static function pellNumber(int $n): array
  127. {
  128. $pell = [];
  129. // Bad input; return empty list
  130. if ($n <= 0) {
  131. return $pell;
  132. }
  133. // Base case (n = 1): P₀ = 0
  134. $pell[] = 0;
  135. if ($n === 1) {
  136. return $pell;
  137. }
  138. // Base case (n = 2): P₀ = 0, P₁ = 1
  139. $pell[] = 1;
  140. if ($n === 2) {
  141. return $pell;
  142. }
  143. // Standard iterative case: Pᵢ = 2Pᵢ₋₁ + Pᵢ₋₂
  144. for ($i = 2; $i < $n; $i++) {
  145. $pell[$i] = 2 * $pell[$i - 1] + $pell[$i - 2];
  146. }
  147. return $pell;
  148. }
  149. /**
  150. * Triangular numbers
  151. * Figurate numbers that represent equilateral triangles.
  152. * https://en.wikipedia.org/wiki/Triangular_number
  153. *
  154. * n(n + 1)
  155. * Tn = --------
  156. * 2
  157. *
  158. * Example:
  159. * n = 6
  160. * Sequence: 1, 3, 6, 10, 15, 21
  161. * Array index: 1, 2, 3, 4, 5, 6
  162. *
  163. * @param int $n How many numbers in the sequence
  164. *
  165. * @return array<float> Indexed from 1
  166. */
  167. public static function triangularNumber(int $n): array
  168. {
  169. $triangular = [];
  170. // Bad input; return empty list
  171. if ($n <= 0) {
  172. return $triangular;
  173. }
  174. // Standard case for pn: n(n + 1) / 2
  175. for ($i = 1; $i <= $n; $i++) {
  176. $triangular[$i] = ($i * ($i + 1)) / 2;
  177. }
  178. return $triangular;
  179. }
  180. /**
  181. * Pentagonal numbers
  182. * Figurate numbers that represent pentagons.
  183. * https://en.wikipedia.org/wiki/Pentagonal_number
  184. *
  185. * 3n² - n
  186. * pn = -------
  187. * 2
  188. *
  189. * Example:
  190. * n = 6
  191. * Sequence: 1, 5, 12, 22, 35, 51
  192. * Array index: 1, 2, 3, 4, 5, 6
  193. *
  194. * @param int $n How many numbers in the sequence
  195. *
  196. * @return array<float> Indexed from 1
  197. */
  198. public static function pentagonalNumber(int $n): array
  199. {
  200. $pentagonal = [];
  201. // Bad input; return empty list
  202. if ($n <= 0) {
  203. return $pentagonal;
  204. }
  205. // Standard case for pn: (3n² - n) / 2
  206. for ($i = 1; $i <= $n; $i++) {
  207. $pentagonal[$i] = (3 * ($i ** 2) - $i) / 2;
  208. }
  209. return $pentagonal;
  210. }
  211. /**
  212. * Hexagonal numbers
  213. * Figurate numbers that represent hexagons.
  214. * https://en.wikipedia.org/wiki/Hexagonal_number
  215. *
  216. * 2n × (2n - 1)
  217. * hn = -------------
  218. * 2
  219. *
  220. * Example:
  221. * n = 6
  222. * Sequence: 1, 6, 15, 28, 45, 66
  223. * Array index: 1, 2, 3, 4, 5, 6
  224. *
  225. * @param int $n How many numbers in the sequence
  226. *
  227. * @return array<float> Indexed from 1
  228. */
  229. public static function hexagonalNumber(int $n): array
  230. {
  231. $hexagonal = [];
  232. // Bad input; return empty list
  233. if ($n <= 0) {
  234. return $hexagonal;
  235. }
  236. // Standard case for hn: (2n × (2n - 1)) / 2
  237. for ($i = 1; $i <= $n; $i++) {
  238. $hexagonal[$i] = ((2 * $i) * (2 * $i - 1)) / 2;
  239. }
  240. return $hexagonal;
  241. }
  242. /**
  243. * Heptagonal numbers
  244. * Figurate numbers that represent heptagons.
  245. * https://en.wikipedia.org/wiki/Heptagonal_number
  246. *
  247. * 5n² - 3n
  248. * Hn = --------
  249. * 2
  250. *
  251. * Example:
  252. * n = 6
  253. * Sequence: 1, 4, 7, 13, 18, 27
  254. * Array index: 1, 2, 3, 4, 5, 6
  255. *
  256. * @param int $n How many numbers in the sequence
  257. *
  258. * @return array<float> Indexed from 1
  259. */
  260. public static function heptagonalNumber(int $n): array
  261. {
  262. $heptagonal = [];
  263. // Bad input; return empty list
  264. if ($n <= 0) {
  265. return $heptagonal;
  266. }
  267. // Standard case for Hn: (5n² - 3n) / 2
  268. for ($i = 1; $i <= $n; $i++) {
  269. $heptagonal[$i] = ((5 * $i ** 2) - (3 * $i)) / 2;
  270. }
  271. return $heptagonal;
  272. }
  273. /**
  274. * Look-and-say sequence (describe the previous term!)
  275. * (Sequence A005150 in the OEIS)
  276. *
  277. * 1, 11, 21, 1211, 111221, 312211, 13112221, 1113213211, ...
  278. *
  279. * To generate a member of the sequence from the previous member,
  280. * read off the digits of the previous member, counting the number of
  281. * digits in groups of the same digit.
  282. *
  283. * 1 is read off as "one 1" or 11.
  284. * 11 is read off as "two 1s" or 21.
  285. * 21 is read off as "one 2, then one 1" or 1211.
  286. * 1211 is read off as "one 1, one 2, then two 1s" or 111221.
  287. * 111221 is read off as "three 1s, two 2s, then one 1" or 312211.
  288. *
  289. * https://en.wikipedia.org/wiki/Look-and-say_sequence
  290. * https://oeis.org/A005150
  291. *
  292. * Example:
  293. * n = 6
  294. * Sequence: 1, 11, 21, 1211, 111221, 312211
  295. * Array index: 1, 2, 3, 4, 5, 6
  296. *
  297. * @param int $n How many numbers in the sequence
  298. *
  299. * @return array<string> of strings indexed from 1
  300. */
  301. public static function lookAndSay(int $n): array
  302. {
  303. if ($n <= 0) {
  304. return [];
  305. }
  306. // Initialize
  307. $list = [1 => '1'];
  308. $previous = '1';
  309. // Base case
  310. if ($n === 1) {
  311. return $list;
  312. }
  313. for ($i = 2; $i <= $n; $i++) {
  314. $sequence = "";
  315. $count = 1;
  316. $len = \strlen($previous);
  317. for ($j = 1; $j < $len; $j++) {
  318. if (\substr($previous, $j, 1) === \substr($previous, $j - 1, 1)) {
  319. $count++;
  320. } else {
  321. $sequence .= $count . \substr($previous, $j - 1, 1);
  322. $count = 1;
  323. }
  324. }
  325. $sequence .= $count . \substr($previous, $j - 1, 1);
  326. $previous = $sequence;
  327. $list[$i] = $sequence;
  328. }
  329. return $list;
  330. }
  331. /**
  332. * Lazy caterer's sequence (central polygonal numbers)
  333. * Describes the maximum number of pieces of a circle that can be made with
  334. * a given number of straight cuts.
  335. *
  336. * https://en.wikipedia.org/wiki/Lazy_caterer%27s_sequence
  337. * https://oeis.org/A000124
  338. *
  339. * n² + n + 2
  340. * p = ----------
  341. * 2
  342. *
  343. * Using binomial coefficients:
  344. *
  345. * (n + 1) (n) (n) (n)
  346. * p = 1 + ( ) = ( ) + ( ) + ( )
  347. * ( 2 ) (0) (1) (2)
  348. *
  349. * Example:
  350. * n = 6
  351. * Sequence: 1, 2, 4, 7, 11, 16, 22
  352. * Array index: 0, 1, 2, 3, 4, 5, 6
  353. *
  354. * @param int $n How many numbers in the sequence
  355. *
  356. * @return array<float>
  357. */
  358. public static function lazyCaterers(int $n): array
  359. {
  360. if ($n < 0) {
  361. return [];
  362. }
  363. $p = [];
  364. for ($i = 0; $i < $n; $i++) {
  365. $p[] = ($i ** 2 + $i + 2) / 2;
  366. }
  367. return $p;
  368. }
  369. /**
  370. * Magic squares series
  371. * The constant sum in every row, column and diagonal of a magic square is
  372. * called the magic constant or magic sum, M.
  373. *
  374. * https://oeis.org/A006003
  375. * https://edublognss.wordpress.com/2013/04/16/famous-mathematical-sequences-and-series/
  376. *
  377. * n(n² + 1)
  378. * M = ---------
  379. * 2
  380. *
  381. * Example:
  382. * n = 6
  383. * Sequence: 0, 1, 5, 15, 34, 65
  384. * Array index: 0, 1, 2, 3, 4, 5,
  385. *
  386. * @param int $n How many numbers in the sequence
  387. *
  388. * @return array<float>
  389. */
  390. public static function magicSquares(int $n): array
  391. {
  392. if ($n < 0) {
  393. return [];
  394. }
  395. $M = [];
  396. for ($i = 0; $i < $n; $i++) {
  397. $M[] = ($i * ($i ** 2 + 1)) / 2;
  398. }
  399. return $M;
  400. }
  401. private const PERFECT_NUMBERS = [
  402. 6, 28, 496, 8128, 33550336, 8589869056, 137438691328, 2305843008139952128, 2658455991569831744654692615953842176, 191561942608236107294793378084303638130997321548169216
  403. ];
  404. /**
  405. * Perfect numbers
  406. * @see https://oeis.org/A000396
  407. *
  408. * Example
  409. * n = 5
  410. * Sequence: 6, 28, 496, 8128, 33550336
  411. * Array index: 0, 1, 2, 3, 4
  412. *
  413. * @param int $n
  414. *
  415. * @return array<int|float> May return float due to integer precision limitations of large numbers
  416. *
  417. * @throws OutOfBoundsException
  418. */
  419. public static function perfectNumbers(int $n): array
  420. {
  421. if ($n <= 0) {
  422. return [];
  423. }
  424. if ($n <= 10) {
  425. return \array_slice(self::PERFECT_NUMBERS, 0, $n);
  426. }
  427. throw new OutOfBoundsException("Perfect numbers beyond the tenth are too large to compute");
  428. }
  429. /**
  430. * Perfect powers
  431. * https://en.wikipedia.org/wiki/Perfect_power
  432. *
  433. * mᵏ = n where m > 1 and k >= 2.
  434. * Without duplication.
  435. * https://oeis.org/A001597 (similar)
  436. *
  437. * Example:
  438. * n = 6
  439. * Sequence: 4, 8, 9, 16, 25, 27
  440. * Array index: 0, 1, 2, 3, 4, 5
  441. *
  442. * @param int $n How many numbers in the sequence
  443. *
  444. * @return array<int>
  445. */
  446. public static function perfectPowers(int $n): array
  447. {
  448. $pp = [];
  449. if ($n <= 0) {
  450. return $pp;
  451. }
  452. $i = 2;
  453. while ($n > 0) {
  454. if (Integer::isPerfectPower($i)) {
  455. $pp[] = $i;
  456. $n--;
  457. }
  458. $i++;
  459. }
  460. return $pp;
  461. }
  462. /**
  463. * Numbers that are not perfect powers
  464. * https://en.wikipedia.org/wiki/Perfect_power
  465. *
  466. * https://oeis.org/A007916
  467. *
  468. * Example:
  469. * n = 6
  470. * Sequence: 2, 3, 5, 6, 7, 10
  471. * Array index: 0, 1, 2, 3, 4, 5
  472. *
  473. * @param int $n How many numbers in the sequence
  474. *
  475. * @return array<int>
  476. */
  477. public static function notPerfectPowers(int $n): array
  478. {
  479. $npp = [];
  480. if ($n <= 0) {
  481. return $npp;
  482. }
  483. $i = 2;
  484. while ($n > 0) {
  485. if (!Integer::isPerfectPower($i)) {
  486. $npp[] = $i;
  487. $n--;
  488. }
  489. $i++;
  490. }
  491. return $npp;
  492. }
  493. /**
  494. * Prime numbers up to n.
  495. * https://oeis.org/A000040
  496. *
  497. * Algorithm: Sieve of Eratosthenes
  498. * Let A be an array of boolean values, indexed by integers 2 to n, initially all set to true.
  499. * for i = 2, 3, 4, ..., not exceeding √n:
  500. * if A[i] is true:
  501. * for j = i², i²+i, i²+2i, i²+3i, ..., not exceeding n:
  502. * A[j] := false.
  503. *
  504. * Output: all i such that A[i] is true.
  505. *
  506. * https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
  507. *
  508. * Example:
  509. * n = 20
  510. * Sequence: 2, 3, 5, 7, 11, 13, 17, 19
  511. * Array index: 0, 1, 2, 3, 4, 5, 6, 7
  512. *
  513. * @param int $n Prime numbers up to this n
  514. *
  515. * @return array<int>
  516. */
  517. public static function primesUpTo(int $n): array
  518. {
  519. if ($n < 2) {
  520. return [];
  521. }
  522. $primes = \array_fill_keys(\range(2, $n), true);
  523. $√n = \ceil(\sqrt($n));
  524. for ($i = 2; $i <= $√n; $i++) {
  525. if ($primes[$i] === true) {
  526. $i² = $i ** 2;
  527. for ($j = $i²; $j <= $n; $j += $i) {
  528. $primes[$j] = false;
  529. }
  530. }
  531. }
  532. return \array_keys(\array_filter($primes));
  533. }
  534. }