Skip to content

Commit e9b8b13

Browse files
raklaptudirmgithub-actionsappgurueu
authored
merge: Implement Shor's factorization algorithm (#1070)
* Updated Documentation in README.md * merge: Fix GetEuclidGCD (#1068) (#1069) * Fix GetEuclidGCD Implement the actual Euclidean Algorithm * Replace == with === * Lua > JS * Standard sucks * Oops * Update GetEuclidGCD.js * Updated Documentation in README.md Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> * feat: implement Shor's Algorithm * chore: add tests * Updated Documentation in README.md * chore: fix spelling Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com>
1 parent 4b07e8a commit e9b8b13

File tree

3 files changed

+128
-0
lines changed

3 files changed

+128
-0
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@
195195
* [RadianToDegree](Maths/RadianToDegree.js)
196196
* [ReverseNumber](Maths/ReverseNumber.js)
197197
* [ReversePolishNotation](Maths/ReversePolishNotation.js)
198+
* [ShorsAlgorithm](Maths/ShorsAlgorithm.js)
198199
* [SieveOfEratosthenes](Maths/SieveOfEratosthenes.js)
199200
* [SimpsonIntegration](Maths/SimpsonIntegration.js)
200201
* [Softmax](Maths/Softmax.js)

Maths/ShorsAlgorithm.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* @function ShorsAlgorithm
3+
* @description Classical implementation of Shor's Algorithm.
4+
* @param {Integer} num - Find a non-trivial factor of this number.
5+
* @returns {Integer} - A non-trivial factor of num.
6+
* @see https://en.wikipedia.org/wiki/Shor%27s_algorithm
7+
* @see https://www.youtube.com/watch?v=lvTqbM5Dq4Q
8+
*
9+
* Shor's algorithm is a quantum algorithm for integer factorization. This
10+
* function implements a version of the algorithm which is computable using
11+
* a classical computer, but is not as efficient as the quantum algorithm.
12+
*
13+
* The algorithm basically consists of guessing a number g which may share
14+
* factors with our target number N, and then use Euclid's GCD algorithm to
15+
* find the common factor.
16+
*
17+
* The algorithm starts with a random guess for g, and then improves the
18+
* guess by using the fact that for two coprimes A and B, A^p = mB + 1.
19+
* For our purposes, this means that g^p = mN + 1. This mathematical
20+
* identity can be rearranged into (g^(p/2) + 1)(g^(p/2) - 1) = mN.
21+
* Provided that p/2 is an integer, and neither g^(p/2) + 1 nor g^(p/2) - 1
22+
* are a multiple of N, either g^(p/2) + 1 or g^(p/2) - 1 must share a
23+
* factor with N, which can then be found using Euclid's GCD algorithm.
24+
*/
25+
function ShorsAlgorithm (num) {
26+
const N = BigInt(num)
27+
28+
while (true) {
29+
// generate random g such that 1 < g < N
30+
const g = BigInt(Math.floor(Math.random() * (num - 1)) + 2)
31+
32+
// check if g shares a factor with N
33+
// if it does, find and return the factor
34+
let K = gcd(g, N)
35+
if (K !== 1) return K
36+
37+
// find p such that g^p = mN + 1
38+
const p = findP(g, N)
39+
40+
// p needs to be even for it's half to be an integer
41+
if (p % 2n === 1n) continue
42+
43+
const base = g ** (p / 2n) // g^(p/2)
44+
const upper = base + 1n // g^(p/2) + 1
45+
const lower = base - 1n // g^(p/2) - 1
46+
47+
// upper and lower can't be a multiple of N
48+
if (upper % N === 0n || lower % N === 0n) continue
49+
50+
// either upper or lower must share a factor with N
51+
K = gcd(upper, N)
52+
if (K !== 1) return K // upper shares a factor
53+
return gcd(lower, N) // otherwise lower shares a factor
54+
}
55+
}
56+
57+
/**
58+
* @function findP
59+
* @description Finds a value p such that A^p = mB + 1.
60+
* @param {BigInt} A
61+
* @param {BigInt} B
62+
* @returns The value p.
63+
*/
64+
function findP (A, B) {
65+
let p = 1n
66+
while (!isValidP(A, B, p)) p++
67+
return p
68+
}
69+
70+
/**
71+
* @function isValidP
72+
* @description Checks if A, B, and p fulfill A^p = mB + 1.
73+
* @param {BigInt} A
74+
* @param {BigInt} B
75+
* @param {BigInt} p
76+
* @returns Whether A, B, and p fulfill A^p = mB + 1.
77+
*/
78+
function isValidP (A, B, p) {
79+
// A^p = mB + 1 => A^p - 1 = 0 (mod B)
80+
return (A ** p - 1n) % B === 0n
81+
}
82+
83+
/**
84+
* @function gcd
85+
* @description Euclid's GCD algorithm.
86+
* @param {BigInt} A
87+
* @param {BigInt} B
88+
* @returns Greatest Common Divisor between A and B.
89+
*/
90+
function gcd (A, B) {
91+
while (B !== 0n) {
92+
[A, B] = [B, A % B]
93+
}
94+
95+
return Number(A)
96+
}
97+
98+
export { ShorsAlgorithm }

Maths/test/ShorsAlgorithm.test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { ShorsAlgorithm } from '../ShorsAlgorithm'
2+
import { fermatPrimeCheck } from '../FermatPrimalityTest'
3+
4+
describe("Shor's Algorithm", () => {
5+
const N = 10 // number of tests
6+
const max = 35000 // max value to factorize
7+
const min = 1000 // min value to factorize
8+
9+
for (let i = 0; i < N; i++) {
10+
while (true) {
11+
const num = Math.floor(Math.random() * max) + min
12+
// num must be composite, don't care for false negatives
13+
if (fermatPrimeCheck(num, 1)) continue
14+
15+
it('should find a non-trivial factor of ' + num, () => {
16+
const f = ShorsAlgorithm(num)
17+
18+
// should not be trivial
19+
expect(f).not.toEqual(1)
20+
expect(f).not.toEqual(num)
21+
22+
// should be a factor
23+
expect(num % f).toEqual(0)
24+
})
25+
26+
break
27+
}
28+
}
29+
})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy