-
Notifications
You must be signed in to change notification settings - Fork 0
/
quantumFunctions.js
112 lines (101 loc) · 2.64 KB
/
quantumFunctions.js
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
const { GPU } = require('gpu.js');
const gpu = new GPU();
/**
* Returns an array of equal amplitudes. Like as if it was a
* register of entangled qubits.
* @param Q, the number of values to represent (q-qbits => Q = 2^q)
*/
const makeHRegister = (Q) => {
return [...Array(Q)].map(() => 1/Q);
}
/**
* returns a^x mod N
*/
const axmodnFnLinear = function axmodnFn(R, a, N) {
R[0] = 1;
for(let i = 1; i < R.length; i++) {
R[i] = (R[i-1]*a)%N;
}
return R;
};
const axmodnFn = function axmodnFn(a, N, x) {
let p = 1;
for(let i = 0; i < x; i++) {
p = (p*a)%N;
}
return p;
};
/**
* Returns an "entangled" register in which only values from the
* field of a^x mod N are present. You are expected to resolve
* any entanglement.
*/
const axmodnGate = gpu.createKernel(function(R, a, N) {
return axmodnFn(a, N, this.thread.x);
}).setDynamicOutput(true);
gpu.addFunction(axmodnFn);
/**
* register values are probabilities that total 1. If we sum them
* in sequence, each value has a "slot". Pick a random value from
* [0, 1) and find which slot it matches
*/
const measure = (R) => {
const rand = Math.random();
let slotStart = 0, slotEnd = 0;
for(let i = 0; i < R.length; i++) {
slotEnd += R[i];
if(slotStart <= rand && rand < slotEnd) {
return i;
}
slotStart += R[i];
}
return -1;
};
/**
* returns a register where amplitudes in R1 are wiped out
* if the slot wouldn't match a slot in R2 with the measured
* value.
*/
const partialCollapse = gpu.createKernel(function(R1, R2, v) {
if(R2[this.thread.x] === v)
return R1[this.thread.x];
return 0;
}).setDynamicOutput(true);
/**
* Scales all amplitudes so their sum is 1
*/
const normalize = (R) => {
const normalizeRegister = gpu.createKernel(function(R, scale) {
return R[this.thread.x] * scale;
}).setOutput([R.length]);
const total = R.reduce((a,b) => a+b, 0);
return normalizeRegister(R, 1/total);
};
/**
* sort of computes the fourier tranform on an array 'reg'
* this is the "how much power at this frequency" step
* returns the powers of the result, which is enough for finding the dominant frequency/period
*/
const fourier = function fourier(reg, x, size) {
let a = 0, b = 0;
for(let j = 0; j < size; j++) {
a += reg[j] * Math.cos(-2*Math.PI*x*j/size);
b += reg[j] * Math.sin(-2*Math.PI*x*j/size);
}
return a*a + b*b;
};
gpu.addFunction(fourier);
const gpufourier = gpu.createKernel(function(R, size) {
return fourier(R, this.thread.x, size)
}).setDynamicOutput(true);
module.exports = {
axmodnFn,
axmodnFnLinear,
axmodnGate,
fourier,
gpufourier,
makeHRegister,
measure,
normalize,
partialCollapse,
};