Giter Club home page Giter Club logo

quantum-circuit's Introduction

Quantum Circuit Simulator

quantum-circuit is open source quantum circuit simulator implemented in javascript. Smoothly runs 20+ qubit simulations in browser or at server (node.js). You can use it in your javascript program to run quantum simulations.

Circuit can be imported from OpenQASM, Quil and IONQ. You can export circuits to OpenQASM, pyQuil, Quil, Qiskit, Cirq, TensorFlow Quantum, QSharp, and QuEST, so it can be used for conversion between quantum programming languages. Circuit drawing can be exported to SVG vector image.

Live examples

Quantum Programming Studio

Quantum Programming Studio is web based quantum programming IDE and simulator built on top of this package. Circuit can be executed on real quantum computer directly from the UI.

Other live examples

Using in browser

Simply include quantum-circuit.min.js into your html page (available via unpkg CDN https://unpkg.com/quantum-circuit)

<!doctype html>
<html>
    <head>
        <title>Quantum Circuit Simulator Example</title>
    </head>

    <body>
        <script type="text/javascript" src="https://unpkg.com/quantum-circuit"></script>

        <script type="text/javascript">
            // Your code here
        </script>
    </body>
</html>

Using at server with node.js

Add quantum-circuit npm module to your node.js project:

npm install --save quantum-circuit

And then import it into your program:

var QuantumCircuit = require("quantum-circuit");

// Your code here

Node.js examples

See /example/nodejs directory.

Using with Jupyter notebook

You need to install ijavascript kernel for Jupyter notebook

You can install quantum-circuit npm module globally and invoke jupyter notebook from any directory:

npm install -g quantum-circuit

Or inside new directory do:

npm init
npm install --save quantum-circuit
jupyter notebook

Jupyter notebook examples

See /example/jupyter directory.

Getting started

Create circuit

Create instance of QuantumCircuit class, optionally passing number of qubits (wires) to constructor:

var circuit = new QuantumCircuit(3);

Note: number of qubits is optional argument - circuit will expand automatically if you add gates to non-existing wires

Add single-qubit gates

Call addGate method passing gate name, column index and qubit (wire) index:

circuit.addGate(gateName, column, wire);

For example, to add Hadamard gate as a first gate (column 0) at second qubit (wire 1) type:

circuit.addGate("h", 0, 1);

Result is:

                  
         Column 0 
                  
Wire 0 -----------
                  
          |---|   
Wire 1 ---| H |---
          |---|   
                  

Note: if column is negative integer then gate will be added to the end of the wire

Add multi-qubit gates

Call addGate method passing gate name, column index and array of connected qubits (wires):

circuit.addGate(gateName, column, arrayOfWires);

For example, to add CNOT as a second gate (column 1) controlled by second qubit (wire 1) at third qubit as target (wire 2) do:

circuit.addGate("cx", 1, [1, 2]);
                                
         Column 0    Column 1   
                               
Wire 0 ------------------------
                               
                               
Wire 1 -----------------o------
                        |      
                     |-----|   
Wire 2 --------------| CX  |---
                     |-----|   
                               

Note: if column is negative integer then gate will be added to the end

Example - Quantum random number generator

var QuantumCircuit = require("quantum-circuit");

//
// 8-bit quantum random number generator
//

var quantumRandom = function() {

    var circuit = new QuantumCircuit();

    for(var i = 0; i < 8; i++) {
        //
        // add Hadamard gate to the end (-1) of i-th wire
        //
        circuit.addGate("h", -1, i);

        //
        // add measurement gate to i-th qubit which will store result 
        // into classical register "c", into i-th classical bit
        //
        circuit.addMeasure(i, "c", i); 
    }

    // run circuit
    circuit.run();

    // return value of register "c"
    return circuit.getCregValue("c");
};

// Usage - print random number to terminal
console.log(quantumRandom());

Implemented gates

Name pyQuil Cirq Q# IONQ Qubits Params Description
id I I I 1 Single qubit identity gate
x X X X x 1 Pauli X (PI rotation over X-axis) aka "NOT" gate
y Y Y Y y 1 Pauli Y (PI rotation over Y-axis)
z Z Z Z z 1 Pauli Z (PI rotation over Z-axis)
h H H H h 1 Hadamard gate
srn def srn X**(1/2) v 1 Square root of NOT
srndg def srndg X**(-1/2) vi 1 Inverse square root of NOT
r2 S S S 1 PI/2 rotation over Z-axis aka "Phase PI/2"
r4 T T T 1 PI/4 rotation over Z-axis aka "Phase PI/4"
r8 PHASE(pi/8) u1(pi/8) 1 PI/8 rotation over Z-axis aka "Phase PI/8"
rx RX rx Rx rx 1 theta Rotation around the X-axis by given angle
ry RY ry Ry ry 1 theta Rotation around the Y-axis by given angle
rz RZ rz Rz rz 1 phi Rotation around the Z-axis by given angle
u1 PHASE def u1 1 lambda Single-qubit rotation about the Z axis
u2 def u2 def u2 1 phi, lambda Single-qubit rotation about the X+Z axis
u3 def u3 def u3 1 theta, phi, lambda Generic single-qubit rotation gate with 3 Euler angles
s S S S s 1 PI/2 rotation over Z-axis (synonym for r2)
t T T T t 1 PI/4 rotation over Z-axis (synonym for r4)
sdg PHASE(-pi/2) u1(-pi/2) si 1 (-PI/2) rotation over Z-axis
tdg PHASE(-pi/4) u1(-pi/4) ti 1 (-PI/4) rotation over Z-axis
gpi def gpi gpi gpi 1 phi GPi gate
gpi2 def gpi2 gpi2 gpi2 1 phi GPi2 gate
vz def vz vz vz 1 theta VirtualZ gate
cx CNOT CNOT CNOT cnot 2 Controlled NOT (CNOT) gate
cy def cy Y Controlled Y 2 Controlled Y gate (controlled rotation over Y-axis by PI)
cz CZ CZ Controlled Z 2 Controlled Z gate (controlled rotation over Z-axis by PI)
ch def ch H Controlled H 2 Controlled Hadamard gate
csrn def csrn X**(1/2) 2 Controlled square root of NOT
swap SWAP SWAP SWAP swap 2 Swaps the state of two qubits.
srswap def srswap SWAP**(1/2) 2 Square root of swap
iswap ISWAP ISWAP 2 Swaps the state of two qubits, applying a -i phase to q1 when it is in the 1 state and a -i phase to q2 when it is in the 0 state
xx def xx xx xx 2 theta XX gate
yy def yy YY yy 2 theta YY gate
zz def zz zz 2 theta Parametric 2-qubit rotation about ZZ
xy XY def xy 2 phi XY gate
ms def ms ms ms 2 phi0, phi1 Mølmer-Sørensen gate
cr2 CPHASE(pi/2) cu1(pi/2) 2 Controlled PI/2 rotation over Z-axis
cr4 CPHASE(pi/4) cu1(pi/4) 2 Controlled PI/4 rotation over Z-axis
cr8 CPHASE(pi/8) cu1(pi/8) 2 Controlled PI/8 rotation over Z-axis
crx def crx rx(theta) Controlled Rx 2 theta Controlled rotation around the X-axis by given angle
cry def cry ry(theta) Controlled Ry 2 theta Controlled rotation around the Y-axis by given angle
crz def crz rz(phi) Controlled Rz 2 phi Controlled rotation around the Z-axis by given angle
cu1 CPHASE def cu1 2 lambda Controlled rotation about the Z axis
cu2 def cu2 def cu2 2 phi, lambda Controlled rotation about the X+Z axis
cu3 def cu3 def cu3 2 theta, phi, lambda Controlled rotation gate with 3 Euler angles
cs CPHASE(pi/2) cu1(pi/2) 2 Controlled PI/2 rotation over Z-axis (synonym for cr2)
ct CPHASE(pi/4) cu1(pi/4) 2 Controlled PI/4 rotation over Z-axis (synonym for cr4)
csdg CPHASE(-pi/2) cu1(-pi/2) 2 Controlled (-PI/2) rotation over Z-axis
ctdg CPHASE(-pi/4) cu1(-pi/4) 2 Controlled (-PI/4) rotation over Z-axis
ccx CCNOT CCX CCNOT 3 Toffoli aka "CCNOT" gate
cswap CSWAP CSWAP Controlled SWAP 3 Controlled swap aka "Fredkin" gate
csrswap def csrswap SWAP**(1/2) 3 Controlled square root of swap
reset RESET reset Reset 1 Resets qubit
measure MEASURE measure M 1 Measures qubit and stores chance (0 or 1) into classical bit

For more details see gate reference

Run circuit

Simply call run method.

circuit.run();

Initial state

By default, initial state of each qubit is |0>. You can pass initial values as array of bool (true or false) or integers (0 or 1). This will set first two qubits to |1> and evaluate circuit:

circuit.run([1, 1]);

Measurement

Method probabilities() will return array of probabilities (real numbers between 0 and 1) for each qubit:

console.log(circuit.probabilities());

Method probability(wire) will return probability (real number between 0 and 1) for given qubit:

console.log(circuit.probability(0));

Method measureAll() returns array of chances (as integers 0 or 1) for each qubit:

Example:

console.log(circuit.measureAll());

Method measure(wire) returns chance (as integer 0 or 1) for given qubit:

Example:

console.log(circuit.measure(0));

You can store measurement into classical register. For example, to measure first qubit (wire 0) and store result into classical register named c as fourth bit (bit 3):

circuit.measure(0, "c", 3);

You can add measure gate to circuit and then measurement will be done automatically and result will be stored into classical register:

circuit.addGate("measure", -1, 0, { creg: { name: "c", bit: 3 } });

Short form of writing this is addMeasure(wire, creg, cbit):

circuit.addMeasure(0, "c", 3);

Note:

  • Measurement gate will reset qubit to measured value only if there are gates with classical control (gates controlled by classical registers). Otherwise, measurement gate will leave qubit as is - measured value will be written to classical register and qubit will remain unchanged. This "nondestructive" behavior is handy when experimenting. However, it will automatically switches to "destructive" mode when needed (when classical control is present)

  • If specified classical register doesn't exists - it will be created automatically.

Classical registers

Create register

Classical registers are created automatically if you add measurement gate to the circuit but you can also manually create registers by calling createCreg(name, len).

Example: create classical 5-bit register named ans:

circuit.createCreg("ans", 5);

Read register

To get register value as integer, call getCregValue(name).

Example:

var value = circuit.getCregValue("ans");

Read all registers as dictionary

var regs = circuit.getCregs();
console.log(regs);

Read all registers as tab delimited CSV string

var tsv = circuit.cregsAsString();
console.log(tsv);

Read single bit

Example: get bit 3 from register named ans:

console.log(circuit.getCregBit("ans", 3));

Returns integer: 0 or 1

Set single bit

Example: set bit 3 to 1 in register named ans:

circuit.setCregBit("ans", 3, 1);

Control by classical register

Each quatum gate in the circuit (except "measure" gate) can be controlled by classical register - gate will be executed only if classical register contains specified value. Pass options object as fourth argument to addGate method:

Example:

circuit.addGate("x", -1, 0, { 
    condition: { 
        creg: "ans",
        value: 7
    }
});

In this example, "x" gate will execute on qubit 0 only if value of register named "ans" equals 7.

Reset qubit

You can reset qubit to value |0> or |1> with resetQubit method:

circuit.resetQubit(3, 0);

In this example, qubit 3 will be set to 0|>.

Note that all entangled qubits will be changed as well

View/print state vector

You can get state as string with method stateAsString(onlyPossible):

var s = circuit.stateAsString(false);

If you want only possible values (only values with probability > 0) then pass true:

var s = circuit.stateAsString(true);

Or, you can print state to javascript console with method print(onlyPossible):

circuit.print(false);

If you want to print only possible values (only values with probability > 0) then pass true:

var s = circuit.print(true);

Save/Load circuit

You can export circuit to javascript object (format internally used by QuantumCircuit) by calling save method:

var obj = circuit.save();

// now do something with obj, save to file or whatever...

And load previously saved circuit by calling load method:

var obj = // ...load object from file or from another circuit or whatever

circuit.load(obj);

Use circuit as a gate in another circuit

You can "compile" any circuit and use it as a gate in another circuit like this:

// export circuit to variable
var obj = someCircuit.save();

// register it as a gate in another circuit
anotherCircuit.registerGate("my_gate", obj);

// use it as a gate in another circuit
// assuming original circuit has three qubits then gate must spread to 3 qubits, in this example: 2, 3, 4)
anotherCircuit.addGate("my_gate", 0, [2, 3, 4]);

Decompose circuit

If your circuit contains user defined gates (created from another circuit), you can decompose it into equivalent circuit containing only basic gates.

If you pass true as argument to function save, you'll get decomposed circuit.

Example:

var obj = circuit.save(true);
// now obj contains decomposed circuit. You can load it:
circuit.load(obj);

Import circuit

Import from QASM

Circuit can be imported from OpenQASM with following limitations:

  • import directive is ignored (but most of gates defined in qelib1.inc are supported) TODO

  • barrier is ignored. TODO

  • reset is ignored. TODO

To import circuit from OpenQASM use importQASM(input, errorCallback) method:

Example:

circuit.importQASM("OPENQASM 2.0;\nimport \"qelib1.inc\";\nqreg q[2];\nh q[0];\ncx q[0],q[1];\n", function(errors) {
    console.log(errors);
});
  • input is string containing QASM source code.

  • errorCallback (optional) callback will be called after parsing with one argument: array containing errors or empty array on success. If no callback is provided, function will throw error if input contains errors.

Import from QUIL

Circuit can be imported from Quil:

To import circuit from QUIL use importQuil(quil, errorCallback, options, qubitNames, renamedGates, lineOffset) method:

Example:

circuit.importQuil("H 0\nCNOT 0 1\n", function(errors) {
    console.log(errors);
});
  • quil is string containing QUIL source code.

  • errorCallback (optional) callback will be called after parsing with one argument: array containing errors or empty array on success. If no callback is provided, function will throw error if input contains errors.

  • options (optional) function will be called after parsing with array containing syntax errors.

  • qubitNames (optional) names to be given to the qubits.

  • renamedGates (optional) custom names given to basic commands

  • lineOffset (optional) no. of spaces before a new line

Import from Qobj

Circuit can be imported from Qobj:

To import circuit from OpenQASM use importQobj(qobj, errorCallback) method:

Example:

circuit.importQobj({"qobj_id":"qobj_WlLkcGHxihyqWGrKEZ","type":"QASM","schema_version":"1.0","experiments":[{"header":{"memory_slots":0,"n_qubits":2,"qreg_sizes":[["q",2]],"qubit_labels":[["q",0],["q",1]],"creg_sizes":[],"clbit_labels":[],"name":"circuit0","description":"text_exp"},"config":{"n_qubits":2,"memory_slots":0},"instructions":[{"name":"x","qubits":[0,1]}]}],"header":{"description":"test_circ"},"config":{"shots":1,"memory_slots":0}}, function(errors) {
    console.log(errors);
});
  • qobj is Qobj JSON ("type": "QASM").

  • errorCallback (optional) callback will be called after parsing with one argument: array containing errors or empty array on success. If no callback is provided, function will throw error if input contains errors.

Import from IONQ json

Circuit can be imported from IONQ json:

To import circuit from IONQ json use importIonq(data, errorCallback) method:

Example:

var ionqCircuit = {
  "qubits": 2,
  "circuit": [
    {
      "gate": "h",
      "target": 0
    },
    {
      "gate": "cnot",
      "target": 1,
      "control": 0
    }
  ]
};

circuit.importIonq(ionqCircuit, function(errors) {
    console.log(errors);
});
  • data is IONQ JSON object.

  • errorCallback (optional) callback will be called after parsing with one argument: array containing errors or empty array on success. If no callback is provided, function will throw error if input contains errors.

Export circuit

Export to JavaScript

Circuit can be exported to JavaScript with exportJavaScript(comment, decompose, null, asJupyter) method:

Example:

var js = circuit.exportJavaScript("Comment to insert at the beginning.\nCan be multi-line comment like this one.", false);
  • comment - comment to insert at the beginning of the file.

  • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

  • asJupyter - when this argument is true jupyter notebook (set to use ijavascript kernel) will be returned.

Export to python (Qiskit)

Circuit can be exported to Qiskit with following limitation:

  • User defined gates are not generated. Instead, circuit is decomposed to basic gates and exported. Effect is the same but code is less readable. TODO

  • Gates not directly supported by Qiskit are exported as-is - their definition is not generated. TODO

To export circuit to Qiskit use exportToQiskit(options, exportAsGateName, circuitReplacement, insideSubmodule) method :

Example:

var qiskit = circuit.exportToQiskit({comment:"Comment to insert at the beginning.\nCan be multi-line comment as this one."}, false, null, null);
  • options - consists of parameters for circuit export as follows:

    • comment - comment to insert at the beginning of the file.

    • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

    • versionStr - Qiskit version. Can be "0.7". Exports to latest supported version when empty string is provided. Remember - it is a string.

    • providerName - name of the Qiskit backend simulator provider.

    • backendName - name of the Qiskit backend simulator.

    • asJupyter - when this argument is true jupyter notebook will be returned.

    • shots - no. of trials.

    • hybrid - when true exports user defined cost function along with circuit for hybrid Quantum-Classical Algorithms

  • insideSubmodule - when true adds extra indent for alignment

  • exportAsGateName - name of the custom gate containing the Qiskit circuit.

  • circuitReplacement - when true exports only gates in the circuit

(Deprecated. Please use exportToQiskit() instead)

To export circuit to Qiskit you can also use exportQiskit(comment, decompose, exportAsGateName, versionStr, providerName, backendName, asJupyter, shots, circuitReplacement, insideSubmodule, hybrid)

Example:

var qiskit = circuit.exportQiskit("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false, null, null);
  • comment - comment to insert at the beginning of the file.

  • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

  • versionStr - Qiskit version. Can be "0.7". Exports to latest supported version when empty string is provided. Remember - it is a string.

  • providerName - name of the Qiskit backend simulator provider.

  • backendName - name of the Qiskit backend simulator.

  • asJupyter - when this argument is true jupyter notebook will be returned.

  • shots - no. of trials.

  • hybrid - when true exports user defined cost function along with circuit for hybrid Quantum-Classical Algorithms

  • insideSubmodule - when true adds extra indent for alignment

  • exportAsGateName - name of the custom gate containing the Qiskit circuit.

  • circuitReplacement - when true exports only gates in the circuit

Export to QASM

Circuit can be exported to OpenQASM with following limitation:

  • at the moment, gates not directly supported by QASM and qelib1.inc are exported as-is - their definition is not generated. TODO

To export circuit to OpenQASM use exportToQASM(options, exportAsGateName, circuitReplacement, insideSubmodule) method:

Example:

var qasm = circuit.exportToQASM({comment:"Comment to insert at the beginning.\nCan be multi-line comment as this one."}, false);
  • options - consists of parameters for circuit export as follows:

    • comment - comment to insert at the beginning of the file.

    • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

    • compatibilityMode - if set to true exports the circuit in compatible mode

  • insideSubmodule - when true adds extra indent for alignment

  • exportAsGateName - name of the custom gate containing the Qiskit circuit.

  • circuitReplacement - when true exports only gates in the circuit

(Deprecated. Please use exportToQASM() instead)

To export circuit to OpenQASM you can also use exportQASM(comment, decompose, exportAsGateName, circuitReplacement, compatibilityMode, insideSubmodule) method:

Example:

var qasm = circuit.exportQASM("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false);
  • comment - comment to insert at the beginning of the file.

  • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

  • exportAsGateName - name of the custom gate containing the Qiskit circuit.

  • circuitReplacement - when true exports only gates in the circuit

  • compatibilityMode - if set to true exports the circuit in compatible mode

  • insideSubmodule - when true adds extra indent for alignment

Export to python (pyQuil)

Circuit can be exported to pyQuil

To export circuit to pyQuil use exportToPyquil(options, exportAsGateName) method:

Example:

var qasm = circuit.exportToPyquil({comment:"Comment to insert at the beginning.\nCan be multi-line comment as this one."}, false);
  • options - consists of parameters for circuit export as follows:

    • comment - comment to insert at the beginning of the file.

    • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

    • versionStr - pyQuil version. Can be "1.9", "2.0" or "2.1". Exports to latest supported version when empty string is provided. Remember - it is a string.

    • lattice - You can optionally pass then name of the lattice.

    • asQVM - If this argument is true (and if lattice is specified) then produced code will run on QVM mimicking running on QPU. Otherwise, produced code will run on QPU.

    • asJupyter - when this argument is true jupyter notebook will be returned.

    • shots - no. of trials.

    • hybrid - when true exports user defined cost function along with circuit for hybrid Quantum-Classical Algorithms

  • exportAsGateName - name of the custom gate containing the Pyquil circuit.

(Deprecated. Please use exportToPyquil() instead)

To export circuit to Pyquil you can also use exportPyquil(comment, decompose, exportAsGateName, versionStr, lattice, asQVM, asJupyter, shots, hybrid) method:

Example:

var pyquil = circuit.exportPyquil("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false, null, "2.1", "", false);
  • comment - comment to insert at the beginning of the file.

  • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

  • exportAsGateName - name of the custom gate containing the Pyquil circuit.

  • versionStr - pyQuil version. Can be "1.9", "2.0" or "2.1". Exports to latest supported version when empty string is provided. Remember - it is a string.

  • lattice - You can optionally pass then name of the lattice.

  • asQVM - If this argument is true (and if lattice is specified) then produced code will run on QVM mimicking running on QPU. Otherwise, produced code will run on QPU.

  • asJupyter - when this argument is true jupyter notebook will be returned.

  • shots - no. of trials.

  • hybrid - when true exports user defined cost function along with circuit for hybrid Quantum-Classical Algorithms

Export to Quil

Circuit can be exported to Quil

To export circuit to Quil use exportToQuil(options, exportAsGateName) method:

Example:

var quil = circuit.exportToQuil({comment:"Comment to insert at the beginning.\nCan be multi-line comment as this one."}, false);
  • options - consists of parameters for circuit export as follows:

    • comment - comment to insert at the beginning of the file.

    • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

    • versionStr - pyQuil version. Can be "1.9", "2.0" or "2.1". Exports to latest supported version when empty string is provided. Remember - it is a string.

  • exportAsGateName - name of the custom gate containing the Pyquil circuit.

(Deprecated. Please use exportToQuil() instead)

To export circuit to Quil you can also use exportQuil(comment, decompose, exportAsGateName, versionStr) method:

Example:

var quil = circuit.exportQuil("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false, null, "2.0");
  • comment - comment to insert at the beginning of the file.

  • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines (DEFCIRCUIT).

  • exportAsGateName - name of the custom gate containing the Quil circuit.

  • versionStr - Quil version. Can be "1.0" or "2.0" or empty string. Exports to latest supported version when empty string is provided. Remember - it is a string.

Export to python (Cirq)

Circuit can be exported to Cirq with following limitation:

  • Gates not directly supported by Cirq are exported as-is - their definition is not generated. TODO

  • Classical control is ignored (comment with warning is generated). TODO

To export circuit to Cirq use exportToCirq(options, exportAsGateName) method:

Example:

var cirq = circuit.exportToCirq({comment:"Comment to insert at the beginning.\nCan be multi-line comment as this one."}, false);
  • options - consists of parameters for circuit export as follows:

    • comment - comment to insert at the beginning of the file.

    • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

    • versionStr - Cirq version. Can be "0.5" or empty string. Exports to latest supported version when empty string is provided. Remember - it is a string.

    • asJupyter - when this argument is true jupyter notebook will be returned.

    • shots - no. of trials.

    • exportTfq - if set to true the export function will export circuit to Tensorflow Quantum.

  • exportAsGateName - name of the custom gate containing the Cirq circuit.

(Deprecated. Please use exportToCirq() instead)

To export circuit to Cirq you can also use exportCirq(comment, decompose, exportAsGateName, versionStr, asJupyter, shots, exportTfq) method:

Example:

var cirq = circuit.exportCirq("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false, null, null, false, null, false);
  • comment - comment to insert at the beginning of the file.

  • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

  • exportAsGateName - name of the custom gate containing the Cirq circuit.

  • versionStr - Cirq version. Can be "0.5" or empty string. Exports to latest supported version when empty string is provided. Remember - it is a string.

  • asJupyter - when this argument is true jupyter notebook will be returned.

  • shots - no. of trials.

  • exportTfq - if set to true the export function will export circuit to Tensorflow Quantum.

Export to C/C++ (QuEST)

Circuit can be exported to QuEST

To export circuit to QuEST use exportQuEST(newOptions, exportAsGateName, definedFunc) method:

Example:

var quest = circuit.exportToQuEST("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false);
  • options - consists of parameters for circuit export as follows:

    • comment - comment to insert at the beginning of the file.

    • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

  • exportAsGateName - name of the custom gate containing the Cirq circuit.

  • definedFunc - list of gates that must be present in the defined function

(Deprecated. Please use exportToQuEST() instead)

To export circuit to QuEST you can also use exportQuEST(comment, decompose, exportAsGateName, definedFunc) method:

Example:

var quest = circuit.exportQuEST("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false, null, null);
  • comment - comment to insert at the beginning of the file.

  • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

  • exportAsGateName - name of the custom gate containing the QuEST circuit.

  • definedFunc - list of gates that must be present in the defined function

Export to Q# (QSharp)

Circuit can be exported to Q#.

To export circuit to Q# use exportQSharp(options, exportAsGateName) method:

Example:

var qsharp = circuit.exportQSharp("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false, null, null, false, null);
  • options - consists of parameters for circuit export as follows:

    • comment - comment to insert at the beginning of the file.

    • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

    • versionStr - QSharp version. Can be "0.1" or empty string. Exports to latest supported version when empty string is provided. Remember - it is a string.

    • asJupyter - when this argument is true jupyter notebook (set to use qsharp kernel) will be returned.

    • circuitName - Name of the circuit that is being exported to QSharp. By default set to "Circuit"

    • indentDepth - The no. of tabs to be put before a Python line of code.

  • exportAsGateName - name of the custom gate containing the QSharp circuit.

(Deprecated. Please use exportToQSharp() instead)

To export circuit to Q# use exportQSharp(comment, decompose, exportAsGateName, versionStr, asJupyter, circuitName, indentDepth) method:

Example:

var qsharp = circuit.exportQSharp("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false, null, null, false, null);
  • comment - comment to insert at the beginning of the file.

  • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

  • exportAsGateName - name of the custom gate containing the QSharp circuit.

  • versionStr - QSharp version. Can be "0.1" or empty string. Exports to latest supported version when empty string is provided. Remember - it is a string.

  • asJupyter - when this argument is true jupyter notebook (set to use qsharp kernel) will be returned.

  • circuitName - Name of the circuit that is being exported to QSharp. By default set to "Circuit"

  • indentDepth - The no. of tabs to be put before a Python line of code.

Export to Qobj

Circuit can be exported to Qobj:

To export circuit to Qiskit use exportToQobj(options, circuitReplacement) method :

Example:

var qobj = circuit.exportToQobj({circuitName:"new_circuit"}, false);
  • options - consists of parameters for circuit export as follows:

    • circuitName - name of the circuit that is being exported to Qobj

    • experimentName - name of the experiment that describes the number of memory slots, qubits, qubit names, classical bit names etc.

    • numShots - no. of trials.

  • circuitReplacement - when true exports only gates in the circuit

(Deprecated. Please use exportToQobj() instead)

To export circuit to Qobj you can also use exportQobj(circuitName, experimentName, numShots, circuitReplacement)

Example:

var qobj = circuit.exportQobj("new_circuit", false);
  • circuitName - name of the circuit that is being exported to Qobj

  • experimentName - name of the experiment that describes the number of memory slots, qubits, qubit names, classical bit names etc.

  • numShots - no. of trials.

  • circuitReplacement - when true exports only gates in the circuit

Export to python (Tensorflow Quantum)

Circuit can be exported to Tensorflow Quantum:

To export circuit to TFQ use exportToTFQ(options, exportAsGateName) method :

Example:

var tfq = circuit.exportToTFQ({comment:"Comment to insert at the beginning.\nCan be multi-line comment as this one."}, false);
  • options - consists of parameters for circuit export as follows:

    • comment - comment to insert at the beginning of the file.

    • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

    • versionStr - TFQ version. Exports to latest supported version when empty string is provided. Remember - it is a string.

    • asJupyter - when this argument is true jupyter notebook will be returned.

    • shots - no. of trials.

  • exportAsGateName - name of the custom gate containing the TFQ circuit.

(Deprecated. Please use exportToTFQ() instead)

To export circuit to TFQ you can also use exportTFQ(comment, decompose, exportAsGateName, versionStr, asJupyter, shots)

Example:

var tfq = circuit.exportTFQ("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false, null, null);
  • comment - comment to insert at the beginning of the file.

  • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

  • exportAsGateName - name of the custom gate containing the TFQ circuit.

  • versionStr - TFQ version. Exports to latest supported version when empty string is provided. Remember - it is a string.

  • asJupyter - when this argument is true jupyter notebook will be returned.

  • shots - no. of trials.

Export to python (Braket)

Circuit can be exported to Braket:

To export circuit to Braket use exportToBraket(options, exportAsGateName) method :

Example:

var braket = circuit.exportToBraket({comment:"Comment to insert at the beginning.\nCan be multi-line comment as this one."}, false);
  • options - consists of parameters for circuit export as follows:

    • comment - comment to insert at the beginning of the file.

    • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

    • versionStr - Braket version. Exports to latest supported version when empty string is provided. Remember - it is a string.

    • asJupyter - when this argument is true jupyter notebook will be returned.

    • shots - no. of trials.

    • indentDepth - The no. of tabs to be put before a Python line of code.

    • hybrid - when true exports user defined cost function along with circuit for hybrid Quantum-Classical Algorithms

  • exportAsGateName - name of the custom gate containing the Braket circuit.

(Deprecated. Please use exportToBraket() instead)

To export circuit to Braket you can also use exportBraket(comment, decompose, exportAsGateName, versionStr, asJupyter, shots, hybrid, indentDepth)

Example:

var braket = circuit.exportBraket("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false, null, null);
  • comment - comment to insert at the beginning of the file.

  • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

  • exportAsGateName - name of the custom gate containing the Braket circuit.

  • versionStr - Braket version. Exports to latest supported version when empty string is provided. Remember - it is a string.

  • asJupyter - when this argument is true jupyter notebook will be returned.

  • shots - no. of trials.

  • indentDepth - The no. of tabs to be put before a Python line of code.

  • hybrid - when true exports user defined cost function along with circuit for hybrid Quantum-Classical Algorithms

Export to python (pyAQASM)

Circuit can be exported to pyAQASM:

To export circuit to pyAQASM use exportToPyAQASM(options, exportAsGateName) method :

Example:

var pyAqasm = circuit.exportToPyAQASM({comment:"Comment to insert at the beginning.\nCan be multi-line comment as this one."}, false);
  • options - consists of parameters for circuit export as follows:

    • comment - comment to insert at the beginning of the file.

    • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

    • asJupyter - when this argument is true jupyter notebook will be returned.

    • shots - no. of trials.

    • hybrid - when true exports user defined cost function along with circuit for hybrid Quantum-Classical Algorithms

  • exportAsGateName - name of the custom gate containing the pyAQASM circuit.

(Deprecated. Please use exportToPyAQASM() instead)

To export circuit to pyAQASM you can also use exportPyAQASM(comment, decompose, exportAsGateName, asJupyter, shots, hybrid)

Example:

var pyAqasm = circuit.exportPyAQASM("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false, null, null);
  • comment - comment to insert at the beginning of the file.

  • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

  • exportAsGateName - name of the custom gate containing the pyAQASM circuit.

  • asJupyter - when this argument is true jupyter notebook will be returned.

  • shots - no. of trials.

  • hybrid - when true exports user defined cost function along with circuit for hybrid Quantum-Classical Algorithms

Export to python (AQASM)

Circuit can be exported to AQASM:

To export circuit to AQASM use exportToAQASM(options, isExportPyAQASM, exportAsGateName, indentDepth) method :

Example:

var aqasm = circuit.exportToAQASM({comment:"Comment to insert at the beginning.\nCan be multi-line comment as this one."}, false);
  • options - consists of parameters for circuit export as follows:

    • comment - comment to insert at the beginning of the file.

    • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

    • asJupyter - when this argument is true jupyter notebook will be returned.

    • shots - no. of trials.

    • hybrid - when true exports user defined cost function along with circuit for hybrid Quantum-Classical Algorithms

  • isExportPyAQASM - if true, this function will be used to export to pyAQASM instead of AQASM.

  • exportAsGateName - name of the custom gate containing the AQASM circuit.

  • indentDepth - The no. of tabs to be put before a Python line of code.

(Deprecated. Please use exportToAQASM() instead)

To export circuit to pyAQASM you can also use exportAQASM(comment, decompose, isExportPyAQASM, exportAsGateName, asJupyter, shots, hybrid, indentDepth)

Example:

var aqasm = circuit.exportAQASM("Comment to insert at the beginning.\nCan be multi-line comment as this one.", false, null, null);
  • comment - comment to insert at the beginning of the file.

  • decompose - if set to true and circuit contains user defined gates then it will be decomposed to basic gates and then exported. If set to false then user defined gates will exported as subroutines.

  • isExportPyAQASM - if true, this function will be used to export to pyAQASM instead of AQASM.

  • exportAsGateName - name of the custom gate containing the AQASM circuit.

  • asJupyter - when this argument is true jupyter notebook will be returned.

  • shots - no. of trials.

  • hybrid - when true exports user defined cost function along with circuit for hybrid Quantum-Classical Algorithms

  • indentDepth - The no. of tabs to be put before a Python line of code.

Export to SVG

Vector .svg image of circuit can be created with exportSVG(embedded) function with following limitations:

  • Gate symbols are non-standard. TODO (BTW, do we have standard?)

Example 1

Show circuit in browser:

// Assuming we have <div id="drawing"></div> somewhere in HTML
var container = document.getElementById("drawing");

// SVG is returned as string
var svg = circuit.exportSVG(true);

// add SVG into container
container.innerHTML = svg;

Example 2

Generate standalone SVG image at server with node.js:

// export as standalone SVG
var svg = circuit.exportSVG(false);

// do something with svg string (e.g. save to file)
...

// Or, export as embedded SVG for use in browser
svg = circuit.exportSVG(true);

// do something with svg string (e.g. serve via HTTP)
...

Export to Quirk

Circuit can be exported to popular open-source drag-and-drop quantum circuit simulator Quirk with following limitations:

  • Quirk doesn't support more than 16 qubits.

  • Quirk can possibly incorrectly interpret circuit if we have multiple controlled gates in the same column.

  • Quirk doesn't support non-sequentially positioned multi-qubit user-defined gates (for example gate on wires [3, 0, 1]) so it's best to export decomposed circuit.

Example:

var quirkData = circuit.exportQuirk(true);

var quirkURL = "http://algassert.com/quirk#circuit=" + JSON.stringify(quirkData);

// Now do something with quirkURL. Assuming this code runs in browser and we have <a id="quirk"></a> somewhere, you can:
var quirkLink = document.getElementById("quirk");
quirkLink.setAttr("href", quirkLink);

About simulator algorithm

Memory usage: up to 2 * (2^numQubits) * sizeOfComplexNumber

  • Naive implementation stores entire state vector in an array of size 2^numQubits. We are storing state in a "map", and only amplitudes with non-zero probabilities are stored. So, in worst case, size of state map is 2^n, but it's less most of the time because we don't store zeroes.

  • Naive implementation creates transformation matrix and multiplies it with state vector. We are not creating and not storing entire transformation matrix in memory. Instead, elements of transformation matrix are calculated one by one and state is multiplied and stored in new state map on the fly. This way, memory usage is minimal (in worst case we have two 2^n state vectors at a time).

  • Algorithm is parallelizable so it could use GPU, but GPU support is not implemented yet (work in progress).

Benchmark

Performance is measured on MacBook Pro MJLT2 mid-2015 (Core i7 2.5 GHz, 16GB RAM)

Benchmark 1

Benchmark 2

Benchmark 3

You can find scripts in /benchmark directory.

Gates

id

Single qubit identity gate

Qubits: 1

Matrix:

[

    [1,0],
    [0,1]
]

Example:

circuit.appendGate("id", 0);

x

Pauli X (PI rotation over X-axis) aka "NOT" gate

Qubits: 1

Matrix:

[

    [0,1],
    [1,0]
]

Example:

circuit.appendGate("x", 0);

y

Pauli Y (PI rotation over Y-axis)

Qubits: 1

Matrix:

[

    [0,"-i"],
    ["i",0]
]

Example:

circuit.appendGate("y", 0);

z

Pauli Z (PI rotation over Z-axis)

Qubits: 1

Matrix:

[

    [1,0],
    [0,-1]
]

Example:

circuit.appendGate("z", 0);

h

Hadamard gate

Qubits: 1

Matrix:

[

    ["1 / sqrt(2)","1 / sqrt(2)"],
    ["1 / sqrt(2)","-1 / sqrt(2)"]
]

Example:

circuit.appendGate("h", 0);

srn

Square root of NOT

Qubits: 1

Matrix:

[

    ["0.5+0.5i","0.5-0.5i"],
    ["0.5-0.5i","0.5+0.5i"]
]

Example:

circuit.appendGate("srn", 0);

srndg

Inverse square root of NOT

Qubits: 1

Matrix:

[

    ["0.5-0.5i","0.5+0.5i"],
    ["0.5+0.5i","0.5-0.5i"]
]

Example:

circuit.appendGate("srndg", 0);

r2

PI/2 rotation over Z-axis aka "Phase PI/2"

Qubits: 1

Matrix:

[

    [1,0],
    [0,"exp(i * pi / 2)"]
]

Example:

circuit.appendGate("r2", 0);

r4

PI/4 rotation over Z-axis aka "Phase PI/4"

Qubits: 1

Matrix:

[

    [1,0],
    [0,"exp(i * pi / 4)"]
]

Example:

circuit.appendGate("r4", 0);

r8

PI/8 rotation over Z-axis aka "Phase PI/8"

Qubits: 1

Matrix:

[

    [1,0],
    [0,"exp(i * pi / 8)"]
]

Example:

circuit.appendGate("r8", 0);

rx

Rotation around the X-axis by given angle

Qubits: 1

Parameters:

  • theta

Matrix:

[

    ["cos(theta / 2)","-i * sin(theta / 2)"],
    ["-i * sin(theta / 2)","cos(theta / 2)"]
]

Example:

circuit.appendGate("rx", 0, {
    params: {
        theta: "pi/2"
    }
});

ry

Rotation around the Y-axis by given angle

Qubits: 1

Parameters:

  • theta

Matrix:

[

    ["cos(theta / 2)","-1 * sin(theta / 2)"],
    ["sin(theta / 2)","cos(theta / 2)"]
]

Example:

circuit.appendGate("ry", 0, {
    params: {
        theta: "pi/2"
    }
});

rz

Rotation around the Z-axis by given angle

Qubits: 1

Parameters:

  • phi

Matrix:

[

    ["cos(phi / 2) - i * sin(phi / 2)",0],
    [0,"cos(phi / 2) + i * sin(phi / 2)"]
]

Example:

circuit.appendGate("rz", 0, {
    params: {
        phi: "pi/2"
    }
});

u1

Single-qubit rotation about the Z axis

Qubits: 1

Parameters:

  • lambda

Matrix:

[

    [1,0],
    [0,"exp(i * lambda)"]
]

Example:

circuit.appendGate("u1", 0, {
    params: {
        lambda: "pi/2"
    }
});

u2

Single-qubit rotation about the X+Z axis

Qubits: 1

Parameters:

  • phi
  • lambda

Matrix:

[

    ["1 / sqrt(2)","-exp(i * lambda) * 1 / sqrt(2)"],
    ["exp(i * phi) * 1 / sqrt(2)","exp(i * lambda + i * phi) * 1 / sqrt(2)"]
]

Example:

circuit.appendGate("u2", 0, {
    params: {
        phi: "pi/2",
        lambda: "pi/2"
    }
});

u3

Generic single-qubit rotation gate with 3 Euler angles

Qubits: 1

Parameters:

  • theta
  • phi
  • lambda

Matrix:

[

    ["cos(theta/2)","-exp(i * lambda) * sin(theta / 2)"],
    ["exp(i * phi) * sin(theta / 2)","exp(i * lambda + i * phi) * cos(theta / 2)"]
]

Example:

circuit.appendGate("u3", 0, {
    params: {
        theta: "pi/2",
        phi: "pi/2",
        lambda: "pi/2"
    }
});

s

PI/2 rotation over Z-axis (synonym for r2)

Qubits: 1

Matrix:

[

    [1,0],
    [0,"i"]
]

Example:

circuit.appendGate("s", 0);

t

PI/4 rotation over Z-axis (synonym for r4)

Qubits: 1

Matrix:

[

    [1,0],
    [0,"exp(i * pi / 4)"]
]

Example:

circuit.appendGate("t", 0);

sdg

(-PI/2) rotation over Z-axis

Qubits: 1

Matrix:

[

    [1,0],
    [0,"-i"]
]

Example:

circuit.appendGate("sdg", 0);

tdg

(-PI/4) rotation over Z-axis

Qubits: 1

Matrix:

[

    [1,0],
    [0,"exp(-i * pi / 4)"]
]

Example:

circuit.appendGate("tdg", 0);

gpi

GPi gate

Qubits: 1

Parameters:

  • phi

Matrix:

[

    [0,"exp(-i*phi)"],
    ["exp(i*phi)",0]
]

Example:

circuit.appendGate("gpi", 0, {
    params: {
        phi: "pi/2"
    }
});

gpi2

GPi2 gate

Qubits: 1

Parameters:

  • phi

Matrix:

[

    ["1/sqrt(2)","(-i*exp(-i*phi))/sqrt(2)"],
    ["(-i*exp(i*phi))/sqrt(2)","1/sqrt(2)"]
]

Example:

circuit.appendGate("gpi2", 0, {
    params: {
        phi: "pi/2"
    }
});

vz

VirtualZ gate

Qubits: 1

Parameters:

  • theta

Matrix:

[

    ["exp(-i*theta/2)",0],
    [0,"exp(i*theta/2)"]
]

Example:

circuit.appendGate("vz", 0, {
    params: {
        theta: "pi/2"
    }
});

cx

Controlled NOT (CNOT) gate

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,0,1],
    [0,0,1,0]
]

Example:

circuit.appendGate("cx", [0, 1]);

cy

Controlled Y gate (controlled rotation over Y-axis by PI)

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,0,"-i"],
    [0,0,"i",0]
]

Example:

circuit.appendGate("cy", [0, 1]);

cz

Controlled Z gate (controlled rotation over Z-axis by PI)

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,1,0],
    [0,0,0,-1]
]

Example:

circuit.appendGate("cz", [0, 1]);

ch

Controlled Hadamard gate

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,"1 / sqrt(2)","1 / sqrt(2)"],
    [0,0,"1 / sqrt(2)","-1 / sqrt(2)"]
]

Example:

circuit.appendGate("ch", [0, 1]);

csrn

Controlled square root of NOT

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,"0.5+0.5i","0.5-0.5i"],
    [0,0,"0.5-0.5i","0.5+0.5i"]
]

Example:

circuit.appendGate("csrn", [0, 1]);

swap

Swaps the state of two qubits.

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,0,1,0],
    [0,1,0,0],
    [0,0,0,1]
]

Example:

circuit.appendGate("swap", [0, 1]);

srswap

Square root of swap

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,"0.5 * (1 + i)","0.5 * (1 - i)",0],
    [0,"0.5 * (1 - i)","0.5 * (1 + i)",0],
    [0,0,0,1]
]

Example:

circuit.appendGate("srswap", [0, 1]);

iswap

Swaps the state of two qubits, applying a -i phase to q1 when it is in the 1 state and a -i phase to q2 when it is in the 0 state

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,0,"0+i",0],
    [0,"0+i",0,0],
    [0,0,0,1]
]

Example:

circuit.appendGate("iswap", [0, 1]);

xx

XX gate

Qubits: 2

Parameters:

  • theta

Matrix:

[

    ["cos(theta)",0,0,"-i*sin(theta)"],
    [0,"cos(theta)","-i*sin(theta)",0],
    [0,"-i*sin(theta)","cos(theta)",0],
    ["-i*sin(theta)",0,0,"cos(theta)"]
]

Example:

circuit.appendGate("xx", [0, 1], {
    params: {
        theta: "pi/2"
    }
});

yy

YY gate

Qubits: 2

Parameters:

  • theta

Matrix:

[

    ["cos(theta)",0,0,"i*sin(theta)"],
    [0,"cos(theta)","-i*sin(theta)",0],
    [0,"-i*sin(theta)","cos(theta)",0],
    ["i*sin(theta)",0,0,"cos(theta)"]
]

Example:

circuit.appendGate("yy", [0, 1], {
    params: {
        theta: "pi/2"
    }
});

zz

Parametric 2-qubit rotation about ZZ

Qubits: 2

Parameters:

  • theta

Matrix:

[

    ["exp(-i * theta / 2)",0,0,0],
    [0,"exp(i * theta / 2)",0,0],
    [0,0,"exp(i * theta / 2)",0],
    [0,0,0,"exp(-i * theta / 2)"]
]

Example:

circuit.appendGate("zz", [0, 1], {
    params: {
        theta: "pi/2"
    }
});

xy

XY gate

Qubits: 2

Parameters:

  • phi

Matrix:

[

    [1,0,0,0],
    [0,"cos(phi / 2)","i * sin(phi / 2)",0],
    [0,"i * sin(phi / 2)","cos(phi / 2)",0],
    [0,0,0,1]
]

Example:

circuit.appendGate("xy", [0, 1], {
    params: {
        phi: "pi/2"
    }
});

ms

Mølmer-Sørensen gate

Qubits: 2

Parameters:

  • phi0
  • phi1

Matrix:

[

    ["1/sqrt(2)",0,0,"(-i*exp(-i*(phi0+phi1)))/sqrt(2)"],
    [0,"1/sqrt(2)","(-i*exp(-i*(phi0-phi1)))/sqrt(2)",0],
    [0,"(-i*exp(i*(phi0-phi1)))/sqrt(2)","1/sqrt(2)",0],
    ["(-i*exp(i*(phi0+phi1)))/sqrt(2)",0,0,"1/sqrt(2)"]
]

Example:

circuit.appendGate("ms", [0, 1], {
    params: {
        phi0: "pi/2",
        phi1: "pi/2"
    }
});

cr2

Controlled PI/2 rotation over Z-axis

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,1,0],
    [0,0,0,"exp(i * pi / 2)"]
]

Example:

circuit.appendGate("cr2", [0, 1]);

cr4

Controlled PI/4 rotation over Z-axis

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,1,0],
    [0,0,0,"exp(i * pi / 4)"]
]

Example:

circuit.appendGate("cr4", [0, 1]);

cr8

Controlled PI/8 rotation over Z-axis

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,1,0],
    [0,0,0,"exp(i * pi / 8)"]
]

Example:

circuit.appendGate("cr8", [0, 1]);

crx

Controlled rotation around the X-axis by given angle

Qubits: 2

Parameters:

  • theta

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,"cos(theta / 2)","-i * sin(theta / 2)"],
    [0,0,"-i * sin(theta / 2)","cos(theta / 2)"]
]

Example:

circuit.appendGate("crx", [0, 1], {
    params: {
        theta: "pi/2"
    }
});

cry

Controlled rotation around the Y-axis by given angle

Qubits: 2

Parameters:

  • theta

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,"cos(theta / 2)","-1 * sin(theta / 2)"],
    [0,0,"sin(theta / 2)","cos(theta / 2)"]
]

Example:

circuit.appendGate("cry", [0, 1], {
    params: {
        theta: "pi/2"
    }
});

crz

Controlled rotation around the Z-axis by given angle

Qubits: 2

Parameters:

  • phi

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,"cos(phi / 2) - i * sin(phi / 2)",0],
    [0,0,0,"cos(phi / 2) + i * sin(phi / 2)"]
]

Example:

circuit.appendGate("crz", [0, 1], {
    params: {
        phi: "pi/2"
    }
});

cu1

Controlled rotation about the Z axis

Qubits: 2

Parameters:

  • lambda

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,1,0],
    [0,0,0,"exp(i * lambda)"]
]

Example:

circuit.appendGate("cu1", [0, 1], {
    params: {
        lambda: "pi/2"
    }
});

cu2

Controlled rotation about the X+Z axis

Qubits: 2

Parameters:

  • phi
  • lambda

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,"1 / sqrt(2)","-exp(i * lambda) * 1 / sqrt(2)"],
    [0,0,"exp(i * phi) * 1 / sqrt(2)","exp(i * lambda + i * phi) * 1 / sqrt(2)"]
]

Example:

circuit.appendGate("cu2", [0, 1], {
    params: {
        phi: "pi/2",
        lambda: "pi/2"
    }
});

cu3

Controlled rotation gate with 3 Euler angles

Qubits: 2

Parameters:

  • theta
  • phi
  • lambda

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,"cos(theta/2)","-exp(i * lambda) * sin(theta / 2)"],
    [0,0,"exp(i * phi) * sin(theta / 2)","exp(i * lambda + i * phi) * cos(theta / 2)"]
]

Example:

circuit.appendGate("cu3", [0, 1], {
    params: {
        theta: "pi/2",
        phi: "pi/2",
        lambda: "pi/2"
    }
});

cs

Controlled PI/2 rotation over Z-axis (synonym for cr2)

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,1,0],
    [0,0,0,"i"]
]

Example:

circuit.appendGate("cs", [0, 1]);

ct

Controlled PI/4 rotation over Z-axis (synonym for cr4)

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,1,0],
    [0,0,0,"exp(i * pi / 4)"]
]

Example:

circuit.appendGate("ct", [0, 1]);

csdg

Controlled (-PI/2) rotation over Z-axis

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,1,0],
    [0,0,0,"-i"]
]

Example:

circuit.appendGate("csdg", [0, 1]);

ctdg

Controlled (-PI/4) rotation over Z-axis

Qubits: 2

Matrix:

[

    [1,0,0,0],
    [0,1,0,0],
    [0,0,1,0],
    [0,0,0,"exp(-i * pi / 4)"]
]

Example:

circuit.appendGate("ctdg", [0, 1]);

ccx

Toffoli aka "CCNOT" gate

Qubits: 3

Matrix:

[

    [1,0,0,0,0,0,0,0],
    [0,1,0,0,0,0,0,0],
    [0,0,1,0,0,0,0,0],
    [0,0,0,1,0,0,0,0],
    [0,0,0,0,1,0,0,0],
    [0,0,0,0,0,1,0,0],
    [0,0,0,0,0,0,0,1],
    [0,0,0,0,0,0,1,0]
]

Example:

circuit.appendGate("ccx", [0, 1, 2]);

cswap

Controlled swap aka "Fredkin" gate

Qubits: 3

Matrix:

[

    [1,0,0,0,0,0,0,0],
    [0,1,0,0,0,0,0,0],
    [0,0,1,0,0,0,0,0],
    [0,0,0,1,0,0,0,0],
    [0,0,0,0,1,0,0,0],
    [0,0,0,0,0,0,1,0],
    [0,0,0,0,0,1,0,0],
    [0,0,0,0,0,0,0,1]
]

Example:

circuit.appendGate("cswap", [0, 1, 2]);

csrswap

Controlled square root of swap

Qubits: 3

Matrix:

[

    [1,0,0,0,0,0,0,0],
    [0,1,0,0,0,0,0,0],
    [0,0,1,0,0,0,0,0],
    [0,0,0,1,0,0,0,0],
    [0,0,0,0,1,0,0,0],
    [0,0,0,0,0,"0.5 * (1 + i)","0.5 * (1 - i)",0],
    [0,0,0,0,0,"0.5 * (1 - i)","0.5 * (1 + i)",0],
    [0,0,0,0,0,0,0,1]
]

Example:

circuit.appendGate("csrswap", [0, 1, 2]);

reset

Resets qubit

Qubits: 1

Example:

circuit.appendGate("reset", 0);

measure

Measures qubit and stores chance (0 or 1) into classical bit

Qubits: 1

Example:

circuit.appendGate("measure", 0, {
    creg: {
        name: "c",
        bit: 3
    }
});

Or:

circuit.addMeasure(0, "c", 3);

API docs

To be written...

License

MIT

quantum-circuit's People

Contributors

dependabot[bot] avatar dmvjs avatar kaustuvi avatar nemanja-n avatar perak avatar schmeichelinho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

quantum-circuit's Issues

Hadamard Gate's probability

I'm not sure I'm using this correctly, but I think there is some problem in hadamard gate.
When I apply hadamard gate to every qubits and run them, they are mostly zero.

var qubitSystem = new QuantumCircuit(10);
qubitSystem.addGate("h", 1, [0,1,2,3,4,5,6,7,8,9]);
qubitSystem.run();
console.log(qubitSystem.measureAll());

This mostly returns zero-filled list.
I know this is just a simulator, but I'm using this for my project, which includes some sort of Quantum Randint Generator.
Could you please consider changing some probabilities of hadamard gate, when I measure them?

Adding classical control

Any chance of adding classical control to circuits in the editor? This is often a great way of comparing QASM and Quil and takes some of the most effort to convert.

problem with U3 gate

OPENQASM 2.0;
include "qelib1.inc";
qreg q[8];
creg c[1];
x q[0];
u1 (pi/6) q[1];
z q[2];
ry (pi/6) q[3];
rz (0) q[4];
s q[5];
srswap q[6], q[7];
h q[0];
u2 (0, pi/7) q[1];
h q[2];
u1 (pi/2) q[3];
u2 (pi/11, 0) q[4];
sdg q[5];
tdg q[6];
y q[0];
srn q[1];
u1 (pi/4) q[2];
u1 (pi/8) q[3];
t q[4];
ms (0) q[6], q[7];
u2 (0, 0) q[5];
ms (pi/7) q[0], q[2];
u1 (0) q[3];
#u3 (1, 2, 3) q[4];
swap q[5], q[6];
srswap q[3], q[7];
srswap q[6], q[1];

In above circuit, when I uncomment the U3 gate, the states of other qubits changes, which is obviously wrong because U3 gate only apply to q[4].

I see you have fixed the U2 gate and I think the U3 gate may have the same issue with U2.

Get unitary matrix of the circuit

It would be great if QuantumCircuit had a method to query the unitary matrix of the whole circuit.

After it will be implemented this matrix could be shown on the Quantum Programming Studio simulation page.

Bloch sphere plot wrong

The Bell state prepared by this circuit should have a (0,0,0) bloch sphere on each qubits. But the plots of the simulated results shows a pure state on each qubits.

About the signed bitgate parameter

In some angular bitgates, when the parameter with the negative sign is used, the bitgate in the graph disappears, and so does the data. What is the problem

the problem on simulating of the BV algorithm

Dear Sir,
Today, I have tried the BV algorithm as discussed in P12 of arXiv:1804.03719v1. The result is quite strange, the probabilities are huge numbers larger than 1. The quantum circuit is as follows. I suppose that there are some problems in these related gates. Could you give a test on this circuit?
OPENQASM 2.0;
include "qelib1.inc";
qreg q[3];
creg c[2];
h q[0];
h q[1];
x q[2];
h q[0];
x q[1];
h q[2];
u2 (0, -1.5708) q[2];
cx q[2], q[0];
u3 (0.785398, 0, 0) q[2];
cx q[2], q[0];
u2 (0.785398, -3.14159) q[0];
u3 (2.35619, 3.14159, 0) q[2];
cx q[1], q[0];
h q[0];
cx q[2], q[0];
u3 (0.785398, 0, 0) q[2];
cx q[2], q[0];
u2 (-0.785398, 3.14159) q[0];
u3 (2.35619, -3.14159, 0) q[2];
cx q[1], q[0];
h q[0];
h q[1];
cx q[2], q[1];
u3 (0.785398, 0, 0) q[2];
cx q[2], q[1];
u2 (-0.785398, 0) q[1];
u3 (0.785398, -3.14159, 0) q[2];
cx q[2], q[0];
u3 (0.785398, 0, 0) q[2];
cx q[2], q[0];
u2 (0.785398, -3.14159) q[0];
u3 (2.35619, 3.14159, 0) q[2];
cx q[1], q[0];
h q[0];
cx q[2], q[0];
u3 (0.785398, 0, 0) q[2];
cx q[2], q[0];
u2 (-0.785398, -3.14159) q[0];
u3 (2.53619, -3.14159, 0) q[2];
cx q[1], q[0];
h q[0];
h q[1];
cx q[2], q[1];
u3 (0.785398, 0, 0) q[2];
cx q[2], q[1];
u2 (0.785398, -3.14159) q[1];
u3 (2.35619, -1.5708, 0) q[2];
h q[1];
measure q[0] -> c[0];
measure q[1] -> c[1];

Interactive measurements: not clear if possible/how to do

Hello,

First thanks for this promising package. I'm trying to implement an interactive circuit, in which the user can say in real time the operations to do depending on the previous measurements outcome (NB: it's different from conditional gate as it is really interactive):

  • please measure qubit 0.
  • The result is 1. What do you want to do?
  • Oh, I'd like to see, what happens now if I measure qubit 1 ?
  • The result is 1.

I tried to use the measure operation to implement a basic measurement of a bell pair (expect 00 or 11 outcome), but does not work as I expect (always 00 outcome, no 11), so I guess I missed something. Is it a bug, or did I missed something?

I saw that there is the measure gate, but I'm affraid by the warning Measurement gate will reset qubit to measured value only if there are gates with classical control, as here, I really want to collapse the state after the first measurement, otherwise I'll get inconsistent measurements.

<!doctype html>
<html>
  <head>
    <title>Measure bell state </title>
    <meta charset="UTF-8">
  </head>
  <body>
    <script type="text/javascript" src="https://unpkg.com/quantum-circuit"></script> 
    
    <script type="text/javascript">
      for(let i=0; i < 10; i++) { // Repeat the circuit 10 times to see if the probability is the expected one: Pb: only 00 outcome, no 11
          console.log("=== New game: expect sometimes outcome 00, sometimes 11");
          circuit = new QuantumCircuit();
          circuit.addGate("h", -1, [0]);
          circuit.addGate("cx", -1, [0, 1]);
          console.log("Alice will measure")
          console.log(circuit.measure(0))
          console.log("Now bob will measure")
          console.log(circuit.measure(1))
      }
    </script> 
  </body>
</html>

Probabilities can be truncated to 0.00000% in stateAsString(true)

Not necessarily an issue - perhaps an enhancement though. Due to the truncation (or maybe rounding - haven't looked behind the scenes) some probabilities (as well as vector values) for viable states end up being output as 0.

Example program:

const QuantumCircuit = require('quantum-circuit');

let qc = new QuantumCircuit();
let qasm = "OPENQASM 2.0;\n" +
           "include \"qelib1.inc\";\n" +
           "qreg r1[1];\n" +
           "rx(0.0000000001) r1;\n";

qc.importQASM(qasm, (error) => {
    qc.run();
    console.log(qc.stateAsString(true));
})

Output:

 1.00000000+0.00000000i|0>	100.00000%
 0.00000000+0.00000000i|1>	  0.00000%

Export to Cirq - classical control is not implemented

Good example is teleportation circuit:

QASM:

OPENQASM 2.0;
include "qelib1.inc";
qreg q[3];
creg c0[1];
creg c1[1];
rx (pi/4) q[0];
h q[1];
cx q[1], q[2];
cx q[0], q[1];
h q[0];
measure q[1] -> c1[0];
if(c1==1) x q[2];
measure q[0] -> c0[0];
if(c0==1) z q[2];

When exported to Cirq, code currently looks like this:

import cirq
import numpy as np

q = [cirq.NamedQubit('q' + str(i)) for i in range(3)]

circuit = cirq.Circuit.from_ops(
    cirq.Rx(np.pi / 4)(q[0]),
    cirq.H(q[1]),
    cirq.CNOT(q[1], q[2]),
    cirq.CNOT(q[0], q[1]),
    cirq.H(q[0]),
    cirq.measure(q[1], key='c10'),

    # Export to cirq WARNING: classical control not implemented yet.
    cirq.X(q[2]),

    cirq.measure(q[0], key='c00'),

    # Export to cirq WARNING: classical control not implemented yet.
    cirq.Z(q[2])
)

simulator = cirq.Simulator()
result = simulator.run(circuit)
print(result)

problem with u2 gate

OPENQASM 2.0;
include "qelib1.inc";
qreg q[1];
creg c[1];
h q[0];
u2 (0, 0) q[0];
u2 (0, 0) q[0];
u2 (0, 0) q[0];
u2 (0, 0) q[0];
u2 (0, 0) q[0];
measure q[0] -> c[0];

Please note that above circuit gives the result 16 by using quantum circuit, which is obviously wrong.

Error at First Access to Quantum-Circuit.COM using QPS Client

My runtime platform is Intel Ubuntu Linux 17 with Anaconda Python 3.6

Installing and Testing Quantum-Circuit API
Installation according instructions was OK
Upgrade of Rigetti forest SDK 2.2.2 and Pyquil was OK

Simulation of a small circuit via web was OK (Hadamard & CNOT entanglement 50%, 50%) is OK
Qubit Measured Probability
q0 0 0.5
q1 0 0.5

Starting the daemon manually at Anaconda Linux Console with environment set to Python 3.6
qps-client --backends rigetti-qvm

Log:

Quantum Programming Studio Client
Connected.
Account: [email protected]
Password:
Login successful.
Backends:
rigetti-qvm

Web GUI

Run on Rigetti QCS or Forest SDK
QMI 131.0.217.166
Test on QVM

Error message:
During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/claude/anaconda3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 600, in urlopen
chunked=chunked)
File "/home/claude/anaconda3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 354, in _make_request
conn.request(method, url, **httplib_request_kw)
File "/home/claude/anaconda3/lib/python3.6/http/client.py", line 1239, in request
self._send_request(method, url, body, headers, encode_chunked)
File "/home/claude/anaconda3/lib/python3.6/http/client.py", line 1285, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/home/claude/anaconda3/lib/python3.6/http/client.py", line 1234, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "/home/claude/anaconda3/lib/python3.6/http/client.py", line 1026, in _send_output
self.send(msg)
File "/home/claude/anaconda3/lib/python3.6/http/client.py", line 964, in send
self.connect()
File "/home/claude/anaconda3/lib/python3.6/site-packages/urllib3/connection.py", line 181, in connect
conn = self._new_conn()
File "/home/claude/anaconda3/lib/python3.6/site-packages/urllib3/connection.py", line 168, in _new_conn
self, "Failed to establish a new connection: %s" % e)
urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPConnection object at 0x7fa09c95c630>: Failed to establish a new connection: [Errno 111] Connection refused

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/claude/anaconda3/lib/python3.6/site-packages/requests/adapters.py", line 449, in send
timeout=timeout
File "/home/claude/anaconda3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 667, in urlopen
**response_kw)
File "/home/claude/anaconda3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 667, in urlopen
**response_kw)
File "/home/claude/anaconda3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 667, in urlopen
**response_kw)
File "/home/claude/anaconda3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 638, in urlopen
_stacktrace=sys.exc_info()[2])
File "/home/claude/anaconda3/lib/python3.6/site-packages/urllib3/util/retry.py", line 398, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='127.0.0.1', port=5000): Max retries exceeded with url: /qvm (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fa09c95c630>: Failed to establish a new connection: [Errno 111] Connection refused',))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "", line 15, in
File "/home/claude/anaconda3/lib/python3.6/site-packages/pyquil/api/_error_reporting.py", line 238, in wrapper
val = func(*args, **kwargs)
File "/home/claude/anaconda3/lib/python3.6/site-packages/pyquil/api/_quantum_computer.py", line 152, in run
return self.qam.run()
File "/home/claude/anaconda3/lib/python3.6/site-packages/pyquil/api/_error_reporting.py", line 238, in wrapper
val = func(*args, **kwargs)
File "/home/claude/anaconda3/lib/python3.6/site-packages/pyquil/api/_qvm.py", line 481, in run
random_seed=self.random_seed)['ro']
File "/home/claude/anaconda3/lib/python3.6/site-packages/pyquil/api/_error_reporting.py", line 238, in wrapper
val = func(*args, **kwargs)
File "/home/claude/anaconda3/lib/python3.6/site-packages/pyquil/api/_base_connection.py", line 362, in _qvm_run
response = post_json(self.session, self.sync_endpoint + "/qvm", payload)
File "/home/claude/anaconda3/lib/python3.6/site-packages/pyquil/api/_base_connection.py", line 56, in post_json
res = session.post(url, json=json)
File "/home/claude/anaconda3/lib/python3.6/site-packages/requests/sessions.py", line 581, in post
return self.request('POST', url, data=data, json=json, **kwargs)
File "/home/claude/anaconda3/lib/python3.6/site-packages/requests/sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "/home/claude/anaconda3/lib/python3.6/site-packages/requests/sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "/home/claude/anaconda3/lib/python3.6/site-packages/requests/adapters.py", line 516, in send
raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='127.0.0.1', port=5000): Max retries exceeded with url: /qvm (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fa09c95c630>: Failed to establish a new connection: [Errno 111] Connection refused',))


Looks like some local environment issue between the Firefox browser and Python.
Any hints how to fix this API connection is welcome.
Regards, Claude

Variables are not defined before use

qWireY, qGateY, cWireY in QuantumCircuit class are never defined before use. This is causing error when building the package.

They could be fixed by adding var before qWireY, qGateY, cWireY at line 7445, line 7449, line 7453 in /dist/quantum-circuit.js file

CNOT Gate is Not in Menu

Why is my CNOT Gate not displayed in the drag and drop menu?
Everything else seems to be fine.
Thanks

Quantum_Classical Export

Quantum Classical export is not working as expected. Whatever you choose for optimizer in exported code you only get the "Powell".
SharedScreenshot
image

Simulation error in Bloch sphere

In this circuit
the Bloch sphere of each qubits seems to be wrong. The circuit should show

s q2;
cx q1, q2;
sdag q2;

is equivalent to CY q1, q2 (comparing the q0,q1 and q2,q3).
However, the Bloch spheres seem to disagree.

Repository of Examples to Illustrate Quantum Programming Concepts

I've been on a mission lately to create lots of quantum computing examples in JavaScript. I had been using dabbling with qcsimulator, qics, and jsqubits but I finally settled on embedding a pared down version of quantum circuit.

I'm working with the O'Reilly book "Programming Quantum Computers", QASM examples, and anything I can comprehend online. These are some examples I've created so far which have not been reviewed. I did see this recent bug report and I'll need to review whether or not I have hacked around this bug or not. I may eventually re-integrate with the full Quantum Circuit library but this is just what I have so far.

The examples are in my Github repository.

Long Identifiers(?) Crash when Importing from QASM

I get an odd crash when importing QASM where there is a register with a long identifier. To reproduce the following code works:

const QuantumCircuit = require('quantum-circuit');

let qc = new QuantumCircuit();
let qasm = "OPENQASM 2.0;\n" +
           "include \"qelib1.inc\";\n" +
           "gate cphase_281472532(param0) q0,q1 {  }\n" +
           "qreg r1[2];\n" +
           "cphase_281472532() r1[1],r1[0];";

qc.importQASM(qasm, (error) => {
    qc.run();
})

And produces this stack trace:


<--- Last few GCs --->

[32091:0xaaaaee353860]     1369 ms: Scavenge 1163.0 (1196.4) -> 1163.0 (1196.4) MB, 32.7 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure
[32091:0xaaaaee353860]     2255 ms: Mark-sweep 1736.9 (1770.2) -> 1723.7 (1758.4) MB, 471.0 / 0.7 ms  (+ 18.4 ms in 10 steps since start of marking, biggest step 7.5 ms, walltime since start of marking 1757 ms) (average mu = 0.751, current mu = 0.751) all

<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 0xffffad358dec]
Security context: 0x0000256db9a1 <JSObject>
    1: /* anonymous */ [0x5d6cb839] [/python_js_test/node_modules/quantum-circuit/lib/quantum-circuit.js:~6162] [pc=0x28576888](this=0x0000347454e1 <QuantumCircuit map = 0xffffa24dee39>,0x0000385666b1 <String[#16]: cphase_281472532>)
    2: /* anonymous */ [0x5d6cb8b9] [/python_js_test/node_modules/quantum-circuit/lib/quantum-circuit.js:6237] [bytecode=0x385...

FATAL ERROR: invalid array length Allocation failed - JavaScript heap out of memory
 1: 0xffffac5df720 node::Abort() [/lib/aarch64-linux-gnu/libnode.so.72]
 2: 0xffffac5218d8 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > node::SPrintF<>(char const*) [/lib/aarch64-linux-gnu/libnode.so.72]
 3: 0xffffac8fded8 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/lib/aarch64-linux-gnu/libnode.so.72]
 4: 0xffffac8fe08c v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/lib/aarch64-linux-gnu/libnode.so.72]
 5: 0xffffaca9e668  [/lib/aarch64-linux-gnu/libnode.so.72]
 6: 0xffffaca7925c v8::internal::Factory::AllocateRawFixedArray(int, v8::internal::AllocationType) [/lib/aarch64-linux-gnu/libnode.so.72]
 7: 0xffffaca79710 v8::internal::Factory::NewFixedArrayWithFiller(v8::internal::RootIndex, int, v8::internal::Object, v8::internal::AllocationType) [/lib/aarch64-linux-gnu/libnode.so.72]
 8: 0xffffaca7a008 v8::internal::Factory::NewUninitializedFixedArray(int, v8::internal::AllocationType) [/lib/aarch64-linux-gnu/libnode.so.72]
 9: 0xffffacbd45a0  [/lib/aarch64-linux-gnu/libnode.so.72]
10: 0xffffacd73474 v8::internal::Runtime_GrowArrayElements(int, unsigned long*, v8::internal::Isolate*) [/lib/aarch64-linux-gnu/libnode.so.72]
11: 0xffffad358dec  [/lib/aarch64-linux-gnu/libnode.so.72]
Aborted

Oddly, it seems that changing the identifier from cphase_281472532 to cphase_28147253 makes the code run fine. It seems there's some code splitting at the _ so perhaps this is expected behaviour?

Matrix of S Gate

The matrix representation of the S Gate as given in https://www.quantum-inspire.com/kbase/s-gate/ is
Screenshot 2024-07-10 at 6 34 04 PM

But i see that the definition of matrix of S gate is different in the library.

How to Reproduce ?

Create circuit with gates applied in following order XHSS and XHZ gate since result of applying SS and Z gates are equivalent. the results should be the same.
But the results diverge and so do their states:

{
  '0': { re: 0.7071067811865475, im: 0 },
  '1': { re: 0.7071067811865475, im: -8.659560562354932e-17 }
} // States with SS gate
{
  '0': { re: 0.7071067811865475, im: 0 },
  '1': { re: 0.7071067811865475, im: 0 }
} // States with Z gate
import QuantumCircuit from 'quantum-circuit';


var ss = new QuantumCircuit();
ss.addGate("h", 0,0) // Apply this so that imaginary part is accounted
ss.addGate("s", 1,0)
ss.addGate("s", 2,0)


var z = new QuantumCircuit();
z.addGate("h", 0,0) // Apply this so that imaginary part is accounted
z.addGate("z", 1, 0)
for(let circuit of [ss, z]) {
  const shots = 100;
  const results = {};
  for (let i = 0; i < shots; i++) {
      circuit.run([true]);
      const measuredState = circuit.measureAll();
      const bitstring = measuredState.map(bit => bit ? '1' : '0').join('');
      if (!results[bitstring]) {
          results[bitstring] = 0;
      }
      results[bitstring]++;
  }
  console.log(results)
}

Results

{ '0': 50, '1': 50 }
{ '0': 40, '1': 60 }

Cirq Circuit requires `device` parameter in order to use XmonSimulator

I am creating a simple circuit as follows:


var circ = new QuantumCircuit();

circ.addGate("h", -1, 0);
circ.addGate("cx", -1, [0, 1]);

circ.run();

console.log("");
console.log(circ.exportCirq());

The exported program generated by quantum-circuit.js is this:

import cirq
import numpy as np

q = [cirq.NamedQubit('q' + str(i)) for i in range(2)]

circuit = cirq.Circuit.from_ops(
    cirq.H(q[0]),
    cirq.CNOT(q[0], q[1]),
    cirq.measure(q[0], key='c0')
)

simulator = cirq.google.XmonSimulator()
result = simulator.run(circuit)
print(result)

However, when I run the exported program in Cirq, it gives me the following error:

  File ".\src\pragma_test.py", line 12, in <module>
    result = simulator.run(circuit)
  File "C:\Users\Kaustuvi\Anaconda3\lib\site-packages\cirq\sim\sampler.py", line 42, in run
    repetitions)[0]
  File "C:\Users\Kaustuvi\Anaconda3\lib\site-packages\cirq\sim\simulator.py", line 73, in run_sweep
    repetitions=repetitions)
  File "C:\Users\Kaustuvi\Anaconda3\lib\site-packages\cirq\google\sim\xmon_simulator.py", line 153, in _run
    _verify_xmon_circuit(circuit)
  File "C:\Users\Kaustuvi\Anaconda3\lib\site-packages\cirq\google\sim\xmon_simulator.py", line 97, in _verify_xmon_circuit
    raise ValueError("XmonSimulator only accepts circuits "
ValueError: XmonSimulator only accepts circuits using an XmonDevice. Maybe you forgot to pass a `device=` parameter into `cirq.Circuit`, or intended to set `new_device=` in your call to `cirq.google.optimized_for_xmon`? Alternatively, maybe you intended to use `cirq.Simulator()` instead?

Basically, Circuit requires the device parameter in order to use XmonSimulator. Perhaps, we could use cirq.Simulator() instead of XmonSimulator? Also, if we are using simulator.run(), the user needs to explicitly add measurement operations, otherwise the simulator can return empty measurements.
Please let me know if I am missing anything.

Classical control gives wrong results

When gate is controlled by classical register, measurement gives correct results, but probabilities and state vector are not correct.

Example circuit:

OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[1];
h q[0];
measure q[0] -> c[0];
if(c==1) x q[1];

Result of measurement is correct: [0, 0] or [1, 1]

Probabilities are wrong:

[0.5, 0] or [0.5, 1]

Expected is:

[0, 0] or [1, 1]

State is wrong. It returns:

0.70710680+0.00000000i|00>	50.00000%
0.70710680+0.00000000i|10>	50.00000%

OR

0.70710680+0.00000000i|11>	50.00000%
0.70710680+0.00000000i|10>	50.00000%

But expected is:

0.70710680+0.00000000i|00>	100.00000%

OR

0.70710680+0.00000000i|11>	100.00000%

Wrong result with some elementary computation

Hi, I tried to parse some very basic OpenQASM circuits and encountered strange results.

For instance, something like:

 rx( pi/3) q[0];
 cx q[0], q[1];                                                              
 crz(pi) q[1], q[0];

yields phase=0 for both qubits with several other simulators, while quantum-circuits gives the correct magnitude but a wrong phase for the second qubit.

Here is a link for the above circuit on Quirk. (Same result on IBM Quantum Experience)

Please disambiguate unary and binary minus in QASM

A statement like "cu1(-pi) q[0], q[1];" cannot be parsed correctly, unless we insert a space like so: "cu1(- pi) q[0], q[1];". This problem can be reproduced on https://quantum-circuit.com/ as well.

The antlr grammar needs to be changed. A quick search found some discussions:
https://stackoverflow.com/questions/32166738/disambiguating-unary-and-binary-minus-in-antlr4-grammar
https://stackoverflow.com/questions/27478834/how-compiler-distinguishes-minus-and-negative-number-during-parser-process

Undefined gates for cr2, cr4, cr8 and crz

Hi!
I have the following program :

var QuantumCircuit = require("../../lib/debug.js");

var circ = new QuantumCircuit();

circ.addGate("cr2", -1, [0, 1, 2]);
circ.addMeasure(1, "c", 3);

circ.run();

console.log("");
console.log(circ.exportCirq());

The exported cirq program is as follows:

import cirq
import numpy as np

q = [cirq.NamedQubit('q' + str(i)) for i in range(3)]

circuit = cirq.Circuit.from_ops(
    cu1(np.pi / 2)(q[0], q[1], q[2]),
    cirq.measure(q[1], key='c3')
)

simulator = cirq.google.XmonSimulator()
result = simulator.run(circuit)
print(result)

The gate cu1 does not belong to cirq's gate set and hence will result in an error if I try to run this program in cirq. cu1 or better still crz with an angle pi/2 (since cr2 is a controlled-RZ rotation with angle pi/2) needs to be defined in order to make the program work. Same goes for cr4 and cr8.

Another issue I came across was with the gate crz. If I have the following program:

var QuantumCircuit = require("../../lib/debug.js");

var circ = new QuantumCircuit();

circ.addGate("crz", -1, [0, 1], {
    params: {
        phi: "pi/2"
    }
});
circ.addMeasure(1, "c", 3);

This outputs the following cirq program:

import cirq
import numpy as np

def crz(p_phi):
    return cirq.TwoQubitMatrixGate(np.array([ [1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0, np.exp(1j * p_phi)] ]))

q = [cirq.NamedQubit('q' + str(i)) for i in range(2)]

circuit = cirq.Circuit.from_ops(
    cu1(np.pi / 2)(q[0], q[1]),
    cirq.measure(q[1], key='c3')
)

simulator = cirq.google.XmonSimulator()
result = simulator.run(circuit)
print(result)

The used gate is crz which is also defined but the circuit is created with cu1. I think the circuit should be created with crz.

I will raise a PR with changes that I think will solve these issues. :)
Till then, please let me know if I am missing something or if there could be some other workaround. :)

antlr source code?

Is QASM.g4 and other source files used to generate quantum-circuit.js available to public?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.