-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathfactoring.qs
140 lines (121 loc) · 4.58 KB
/
factoring.qs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
namespace Factoring {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Math;
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Arithmetic;
open Microsoft.Quantum.Arrays;
open Microsoft.Quantum.Random;
open Microsoft.Quantum.Characterization;
open Microsoft.Quantum.Oracles;
open Microsoft.Quantum.Diagnostics;
@EntryPoint()
operation FactorSemiprimeInteger(number : Int) : (Int, Int)
{
if (number % 2 == 0) {
Message("An even number has been provided, 2 is a factor.");
return (number/2, 2);
}
mutable factors = (1, 1);
mutable foundFactors = false;
repeat {
let a = DrawRandomInt(3, number-1);
if (IsCoprimeI(a, number)){
let r = EstimatePeriod(a, number);
set (foundFactors, factors) = MaybeFactorsFromPeriod(a, r, number);
} else {
let gcd = GreatestCommonDivisorI(a, number);
Message($"We did it by accident, {gcd} is a factor of {number}.");
set foundFactors = true;
set factors = (gcd, number/gcd);
}
} until (foundFactors)
fixup {
Message("Current guess failed, trying again.");
}
return factors;
}
// 3. Use iterative phase estimation to find the frequency of the classical
// function f(x) = ax mod N. The frequency tells you about how quickly f
// returns to the same value as x increases.
// 4. Use a classical algorithm known as the continued fractions expansion to
// convert the frequency from the previous step into a period (r).
// The period r should then have the property that f(x) = f(x + r) for all inputs x.
operation EstimatePeriod(a : Int, number : Int) : Int {
let bitSize = BitSizeI(number);
let nBitsPrecision = 2 * bitSize + 1;
// Values selected below make sure that default conditions for the loop
// are ok.
mutable result = 1;
mutable frequencyEstimate = 0;
repeat{
// QUANTUM PART START
set frequencyEstimate = EstimateFrequency(nBitsPrecision,bitSize, ApplyPeriodFindingOracle(a, _, number, _));
// QUANTUM PART END
if (frequencyEstimate != 0){
set result = PeriodFromFrequency(frequencyEstimate,nBitsPrecision, number, result);
} else {
Message("Estimated 0 as the frequency, trying again.");
}
} until (ExpModI(a, result, number) == 1)
fixup{
Message("So sorry eh, trying period estimation again.");
}
return result;
}
function PeriodFromFrequency(
frequencyEstimate : Int,
nBitsPrecision : Int,
number : Int,
result : Int
) : Int {
let continuedFraction = ContinuedFractionConvergentI(
Fraction(frequencyEstimate, 2^nBitsPrecision), 2^nBitsPrecision
);
let denominator = AbsI(continuedFraction::Denominator);
return ((denominator * result) / GreatestCommonDivisorI(result, denominator));
}
operation EstimateFrequency(
nBitsPrecision : Int,
bitSize : Int,
oracle : ((Int, Qubit[]) => Unit is Adj+Ctl)
) : Int {
use register = Qubit[bitSize];
let registerLE = LittleEndian(register);
ApplyXorInPlace(1, registerLE);
let phase = RobustPhaseEstimation(
nBitsPrecision,
DiscreteOracle(oracle),
registerLE!
);
ResetAll(register);
return Round((phase * IntAsDouble(2 ^ nBitsPrecision))/(2.0 * PI()));
}
operation ApplyPeriodFindingOracle(
a : Int, x : Int, number :Int, register : Qubit[]
) : Unit is Adj + Ctl {
Fact(IsCoprimeI(a, number), "Must be co-prime to modulus.");
MultiplyByModularInteger(
ExpModI(a, x, number),
number,
LittleEndian(register)
);
}
function MaybeFactorsFromPeriod(a : Int, r : Int, number : Int
) : (Bool, (Int, Int)) {
if (r % 2 == 0) {
let halfPower = ExpModI(a, r/2, number);
if (halfPower != number - 1){
let factor = MaxI(
GreatestCommonDivisorI(halfPower + 1, number),
GreatestCommonDivisorI(halfPower - 1, number)
);
return (true, (factor, number/factor));
} else {
return (false, (1, 1));
}
} else {
return (false, (1, 1));
}
}
}