Skip to content

Commit eb69ba2

Browse files
committed
Multi-controlled gates now possible
1 parent ec87e72 commit eb69ba2

3 files changed

Lines changed: 243 additions & 5 deletions

File tree

lib/qasm_import/QASMImport.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,24 @@ QCQASMListener.prototype.enterStatement = function(ctx) {
153153
var mixedlist = uop.anylist() ? uop.anylist().mixedlist() : null;
154154
var explist = uop.explist();
155155

156+
157+
switch(gateName) {
158+
case "CX": gateName = "cx"; break;
159+
case "U": gateName = "u3"; break;
160+
}
161+
162+
if(!self.circuit.basicGates[gateName] && !self.circuit.customGates[gateName]) {
163+
// find gate by qasm name
164+
for(var tmpName in self.circuit.basicGates) {
165+
var tmpDef = self.circuit.basicGates[tmpName];
166+
if(tmpDef.exportInfo && tmpDef.exportInfo.qasm && tmpDef.exportInfo.qasm.name && tmpDef.exportInfo.qasm.name == gateName) {
167+
gateName = tmpName;
168+
break;
169+
}
170+
}
171+
}
172+
173+
156174
var params = {};
157175
if(explist && explist.exp()) {
158176
var gateDef = self.circuit.basicGates[gateName];
@@ -189,10 +207,6 @@ QCQASMListener.prototype.enterStatement = function(ctx) {
189207
// ?
190208
}
191209

192-
switch(gateName) {
193-
case "CX": gateName = "cx"; break;
194-
case "U": gateName = "u3"; break;
195-
}
196210
/*
197211
if(!self.compatibilityMode) {
198212
switch(gateName) {

lib/quantum-circuit.js

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,9 @@ var QuantumCircuit = function(numQubits) {
695695
name: "phaseshift",
696696
params: ["lambda"]
697697
},
698+
qasm: {
699+
name: "p"
700+
},
698701
aqasm: {
699702
name: "PH"
700703
}
@@ -3617,6 +3620,227 @@ QuantumCircuit.prototype.appendCircuit = function(circuit, pack) {
36173620
}
36183621
};
36193622

3623+
3624+
3625+
var generateGrayCode = function(numBits) {
3626+
if(numBits <= 0) {
3627+
throw new Error("Cannot generate the gray code for less than 1 bit.");
3628+
}
3629+
3630+
var result = [0];
3631+
for(i = 0; i < numBits; i++) {
3632+
var reversed = [].concat(result).reverse();
3633+
reversed.map(function(x) {
3634+
result.push(x + math.pow(2, i));
3635+
});
3636+
}
3637+
3638+
var gray = [];
3639+
result.map(function(dec) {
3640+
gray.push(binStr(dec, numBits));
3641+
});
3642+
3643+
return gray;
3644+
};
3645+
3646+
3647+
QuantumCircuit.prototype.grayCodeChain = function(numCtrlQubits, gateName, gateOptions) {
3648+
3649+
function compareStrings(s1, s2) {
3650+
var comp = [];
3651+
for(var i = 0; i < s1.length; i++) {
3652+
comp.push(s1[i] != s2[i]);
3653+
}
3654+
return comp;
3655+
}
3656+
3657+
function indicesOfChar(s, ch) {
3658+
var indices = [];
3659+
for(var i = 0; i < s.length; i++) {
3660+
if(s[i] == ch) {
3661+
indices.push(i);
3662+
}
3663+
}
3664+
return indices;
3665+
}
3666+
3667+
function countChar(s, ch) {
3668+
var count = 0;
3669+
for(var i = 0; i < s.length; i++) {
3670+
if(s[i] == ch) {
3671+
count++;
3672+
}
3673+
}
3674+
return count;
3675+
}
3676+
3677+
var qControls = [];
3678+
for(var i = 0; i < numCtrlQubits; i++) {
3679+
qControls.push(i);
3680+
}
3681+
3682+
var qTarget = numCtrlQubits;
3683+
var grayCode = generateGrayCode(numCtrlQubits);
3684+
var lastPattern = null;
3685+
3686+
var rules = [];
3687+
grayCode.map(function(pattern) {
3688+
var lmPos = pattern.indexOf("1");
3689+
if(lmPos >= 0) {
3690+
if(!lastPattern) {
3691+
lastPattern = pattern;
3692+
}
3693+
3694+
var comp = compareStrings(pattern, lastPattern);
3695+
var pos = comp.indexOf(true);
3696+
if(pos >= 0) {
3697+
if(pos != lmPos) {
3698+
rules.push({ gateName: "cx", wires: [ qControls[pos], qControls[lmPos] ], options: null });
3699+
} else {
3700+
var indices = indicesOfChar(pattern, "1");
3701+
for(var idx = 1; idx < indices.length; idx++) {
3702+
rules.push({ gateName: "cx", wires: [ qControls[indices[idx]], qControls[lmPos] ], options: null });
3703+
}
3704+
}
3705+
}
3706+
3707+
if(!(countChar(pattern, "1") % 2)) {
3708+
// inverse
3709+
// !!!
3710+
// Warning - this works only with gate which is own inverse
3711+
// TODO: implement proper inverse for all gates
3712+
// !!!
3713+
var inverseOptions = null;
3714+
if(gateOptions) {
3715+
inverseOptions = JSON.parse(JSON.stringify(gateOptions));
3716+
if(inverseOptions.params) {
3717+
for(key in inverseOptions.params) {
3718+
var val = inverseOptions.params[key];
3719+
if(typeof val == "number") {
3720+
val = 0 - val;
3721+
} else {
3722+
val = "-(" + val + ")";
3723+
}
3724+
inverseOptions.params[key] = val;
3725+
}
3726+
}
3727+
}
3728+
rules.push({ gateName: gateName, wires: [ qControls[lmPos], qTarget ], options: inverseOptions });
3729+
} else {
3730+
rules.push({ gateName: gateName, wires: [ qControls[lmPos], qTarget ], options: gateOptions });
3731+
}
3732+
lastPattern = pattern;
3733+
}
3734+
});
3735+
3736+
return rules;
3737+
};
3738+
3739+
QuantumCircuit.prototype.MCU1Circuit = function(ctrlQubits) {
3740+
var numCtrlQubits = 0;
3741+
var invertControls = [];
3742+
if(typeof ctrlQubits == "number") {
3743+
numCtrlQubits = ctrlQubits;
3744+
} else {
3745+
numCtrlQubits = ctrlQubits.length;
3746+
for(var i = 0; i < numCtrlQubits; i++) {
3747+
if(!ctrlQubits[i] || (typeof ctrlQubits[i] == "number" && ctrlQubits[i] < 0)) {
3748+
invertControls.push(i);
3749+
}
3750+
}
3751+
}
3752+
3753+
if(numCtrlQubits == 0) {
3754+
throw new Error("Cannot create multi-controlled gate with zero control qubits.");
3755+
}
3756+
3757+
function addX(circuit, wires) {
3758+
wires.map(function(wire) {
3759+
circuit.appendGate("x", wire);
3760+
});
3761+
}
3762+
3763+
var scaledLambda = "lambda / " + math.pow(2, numCtrlQubits - 1);
3764+
var gateOptions = { params: { lambda: scaledLambda } };
3765+
3766+
var qc = new QuantumCircuit();
3767+
3768+
if(numCtrlQubits == 1) {
3769+
addX(qc, invertControls);
3770+
qc.appendGate("cu1", [0, 1], gateOptions);
3771+
addX(qc, invertControls);
3772+
return qc;
3773+
}
3774+
3775+
addX(qc, invertControls);
3776+
var rules = this.grayCodeChain(numCtrlQubits, "cu1", gateOptions);
3777+
rules.map(function(rule) {
3778+
qc.appendGate(rule.gateName, rule.wires, rule.options);
3779+
});
3780+
addX(qc, invertControls);
3781+
3782+
return qc;
3783+
};
3784+
3785+
3786+
QuantumCircuit.prototype.MCXCircuit = function(ctrlQubits) {
3787+
var numCtrlQubits = 0;
3788+
var invertControls = [];
3789+
if(typeof ctrlQubits == "number") {
3790+
numCtrlQubits = ctrlQubits;
3791+
} else {
3792+
numCtrlQubits = ctrlQubits.length;
3793+
for(var i = 0; i < numCtrlQubits; i++) {
3794+
if(!ctrlQubits[i] || (typeof ctrlQubits[i] == "number" && ctrlQubits[i] < 0)) {
3795+
invertControls.push(i);
3796+
}
3797+
}
3798+
}
3799+
3800+
var qc = new QuantumCircuit();
3801+
if(numCtrlQubits == 0) {
3802+
throw new Error("Cannot create multi-controlled gate with zero control qubits.");
3803+
}
3804+
3805+
function addX(circuit, wires) {
3806+
wires.map(function(wire) {
3807+
circuit.appendGate("x", wire);
3808+
});
3809+
}
3810+
3811+
if(numCtrlQubits == 1) {
3812+
addX(qc, invertControls);
3813+
qc.appendGate("cx", [0, 1]);
3814+
addX(qc, invertControls);
3815+
return qc;
3816+
}
3817+
3818+
if(numCtrlQubits == 2) {
3819+
addX(qc, invertControls);
3820+
qc.appendGate("ccx", [0, 1, 2]);
3821+
addX(qc, invertControls);
3822+
return qc;
3823+
}
3824+
3825+
var mcu1 = qc.MCU1Circuit(numCtrlQubits);
3826+
var mcu1name = "mcu1_" + numCtrlQubits;
3827+
var mcu1wires = [];
3828+
for(var i = 0; i < numCtrlQubits + 1; i++) {
3829+
mcu1wires.push(i);
3830+
}
3831+
3832+
qc.registerGate(mcu1name, mcu1);
3833+
addX(qc, invertControls);
3834+
qc.appendGate("h", numCtrlQubits);
3835+
qc.appendGate(mcu1name, mcu1wires, { params: { lambda: "pi" }});
3836+
addX(qc, invertControls);
3837+
qc.appendGate("h", numCtrlQubits);
3838+
3839+
return qc;
3840+
};
3841+
3842+
3843+
36203844
QuantumCircuit.prototype.removeTrailingColumns = function() {
36213845
var numCols = this.numCols();
36223846
for(var column = numCols - 1; column >= 0; column--) {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "quantum-circuit",
3-
"version": "0.9.185",
3+
"version": "0.9.186",
44
"description": "Quantum Circuit Simulator",
55
"main": "lib/quantum-circuit.js",
66
"unpkg": "dist/quantum-circuit.min.js",

0 commit comments

Comments
 (0)