Skip to content

Commit e9b8b13

Browse files
raklaptudirmgithub-actionsappgurueu
authored
merge: Implement Shor's factorization algorithm (TheAlgorithms#1070)
* Updated Documentation in README.md * merge: Fix GetEuclidGCD (TheAlgorithms#1068) (TheAlgorithms#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 <[email protected]> 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 <[email protected]>
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+
functionShorsAlgorithm(num){
26+
constN=BigInt(num)
27+
28+
while(true){
29+
// generate random g such that 1 < g < N
30+
constg=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+
letK=gcd(g,N)
35+
if(K!==1)returnK
36+
37+
// find p such that g^p = mN + 1
38+
constp=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+
constbase=g**(p/2n)// g^(p/2)
44+
constupper=base+1n// g^(p/2) + 1
45+
constlower=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)returnK// upper shares a factor
53+
returngcd(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+
functionfindP(A,B){
65+
letp=1n
66+
while(!isValidP(A,B,p))p++
67+
returnp
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+
functionisValidP(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+
functiongcd(A,B){
91+
while(B!==0n){
92+
[A,B]=[B,A%B]
93+
}
94+
95+
returnNumber(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+
constN=10// number of tests
6+
constmax=35000// max value to factorize
7+
constmin=1000// min value to factorize
8+
9+
for(leti=0;i<N;i++){
10+
while(true){
11+
constnum=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+
constf=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)