diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 79659a27..7f2468d1 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -11,9 +11,11 @@ on: jobs: lint: runs-on: ubuntu-latest + continue-on-error: true strategy: + fail-fast: false matrix: - python-version: [ "3.9", "3.10" ] + python-version: [ "3.10", "3.11", "3.12" ] outputs: error-check: ${{ steps.error-check.conclusion }} steps: diff --git a/.gitignore b/.gitignore index 0752b089..8955a3ab 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,7 @@ ipython_config.py # pyenv .python-version +.python-base-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. @@ -131,3 +132,4 @@ dmypy.json .vscode .DS_Store +.idea diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..0d297a67 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +clean_setup: + pyenv virtualenv-delete -f $(shell cat .python-version) + pyenv virtualenv $(shell cat .python-base-version) $(shell cat .python-version) + #make setup +setup: + pip install -r requirements-dev.txt +run_tests: + python -m unittest discover -s ./tests/ -p "test_*.py" +upgrade_dependencies: + pip-compile --allow-unsafe --no-annotate requirements-dev.in --upgrade + pip-compile --allow-unsafe --no-annotate requirements.in --upgrade diff --git a/docs/search.js b/docs/search.js index 869d6d16..bc9dec31 100644 --- a/docs/search.js +++ b/docs/search.js @@ -1,6 +1,6 @@ window.pdocSearch = (function(){ /** elasticlunr - http://weixsong.github.io * Copyright (C) 2017 Oliver Nightingale * Copyright (C) 2017 Wei Song * MIT Licensed */!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();oA Python library to simplify quantum circuits of Pauli gadgets.\nIt consists of two sub-modules, phase and pauli, detailed below.

\n"}, {"fullname": "pauliopt.circuits", "modulename": "pauliopt.circuits", "kind": "module", "doc": "

A general class for quantum circuits, with a ZX / Gadget representation.

\n"}, {"fullname": "pauliopt.circuits.QISKIT_CONVERSION", "modulename": "pauliopt.circuits", "qualname": "QISKIT_CONVERSION", "kind": "variable", "doc": "

\n", "default_value": "{'h': <function <lambda>>, 'x': <function <lambda>>, 'y': <function <lambda>>, 'z': <function <lambda>>, 's': <function <lambda>>, 'sdg': <function <lambda>>, 't': <function <lambda>>, 'tdg': <function <lambda>>, 'swap': <function <lambda>>, 'cx': <function <lambda>>, 'cy': <function <lambda>>, 'cz': <function <lambda>>, 'ccx': <function <lambda>>, 'ccz': <function <lambda>>, 'rx': <function <lambda>>, 'ry': <function <lambda>>, 'rz': <function <lambda>>, 'crx': <function <lambda>>, 'cry': <function <lambda>>, 'crz': <function <lambda>>}"}, {"fullname": "pauliopt.circuits.Circuit", "modulename": "pauliopt.circuits", "qualname": "Circuit", "kind": "class", "doc": "

Class for representing quantum circuits.

\n"}, {"fullname": "pauliopt.circuits.Circuit.__init__", "modulename": "pauliopt.circuits", "qualname": "Circuit.__init__", "kind": "function", "doc": "

\n", "signature": "(n_qubits, _gates=None)"}, {"fullname": "pauliopt.circuits.Circuit.n_qubits", "modulename": "pauliopt.circuits", "qualname": "Circuit.n_qubits", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.circuits.Circuit.add_gate", "modulename": "pauliopt.circuits", "qualname": "Circuit.add_gate", "kind": "function", "doc": "

\n", "signature": "(self, gate):", "funcdef": "def"}, {"fullname": "pauliopt.circuits.Circuit.add_gates", "modulename": "pauliopt.circuits", "qualname": "Circuit.add_gates", "kind": "function", "doc": "

\n", "signature": "(self, gates):", "funcdef": "def"}, {"fullname": "pauliopt.circuits.Circuit.to_phase_circuit", "modulename": "pauliopt.circuits", "qualname": "Circuit.to_phase_circuit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.circuits.Circuit.from_qiskit", "modulename": "pauliopt.circuits", "qualname": "Circuit.from_qiskit", "kind": "function", "doc": "

\n", "signature": "(qc: qiskit.circuit.quantumcircuit.QuantumCircuit):", "funcdef": "def"}, {"fullname": "pauliopt.circuits.Circuit.to_qiskit", "modulename": "pauliopt.circuits", "qualname": "Circuit.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.clifford", "modulename": "pauliopt.clifford", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.clifford.tableau", "modulename": "pauliopt.clifford.tableau", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.clifford.tableau.mult_paulis", "modulename": "pauliopt.clifford.tableau", "qualname": "mult_paulis", "kind": "function", "doc": "

Small helper function to multiply two Pauli strings and correctly update the sign.

\n\n

Args:\n p1 (np.ndarray): Pauli string 1\n p2 (np.ndarray): Pauli string 2\n sign1 (int): Sign of Pauli string 1\n sign2 (int): Sign of Pauli string 2\n n_qubits (int): Number of qubits in the Pauli strings

\n\n

Returns:\n np.ndarray: Pauli string 1 * Pauli string 2

\n", "signature": "(p1, p2, sign1, sign2, n_qubits):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau", "kind": "class", "doc": "

Class for storing and manipulating Clifford tableau.\nA Clifford tableau is a representation of a Clifford circuit as a\n2n x 2n binary matrix, where n is the number of qubits. The first n rows\nrepresent the stabilizers, and the last n rows represent the destabilizers.\nThe first n columns represent the X operators, and the last n columns\nrepresent the Z operators.\nThe sign of the operator in row i is given by the i-th entry of\nthe sign vector.

\n\n

The tableau is initialized as the identity matrix with a zero sign vector.

\n\n

Args:\n n_qubits (int): Number of qubits in the tableau.

\n\n

A more readable representation of the tableau is given by the string:

\n\n
\n
>>> from pauliopt.clifford.tableau import CliffordTableau\n>>> ct = CliffordTableau(2)\n>>> print(ct)\n# Expected Output:\n# X/Z I/I | +\n# I/I X/Z | +\n>>> ct.append_h(0)\n>>> print(ct)\n# Expected Output:\n# Z/X I/I | +\n# I/I X/Z | +\n
\n
\n\n

To get the raw $2n imes 2n$ matrix representation of the tableau, use:

\n\n
\n
>>> ct.tableau\n# Expected Output:\n# array([[0, 0, 1, 0],\n#        [0, 1, 0, 0],\n#        [1, 0, 0, 0],\n#        [0, 0, 0, 1]], dtype=uint8)\n
\n
\n\n

To get the sign vector, use:

\n\n
\n
>>> ct.signs\n# Expected Output:\n# array([0, 0, 0, 0], dtype=uint8)\n
\n
\n"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.__init__", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.__init__", "kind": "function", "doc": "

\n", "signature": "(n_qubits)"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.tableau", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.tableau", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.signs", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.signs", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.n_qubits", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.n_qubits", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.from_tableau", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.from_tableau", "kind": "function", "doc": "

Create a CliffordTableau from a tableau and sign vector.

\n\n

Args:\n tableau (np.ndarray): $2n imes 2n$ binary matrix representing the tableau.\n signs (np.ndarray): $2n$-dimensional binary vector representing the sign vector.

\n\n

Returns:\n CliffordTableau: CliffordTableau object.

\n", "signature": "(tableau, signs):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.from_qiskit_tableau", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.from_qiskit_tableau", "kind": "function", "doc": "

Create a CliffordTableau from a qiskit Clifford object.

\n\n

Args:\n qiskit_ct (qiskit.quantum_info.Clifford): Clifford object.

\n\n

Returns:\n CliffordTableau: CliffordTableau object.

\n", "signature": "(\tqiskit_ct: qiskit.quantum_info.operators.symplectic.clifford.Clifford):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.string_repr", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.string_repr", "kind": "function", "doc": "

Get a string representation of the tableau.

\n\n

Args:\n sep (str): Separator between the pauli operators\n sign_sep (str): Separator between operators and sign.

\n", "signature": "(self, sep=' ', sign_sep='| '):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.x_out", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.x_out", "kind": "function", "doc": "

Get the X operator in row row and column col.

\n\n

Args:\n row (int): Row index.\n col (int): Column index.

\n", "signature": "(self, row, col):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.z_out", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.z_out", "kind": "function", "doc": "

Get the Z operator in row row and column col.

\n\n

Args:\n row (int): Row index.\n col (int): Column index.

\n", "signature": "(self, row, col):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.prepend_h", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.prepend_h", "kind": "function", "doc": "

Prepend a Hadamard gate to the tableau.

\n\n

Args:\n qubit (int): Qubit the hadamard gate is applied to.

\n", "signature": "(self, qubit):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.append_h", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.append_h", "kind": "function", "doc": "

Append a Hadamard gate to the tableau.

\n\n

Args:\n qubit (int): Qubit the hadamard gate is applied to.

\n", "signature": "(self, qubit):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.prepend_s", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.prepend_s", "kind": "function", "doc": "

Prepend a S gate to the tableau.

\n\n

Args:\n qubit (int): Qubit the S gate is applied to.

\n", "signature": "(self, qubit):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.append_s", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.append_s", "kind": "function", "doc": "

Append a S gate to the tableau.

\n\n

Args:\n qubit (int): Qubit the S gate is applied to.

\n", "signature": "(self, qubit):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.prepend_cnot", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.prepend_cnot", "kind": "function", "doc": "

Prepend a CNOT gate to the tableau.

\n\n

Args:\n control (int): Control qubit.\n target (int): Target qubit.

\n", "signature": "(self, control, target):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.append_cnot", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.append_cnot", "kind": "function", "doc": "

Append a CNOT gate to the tableau.

\n\n

Args:\n control (int): Control qubit.\n target (int): Target qubit.

\n", "signature": "(self, control, target):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.insert_pauli_row", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.insert_pauli_row", "kind": "function", "doc": "

Insert a Pauli row into the tableau.

\n\n

Args:\n pauli (np.array): Pauli to be inserted.\n p_sign (int): Sign of the Pauli.\n row (int): Row to insert the Pauli.

\n", "signature": "(self, pauli, p_sign, row):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.inverse", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.inverse", "kind": "function", "doc": "

Invert the tableau.

\n\n

Note: this is will create a deep copy of the tableau.

\n\n

Returns:\n CliffordTableau: Inverted tableau.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau.CliffordTableau.apply", "modulename": "pauliopt.clifford.tableau", "qualname": "CliffordTableau.apply", "kind": "function", "doc": "

Apply a CliffordTableau to the current tableau.

\n\n

Note: this is will create a deep copy of the tableau.

\n\n

Args:\n other (CliffordTableau): CliffordTableau to apply.

\n\n

Returns:\n CliffordTableau: Applied CliffordTableau.

\n", "signature": "(self, other: pauliopt.clifford.tableau.CliffordTableau):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis", "modulename": "pauliopt.clifford.tableau_synthesis", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.clifford.tableau_synthesis.heurisitc_fkt", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "heurisitc_fkt", "kind": "function", "doc": "

The heuristic function for picking the pivot in the tableau synthesis algorithm.

\n\n
Parameters
\n\n
    \n
  • row: The row to consider
  • \n
  • G: The graph of the topology
  • \n
  • remaining: The remaining tableau
  • \n
\n", "signature": "(row, G, remaining: pauliopt.clifford.tableau.CliffordTableau):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.pick_pivot", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "pick_pivot", "kind": "function", "doc": "

Pick the pivot to eliminate the next column in the tableau synthesis algorithm.

\n\n

We currently use the heuristic function h to pick the pivot,\ni.e choose the row with the smallest heurisitc_fkt value.

\n\n
Parameters
\n\n
    \n
  • G: The graph of the topology
  • \n
  • remaining: The remaining tableau
  • \n
  • possible_swaps: The columns that can be swapped
  • \n
  • include_swaps: Whether to include the columns that can be swapped
  • \n
\n", "signature": "(\tG,\tremaining: pauliopt.clifford.tableau.CliffordTableau,\tpossible_swaps,\tinclude_swaps):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.update_dfs", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "update_dfs", "kind": "function", "doc": "

Helper function to update the dfs list in place. (See compute_steiner_tree)

\n\n
Parameters
\n\n
    \n
  • dfs: The dfs list to update
  • \n
  • parent: The parent node
  • \n
  • child: The child node
  • \n
\n", "signature": "(dfs, parent, child):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.relabel_graph_inplace", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "relabel_graph_inplace", "kind": "function", "doc": "

Helper function to relabel the graph in place. (See compute_steiner_tree)

\n\n
Parameters
\n\n
    \n
  • G: The graph to relabel
  • \n
  • parent: The parent node
  • \n
  • child: The child node
  • \n
\n", "signature": "(G, parent, child):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.compute_steiner_tree", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "compute_steiner_tree", "kind": "function", "doc": "

Compute the steiner tree of the sub_graph with the given nodes.\nThis function is a wrapper around the networkx steiner tree function.

\n\n

It will additionally swap the columns of the remaining tableau to further reduce\nthe amount of CNOTs if include_swaps is True.\nInclude_swaps requires lookup, swappable_nodes, permutation and n_qubits to be set.

\n\n
Parameters
\n\n
    \n
  • root: The root node of the steiner tree
  • \n
  • nodes: The nodes to include in the steiner tree
  • \n
  • sub_graph: The graph of the topology

  • \n
  • include_swaps: Whether to include swaps in the steiner tree

  • \n
  • lookup: The lookup table of the topology
  • \n
  • swappable_nodes: The nodes that can be swapped
  • \n
  • permutation: The permutation of the topology
  • \n
  • n_qubits: The number of qubits
  • \n
\n", "signature": "(\troot: int,\tnodes: [<class 'int'>],\tsub_graph: networkx.classes.graph.Graph,\tinclude_swaps=False,\tlookup=None,\tswappable_nodes=None,\tpermutation=None,\tn_qubits=None):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.is_cutting", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "is_cutting", "kind": "function", "doc": "

Check if the given vertex is a cutting vertex in the given graph.

\n\n
Parameters
\n\n
    \n
  • vertex: The vertex to check
  • \n
  • g: The graph to check
  • \n
\n", "signature": "(vertex, g):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.sanitize_z", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "sanitize_z", "kind": "function", "doc": "

Sanitization process for the stabilizer part.

\n\n

Essentially:

\n\n
    \n
  • If the z_out is Y (=3), then apply S
  • \n
  • If the z_out is X (=1), then apply H
  • \n
\n\n
Parameters
\n\n
    \n
  • row: The row of the tableau
  • \n
  • row_z: The row of the tableau for the stabilizer part
  • \n
  • remaining: The remaining tableau
  • \n
  • apply: The function to apply a gate
  • \n
\n", "signature": "(row, row_z, remaining, apply):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.sanitize_field_x", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "sanitize_field_x", "kind": "function", "doc": "

Sanitization process for the destabilizer part.

\n\n

Essentially:

\n\n
    \n
  • If the x_out is Y (=3), then apply S
  • \n
  • If the x_out is X (=2), then apply H
  • \n
\n\n
Parameters
\n\n
    \n
  • row: The row of the tableau
  • \n
  • row_x: The row of the tableau for the destabilizer part
  • \n
  • remaining: The remaining tableau
  • \n
  • apply: The function to apply a gate
  • \n
\n", "signature": "(row, row_x, remaining, apply):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.remove_interactions", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "remove_interactions", "kind": "function", "doc": "

Remove the interactions of the destabilizer/stabilizer part.\nThis function assumed that all elements are Z or I.

\n\n

Include swaps requires swappable_nodes, permutation and include_swaps to be set.

\n\n
Parameters
\n\n
    \n
  • pivot: The pivot of the tableau
  • \n
  • row: The specific row of the tableau
  • \n
  • sub_graph: The graph of the topology
  • \n
  • remaining: The remaining tableau
  • \n
  • apply: The function to apply a gate
  • \n
  • basis: The basis of the tableau (x for destabilizer or z for stabilizer)
  • \n
  • swappable_nodes: The nodes that can be swapped
  • \n
  • permutation: The permutation of the topology
  • \n
  • include_swaps: Whether to include swaps in the steiner tree
  • \n
\n", "signature": "(\tpivot,\trow,\tsub_graph,\tremaining,\tapply,\tbasis,\tinclude_swaps=False,\tswappable_nodes=None,\tpermutation=None):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.steiner_reduce_column", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "steiner_reduce_column", "kind": "function", "doc": "

Steiner reduce a column of the tableau.

\n\n
Parameters
\n\n
    \n
  • pivot: The pivot of the tableau
  • \n
  • sub_graph: The graph of the topology
  • \n
  • remaining: The remaining tableau
  • \n
  • apply: The function to apply a gate
  • \n
  • swappable_nodes: The nodes that can be swapped
  • \n
  • permutation: The permutation of the topology
  • \n
  • include_swaps: Whether to include swaps in the steiner tree
  • \n
\n", "signature": "(\tpivot,\tsub_graph,\tremaining,\tapply,\tswappable_nodes=None,\tpermutation=None,\tinclude_swaps=False):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.get_non_cutting_vertex", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "get_non_cutting_vertex", "kind": "function", "doc": "

\n", "signature": "(G, pivot_col, swappable_nodes):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.synthesize_tableau", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "synthesize_tableau", "kind": "function", "doc": "

Architecture aware synthesis of a Clifford tableau.\nThis is the implementation of the algorithm described in Winderl et. al. [1]

\n\n
Parameters
\n\n
    \n
  • tableau: The Clifford tableau
  • \n
  • topo: The topology
  • \n
  • include_swaps: Whether to allow initial and final measurement permutations
  • \n
\n\n
Returns
\n\n
\n

The synthesized circuit and a inital/final permutation

\n
\n\n

References

\n\n

[1] Winderl, Huang, et al. \"Architecture-Aware Synthesis of Stabilizer Circuits from Clifford Tableaus.\" arXiv preprint arXiv:2309.08972 (2023).

\n", "signature": "(\ttableau: pauliopt.clifford.tableau.CliffordTableau,\ttopo: pauliopt.topologies.Topology,\tinclude_swaps=True):", "funcdef": "def"}, {"fullname": "pauliopt.gates", "modulename": "pauliopt.gates", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.gates.Gate", "modulename": "pauliopt.gates", "qualname": "Gate", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "abc.ABC"}, {"fullname": "pauliopt.gates.Gate.qubits", "modulename": "pauliopt.gates", "qualname": "Gate.qubits", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Gate.name", "modulename": "pauliopt.gates", "qualname": "Gate.name", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Gate.width", "modulename": "pauliopt.gates", "qualname": "Gate.width", "kind": "variable", "doc": "

Width of gate used for drawing.

\n"}, {"fullname": "pauliopt.gates.Gate.draw_zx", "modulename": "pauliopt.gates", "qualname": "Gate.draw_zx", "kind": "function", "doc": "

\n", "signature": "(self, builder, base, row_width, params):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Gate.draw_box", "modulename": "pauliopt.gates", "qualname": "Gate.draw_box", "kind": "function", "doc": "

\n", "signature": "(self, builder, base, row_width, params):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Gate.draw", "modulename": "pauliopt.gates", "qualname": "Gate.draw", "kind": "function", "doc": "

\n", "signature": "(self, builder, base, row_width, params):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Gate.gadgets", "modulename": "pauliopt.gates", "qualname": "Gate.gadgets", "kind": "variable", "doc": "

List of gadgets used to implement this gate.

\n"}, {"fullname": "pauliopt.gates.Gate.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Gate.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.PhaseGate", "modulename": "pauliopt.gates", "qualname": "PhaseGate", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.PhaseGate.phase", "modulename": "pauliopt.gates", "qualname": "PhaseGate.phase", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.H", "modulename": "pauliopt.gates", "qualname": "H", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.H.n_qubits", "modulename": "pauliopt.gates", "qualname": "H.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.H.width", "modulename": "pauliopt.gates", "qualname": "H.width", "kind": "variable", "doc": "

Width of gate used for drawing.

\n", "default_value": "40"}, {"fullname": "pauliopt.gates.H.decomp", "modulename": "pauliopt.gates", "qualname": "H.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.H.draw", "modulename": "pauliopt.gates", "qualname": "H.draw", "kind": "function", "doc": "

\n", "signature": "(self, builder, base, row_width, params):", "funcdef": "def"}, {"fullname": "pauliopt.gates.H.to_qiskit", "modulename": "pauliopt.gates", "qualname": "H.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.X", "modulename": "pauliopt.gates", "qualname": "X", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.X.n_qubits", "modulename": "pauliopt.gates", "qualname": "X.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.X.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "X.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.X.decomp", "modulename": "pauliopt.gates", "qualname": "X.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.X.to_qiskit", "modulename": "pauliopt.gates", "qualname": "X.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Z", "modulename": "pauliopt.gates", "qualname": "Z", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.Z.n_qubits", "modulename": "pauliopt.gates", "qualname": "Z.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Z.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Z.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Z.decomp", "modulename": "pauliopt.gates", "qualname": "Z.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Z.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Z.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Y", "modulename": "pauliopt.gates", "qualname": "Y", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.Y.n_qubits", "modulename": "pauliopt.gates", "qualname": "Y.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Y.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Y.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Y.decomp", "modulename": "pauliopt.gates", "qualname": "Y.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Y.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Y.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.S", "modulename": "pauliopt.gates", "qualname": "S", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.S.n_qubits", "modulename": "pauliopt.gates", "qualname": "S.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.S.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "S.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.S.decomp", "modulename": "pauliopt.gates", "qualname": "S.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.S.to_qiskit", "modulename": "pauliopt.gates", "qualname": "S.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Sdg", "modulename": "pauliopt.gates", "qualname": "Sdg", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.Sdg.n_qubits", "modulename": "pauliopt.gates", "qualname": "Sdg.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Sdg.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Sdg.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Sdg.decomp", "modulename": "pauliopt.gates", "qualname": "Sdg.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Sdg.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Sdg.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.T", "modulename": "pauliopt.gates", "qualname": "T", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.T.n_qubits", "modulename": "pauliopt.gates", "qualname": "T.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.T.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "T.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.T.decomp", "modulename": "pauliopt.gates", "qualname": "T.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.T.to_qiskit", "modulename": "pauliopt.gates", "qualname": "T.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Tdg", "modulename": "pauliopt.gates", "qualname": "Tdg", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.Tdg.n_qubits", "modulename": "pauliopt.gates", "qualname": "Tdg.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Tdg.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Tdg.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Tdg.decomp", "modulename": "pauliopt.gates", "qualname": "Tdg.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Tdg.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Tdg.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.SWAP", "modulename": "pauliopt.gates", "qualname": "SWAP", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.SWAP.n_qubits", "modulename": "pauliopt.gates", "qualname": "SWAP.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.SWAP.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "SWAP.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.SWAP.decomp", "modulename": "pauliopt.gates", "qualname": "SWAP.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.SWAP.to_qiskit", "modulename": "pauliopt.gates", "qualname": "SWAP.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CX", "modulename": "pauliopt.gates", "qualname": "CX", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.CX.n_qubits", "modulename": "pauliopt.gates", "qualname": "CX.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.CX.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "CX.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CX.width", "modulename": "pauliopt.gates", "qualname": "CX.width", "kind": "variable", "doc": "

Width of gate used for drawing.

\n", "default_value": "40"}, {"fullname": "pauliopt.gates.CX.decomp", "modulename": "pauliopt.gates", "qualname": "CX.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CX.draw", "modulename": "pauliopt.gates", "qualname": "CX.draw", "kind": "function", "doc": "

\n", "signature": "(self, builder, base, row_width, params):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CX.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CX.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CY", "modulename": "pauliopt.gates", "qualname": "CY", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.CY.n_qubits", "modulename": "pauliopt.gates", "qualname": "CY.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.CY.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "CY.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CY.decomp", "modulename": "pauliopt.gates", "qualname": "CY.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CY.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CY.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CZ", "modulename": "pauliopt.gates", "qualname": "CZ", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.CZ.n_qubits", "modulename": "pauliopt.gates", "qualname": "CZ.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.CZ.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "CZ.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CZ.decomp", "modulename": "pauliopt.gates", "qualname": "CZ.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CZ.draw", "modulename": "pauliopt.gates", "qualname": "CZ.draw", "kind": "function", "doc": "

\n", "signature": "(self, builder, base, row_width, params):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CZ.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CZ.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CCX", "modulename": "pauliopt.gates", "qualname": "CCX", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.CCX.n_qubits", "modulename": "pauliopt.gates", "qualname": "CCX.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "3"}, {"fullname": "pauliopt.gates.CCX.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "CCX.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CCX.decomp", "modulename": "pauliopt.gates", "qualname": "CCX.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CCX.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CCX.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CCZ", "modulename": "pauliopt.gates", "qualname": "CCZ", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.CCZ.n_qubits", "modulename": "pauliopt.gates", "qualname": "CCZ.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "3"}, {"fullname": "pauliopt.gates.CCZ.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "CCZ.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CCZ.decomp", "modulename": "pauliopt.gates", "qualname": "CCZ.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CCZ.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CCZ.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Rx", "modulename": "pauliopt.gates", "qualname": "Rx", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "PhaseGate"}, {"fullname": "pauliopt.gates.Rx.n_qubits", "modulename": "pauliopt.gates", "qualname": "Rx.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Rx.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Rx.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Rx.decomp", "modulename": "pauliopt.gates", "qualname": "Rx.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Rx.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Rx.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Ry", "modulename": "pauliopt.gates", "qualname": "Ry", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "PhaseGate"}, {"fullname": "pauliopt.gates.Ry.n_qubits", "modulename": "pauliopt.gates", "qualname": "Ry.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Ry.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Ry.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Ry.decomp", "modulename": "pauliopt.gates", "qualname": "Ry.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Ry.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Ry.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Rz", "modulename": "pauliopt.gates", "qualname": "Rz", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "PhaseGate"}, {"fullname": "pauliopt.gates.Rz.n_qubits", "modulename": "pauliopt.gates", "qualname": "Rz.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Rz.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Rz.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Rz.decomp", "modulename": "pauliopt.gates", "qualname": "Rz.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Rz.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Rz.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CRx", "modulename": "pauliopt.gates", "qualname": "CRx", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "PhaseGate"}, {"fullname": "pauliopt.gates.CRx.n_qubits", "modulename": "pauliopt.gates", "qualname": "CRx.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.CRx.draw_gadget", "modulename": "pauliopt.gates", "qualname": "CRx.draw_gadget", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CRx.decomp", "modulename": "pauliopt.gates", "qualname": "CRx.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CRx.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CRx.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CRy", "modulename": "pauliopt.gates", "qualname": "CRy", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "PhaseGate"}, {"fullname": "pauliopt.gates.CRy.n_qubits", "modulename": "pauliopt.gates", "qualname": "CRy.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.CRy.draw_gadget", "modulename": "pauliopt.gates", "qualname": "CRy.draw_gadget", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CRy.decomp", "modulename": "pauliopt.gates", "qualname": "CRy.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CRy.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CRy.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CRz", "modulename": "pauliopt.gates", "qualname": "CRz", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "PhaseGate"}, {"fullname": "pauliopt.gates.CRz.n_qubits", "modulename": "pauliopt.gates", "qualname": "CRz.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.CRz.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "CRz.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CRz.decomp", "modulename": "pauliopt.gates", "qualname": "CRz.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CRz.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CRz.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CNOT", "modulename": "pauliopt.gates", "qualname": "CNOT", "kind": "variable", "doc": "

\n", "default_value": "<class 'pauliopt.gates.CX'>"}, {"fullname": "pauliopt.gates.draw_gadget", "modulename": "pauliopt.gates", "qualname": "draw_gadget", "kind": "function", "doc": "

\n", "signature": "(builder, base, row_width, params, gadget, text_above=True):", "funcdef": "def"}, {"fullname": "pauliopt.pauli", "modulename": "pauliopt.pauli", "kind": "module", "doc": "

This module contains code to create and simplify circuits of Pauli gadgets,\nby conjugation with topologically-aware random circuits of Clifford gates.

\n\n

Currently in development.

\n"}, {"fullname": "pauliopt.pauli.anneal", "modulename": "pauliopt.pauli.anneal", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.pauli.anneal.pick_random_gate", "modulename": "pauliopt.pauli.anneal", "qualname": "pick_random_gate", "kind": "function", "doc": "

\n", "signature": "(num_qubits, gate_set=None):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.anneal.compute_effect", "modulename": "pauliopt.pauli.anneal", "qualname": "compute_effect", "kind": "function", "doc": "

\n", "signature": "(\tpp: pauliopt.pauli.pauli_polynomial.PauliPolynomial,\tgate: pauliopt.pauli.clifford_gates.CliffordGate,\ttopology: pauliopt.topologies.Topology,\tleg_cache=None):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.anneal.anneal", "modulename": "pauliopt.pauli.anneal", "qualname": "anneal", "kind": "function", "doc": "

\n", "signature": "(\tpp: pauliopt.pauli.pauli_polynomial.PauliPolynomial,\ttopology,\tschedule=('geometric', 1.0, 0.1),\tnr_iterations=100):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_gates", "modulename": "pauliopt.pauli.clifford_gates", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType", "kind": "class", "doc": "

An enumeration.

\n", "bases": "enum.Enum"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType.CX", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType.CX", "kind": "variable", "doc": "

\n", "default_value": "<CliffordType.CX: 'cx'>"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType.CY", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType.CY", "kind": "variable", "doc": "

\n", "default_value": "<CliffordType.CY: 'cy'>"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType.CZ", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType.CZ", "kind": "variable", "doc": "

\n", "default_value": "<CliffordType.CZ: 'cz'>"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType.H", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType.H", "kind": "variable", "doc": "

\n", "default_value": "<CliffordType.H: 'h'>"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType.S", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType.S", "kind": "variable", "doc": "

\n", "default_value": "<CliffordType.S: 's'>"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType.V", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType.V", "kind": "variable", "doc": "

\n", "default_value": "<CliffordType.V: 'v'>"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordGate", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordGate", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "abc.ABC"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordGate.c_type", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordGate.c_type", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordGate.propagate_pauli", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordGate.propagate_pauli", "kind": "function", "doc": "

\n", "signature": "(self, gadget: pauliopt.pauli.pauli_gadget.PauliGadget):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_gates.SingleQubitGate", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "SingleQubitGate", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "CliffordGate, abc.ABC"}, {"fullname": "pauliopt.pauli.clifford_gates.SingleQubitGate.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "SingleQubitGate.__init__", "kind": "function", "doc": "

\n", "signature": "(type, qubit)"}, {"fullname": "pauliopt.pauli.clifford_gates.SingleQubitGate.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "SingleQubitGate.rules", "kind": "variable", "doc": "

\n", "default_value": "None"}, {"fullname": "pauliopt.pauli.clifford_gates.SingleQubitGate.qubit", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "SingleQubitGate.qubit", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_gates.SingleQubitGate.propagate_pauli", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "SingleQubitGate.propagate_pauli", "kind": "function", "doc": "

\n", "signature": "(self, gadget: pauliopt.pauli.pauli_gadget.PauliGadget):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_gates.ControlGate", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "ControlGate", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "CliffordGate, abc.ABC"}, {"fullname": "pauliopt.pauli.clifford_gates.ControlGate.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "ControlGate.__init__", "kind": "function", "doc": "

\n", "signature": "(type, control, target)"}, {"fullname": "pauliopt.pauli.clifford_gates.ControlGate.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "ControlGate.rules", "kind": "variable", "doc": "

\n", "default_value": "None"}, {"fullname": "pauliopt.pauli.clifford_gates.ControlGate.control", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "ControlGate.control", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_gates.ControlGate.target", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "ControlGate.target", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_gates.ControlGate.propagate_pauli", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "ControlGate.propagate_pauli", "kind": "function", "doc": "

\n", "signature": "(self, gadget: pauliopt.pauli.pauli_gadget.PauliGadget):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_gates.CX", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CX", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "ControlGate"}, {"fullname": "pauliopt.pauli.clifford_gates.CX.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CX.__init__", "kind": "function", "doc": "

\n", "signature": "(control, target)"}, {"fullname": "pauliopt.pauli.clifford_gates.CX.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CX.rules", "kind": "variable", "doc": "

\n", "default_value": "{'XX': (<Pauli.X: 'X'>, <Pauli.I: 'I'>, 1), 'XY': (<Pauli.Y: 'Y'>, <Pauli.Z: 'Z'>, 1), 'XZ': (<Pauli.Y: 'Y'>, <Pauli.Y: 'Y'>, -1), 'XI': (<Pauli.X: 'X'>, <Pauli.X: 'X'>, 1), 'YX': (<Pauli.Y: 'Y'>, <Pauli.I: 'I'>, 1), 'YY': (<Pauli.X: 'X'>, <Pauli.Z: 'Z'>, -1), 'YZ': (<Pauli.X: 'X'>, <Pauli.Y: 'Y'>, 1), 'YI': (<Pauli.Y: 'Y'>, <Pauli.X: 'X'>, 1), 'ZX': (<Pauli.Z: 'Z'>, <Pauli.X: 'X'>, 1), 'ZY': (<Pauli.I: 'I'>, <Pauli.Y: 'Y'>, 1), 'ZZ': (<Pauli.I: 'I'>, <Pauli.Z: 'Z'>, 1), 'ZI': (<Pauli.Z: 'Z'>, <Pauli.I: 'I'>, 1), 'IX': (<Pauli.I: 'I'>, <Pauli.X: 'X'>, 1), 'IY': (<Pauli.Z: 'Z'>, <Pauli.Y: 'Y'>, 1), 'IZ': (<Pauli.Z: 'Z'>, <Pauli.Z: 'Z'>, 1), 'II': (<Pauli.I: 'I'>, <Pauli.I: 'I'>, 1)}"}, {"fullname": "pauliopt.pauli.clifford_gates.CZ", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CZ", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "ControlGate"}, {"fullname": "pauliopt.pauli.clifford_gates.CZ.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CZ.__init__", "kind": "function", "doc": "

\n", "signature": "(control, target)"}, {"fullname": "pauliopt.pauli.clifford_gates.CZ.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CZ.rules", "kind": "variable", "doc": "

\n", "default_value": "{'XX': (<Pauli.Y: 'Y'>, <Pauli.Y: 'Y'>, 1), 'XY': (<Pauli.Y: 'Y'>, <Pauli.X: 'X'>, -1), 'XZ': (<Pauli.X: 'X'>, <Pauli.I: 'I'>, 1), 'XI': (<Pauli.X: 'X'>, <Pauli.Z: 'Z'>, 1), 'YX': (<Pauli.X: 'X'>, <Pauli.Y: 'Y'>, -1), 'YY': (<Pauli.X: 'X'>, <Pauli.X: 'X'>, 1), 'YZ': (<Pauli.Y: 'Y'>, <Pauli.I: 'I'>, 1), 'YI': (<Pauli.Y: 'Y'>, <Pauli.Z: 'Z'>, 1), 'ZX': (<Pauli.I: 'I'>, <Pauli.X: 'X'>, 1), 'ZY': (<Pauli.I: 'I'>, <Pauli.Y: 'Y'>, 1), 'ZZ': (<Pauli.Z: 'Z'>, <Pauli.Z: 'Z'>, 1), 'ZI': (<Pauli.Z: 'Z'>, <Pauli.I: 'I'>, 1), 'IX': (<Pauli.Z: 'Z'>, <Pauli.X: 'X'>, 1), 'IY': (<Pauli.Z: 'Z'>, <Pauli.Y: 'Y'>, 1), 'IZ': (<Pauli.I: 'I'>, <Pauli.Z: 'Z'>, 1), 'II': (<Pauli.I: 'I'>, <Pauli.I: 'I'>, 1)}"}, {"fullname": "pauliopt.pauli.clifford_gates.CY", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CY", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "ControlGate"}, {"fullname": "pauliopt.pauli.clifford_gates.CY.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CY.__init__", "kind": "function", "doc": "

\n", "signature": "(control, target)"}, {"fullname": "pauliopt.pauli.clifford_gates.CY.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CY.rules", "kind": "variable", "doc": "

\n", "default_value": "{'XX': (<Pauli.Y: 'Y'>, <Pauli.Z: 'Z'>, -1), 'XY': (<Pauli.X: 'X'>, <Pauli.I: 'I'>, 1), 'XZ': (<Pauli.Y: 'Y'>, <Pauli.X: 'X'>, 1), 'XI': (<Pauli.X: 'X'>, <Pauli.Y: 'Y'>, 1), 'YX': (<Pauli.X: 'X'>, <Pauli.Z: 'Z'>, 1), 'YY': (<Pauli.Y: 'Y'>, <Pauli.I: 'I'>, 1), 'YZ': (<Pauli.X: 'X'>, <Pauli.X: 'X'>, -1), 'YI': (<Pauli.Y: 'Y'>, <Pauli.Y: 'Y'>, 1), 'ZX': (<Pauli.I: 'I'>, <Pauli.X: 'X'>, 1), 'ZY': (<Pauli.Z: 'Z'>, <Pauli.Y: 'Y'>, 1), 'ZZ': (<Pauli.I: 'I'>, <Pauli.Z: 'Z'>, 1), 'ZI': (<Pauli.Z: 'Z'>, <Pauli.I: 'I'>, 1), 'IX': (<Pauli.Z: 'Z'>, <Pauli.X: 'X'>, 1), 'IY': (<Pauli.I: 'I'>, <Pauli.Y: 'Y'>, 1), 'IZ': (<Pauli.Z: 'Z'>, <Pauli.Z: 'Z'>, 1), 'II': (<Pauli.I: 'I'>, <Pauli.I: 'I'>, 1)}"}, {"fullname": "pauliopt.pauli.clifford_gates.H", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "H", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "SingleQubitGate"}, {"fullname": "pauliopt.pauli.clifford_gates.H.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "H.__init__", "kind": "function", "doc": "

\n", "signature": "(qubit)"}, {"fullname": "pauliopt.pauli.clifford_gates.H.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "H.rules", "kind": "variable", "doc": "

\n", "default_value": "{'X': (<Pauli.Z: 'Z'>, 1), 'Y': (<Pauli.Y: 'Y'>, -1), 'Z': (<Pauli.X: 'X'>, 1), 'I': (<Pauli.I: 'I'>, 1)}"}, {"fullname": "pauliopt.pauli.clifford_gates.S", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "S", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "SingleQubitGate"}, {"fullname": "pauliopt.pauli.clifford_gates.S.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "S.__init__", "kind": "function", "doc": "

\n", "signature": "(qubit)"}, {"fullname": "pauliopt.pauli.clifford_gates.S.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "S.rules", "kind": "variable", "doc": "

\n", "default_value": "{'X': (<Pauli.Y: 'Y'>, -1), 'Y': (<Pauli.X: 'X'>, 1), 'Z': (<Pauli.Z: 'Z'>, 1), 'I': (<Pauli.I: 'I'>, 1)}"}, {"fullname": "pauliopt.pauli.clifford_gates.V", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "V", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "SingleQubitGate"}, {"fullname": "pauliopt.pauli.clifford_gates.V.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "V.__init__", "kind": "function", "doc": "

\n", "signature": "(qubit)"}, {"fullname": "pauliopt.pauli.clifford_gates.V.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "V.rules", "kind": "variable", "doc": "

\n", "default_value": "{'X': (<Pauli.X: 'X'>, 1), 'Y': (<Pauli.Z: 'Z'>, -1), 'Z': (<Pauli.Y: 'Y'>, 1), 'I': (<Pauli.I: 'I'>, 1)}"}, {"fullname": "pauliopt.pauli.clifford_gates.generate_random_clifford", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "generate_random_clifford", "kind": "function", "doc": "

\n", "signature": "(c_type: pauliopt.pauli.clifford_gates.CliffordType, n_qubits: int):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_gates.clifford_to_qiskit", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "clifford_to_qiskit", "kind": "function", "doc": "

\n", "signature": "(clifford: pauliopt.pauli.clifford_gates.CliffordGate):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_region", "modulename": "pauliopt.pauli.clifford_region", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_region.CliffordRegion", "modulename": "pauliopt.pauli.clifford_region", "qualname": "CliffordRegion", "kind": "class", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_region.CliffordRegion.__init__", "modulename": "pauliopt.pauli.clifford_region", "qualname": "CliffordRegion.__init__", "kind": "function", "doc": "

\n", "signature": "(num_qubits, gates=None)"}, {"fullname": "pauliopt.pauli.clifford_region.CliffordRegion.gates", "modulename": "pauliopt.pauli.clifford_region", "qualname": "CliffordRegion.gates", "kind": "variable", "doc": "

\n", "annotation": ": [<class 'pauliopt.pauli.clifford_gates.CliffordGate'>]"}, {"fullname": "pauliopt.pauli.clifford_region.CliffordRegion.num_qubits", "modulename": "pauliopt.pauli.clifford_region", "qualname": "CliffordRegion.num_qubits", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_region.CliffordRegion.add_gate", "modulename": "pauliopt.pauli.clifford_region", "qualname": "CliffordRegion.add_gate", "kind": "function", "doc": "

\n", "signature": "(self, gate: pauliopt.pauli.clifford_gates.CliffordGate):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_region.CliffordRegion.to_qiskit", "modulename": "pauliopt.pauli.clifford_region", "qualname": "CliffordRegion.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_gadget", "modulename": "pauliopt.pauli.pauli_gadget", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_gadget.decompose_cnot_ladder_z", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "decompose_cnot_ladder_z", "kind": "function", "doc": "

\n", "signature": "(ctrl: int, trg: int, arch: pauliopt.topologies.Topology):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_gadget.find_minimal_cx_assignment", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "find_minimal_cx_assignment", "kind": "function", "doc": "

\n", "signature": "(\tcolumn: <built-in function array>,\tarch: pauliopt.topologies.Topology):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_gadget.PPhase", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PPhase", "kind": "class", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_gadget.PPhase.__init__", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PPhase.__init__", "kind": "function", "doc": "

\n", "signature": "(angle: pauliopt.utils.AngleExpr)"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget", "kind": "class", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget.__init__", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget.__init__", "kind": "function", "doc": "

\n", "signature": "(\tangle: pauliopt.utils.AngleExpr,\tpaulis: List[pauliopt.pauli.utils.Pauli])"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget.angle", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget.angle", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget.paulis", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget.paulis", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget.copy", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget.copy", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget.two_qubit_count", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget.two_qubit_count", "kind": "function", "doc": "

\n", "signature": "(self, topology, leg_cache=None):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget.to_qiskit", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self, topology=None):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_polynomial", "modulename": "pauliopt.pauli.pauli_polynomial", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial", "kind": "class", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.__init__", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.__init__", "kind": "function", "doc": "

\n", "signature": "(num_qubits)"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.num_qubits", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.num_qubits", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.pauli_gadgets", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.pauli_gadgets", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.num_gadgets", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.num_gadgets", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.to_qiskit", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self, topology=None):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.propagate", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.propagate", "kind": "function", "doc": "

\n", "signature": "(self, gate: pauliopt.pauli.clifford_gates.CliffordGate):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.copy", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.copy", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.two_qubit_count", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.two_qubit_count", "kind": "function", "doc": "

\n", "signature": "(self, topology, leg_cache=None):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.to_svg", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.to_svg", "kind": "function", "doc": "

\n", "signature": "(\tself,\thscale: float = 1.0,\tvscale: float = 1.0,\tscale: float = 1.0,\tsvg_code_only=False):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.utils", "modulename": "pauliopt.pauli.utils", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.pauli.utils.Pauli", "modulename": "pauliopt.pauli.utils", "qualname": "Pauli", "kind": "class", "doc": "

An enumeration.

\n", "bases": "enum.Enum"}, {"fullname": "pauliopt.pauli.utils.Pauli.I", "modulename": "pauliopt.pauli.utils", "qualname": "Pauli.I", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.I: 'I'>"}, {"fullname": "pauliopt.pauli.utils.Pauli.X", "modulename": "pauliopt.pauli.utils", "qualname": "Pauli.X", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.X: 'X'>"}, {"fullname": "pauliopt.pauli.utils.Pauli.Y", "modulename": "pauliopt.pauli.utils", "qualname": "Pauli.Y", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.Y: 'Y'>"}, {"fullname": "pauliopt.pauli.utils.Pauli.Z", "modulename": "pauliopt.pauli.utils", "qualname": "Pauli.Z", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.Z: 'Z'>"}, {"fullname": "pauliopt.pauli.utils.I", "modulename": "pauliopt.pauli.utils", "qualname": "I", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.I: 'I'>"}, {"fullname": "pauliopt.pauli.utils.X", "modulename": "pauliopt.pauli.utils", "qualname": "X", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.X: 'X'>"}, {"fullname": "pauliopt.pauli.utils.Y", "modulename": "pauliopt.pauli.utils", "qualname": "Y", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.Y: 'Y'>"}, {"fullname": "pauliopt.pauli.utils.Z", "modulename": "pauliopt.pauli.utils", "qualname": "Z", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.Z: 'Z'>"}, {"fullname": "pauliopt.phase", "modulename": "pauliopt.phase", "kind": "module", "doc": "

This module contains code to create and simplify circuits of mixed ZX phase gadgets,\nby conjugation with topologically-aware random circuits of CX gates.

\n"}, {"fullname": "pauliopt.phase.cx_circuits", "modulename": "pauliopt.phase.cx_circuits", "kind": "module", "doc": "

This module contains code to create CX circuits for the optimization\nof circuits of mixed phase gadgets.

\n"}, {"fullname": "pauliopt.phase.cx_circuits.GateLike", "modulename": "pauliopt.phase.cx_circuits", "qualname": "GateLike", "kind": "variable", "doc": "

\n", "default_value": "typing.Union[typing.List[int], typing.Tuple[int, int]]"}, {"fullname": "pauliopt.phase.cx_circuits.synthesis_methods", "modulename": "pauliopt.phase.cx_circuits", "qualname": "synthesis_methods", "kind": "variable", "doc": "

\n", "default_value": "['permrowcol']"}, {"fullname": "pauliopt.phase.cx_circuits.permrowcol", "modulename": "pauliopt.phase.cx_circuits", "qualname": "permrowcol", "kind": "function", "doc": "

Generates a sequence of CNOTs reallizing the given parity matrix up to permutation (if reallocate=True) using\nthe algorithm from https://arxiv.org/abs/2205.00724.

\n\n

Args:\n matrix (numpy.NDArray): The binary parity matrix\n topology (Topology): The target device topology\n parities_as_columns (bool): Whether the parities in the matrix are row-wise or column-wise. Defaults to False, i.e. row-wise.\n reallocate (bool, optional): Whether to qubits can re reallocated. Defaults to False.

\n\n

Raises:\n ModuleNotFoundError: If 'networkx' or 'galois' is not installed.

\n\n

Returns:\n List[Tuple[int]]: List of CNOTs realizing the given parity matrix\n List[int]: The output permutation of the qubit mapping. Equals [0..n] if reallocate==False.

\n", "signature": "(\tmatrix: numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]],\ttopology: pauliopt.topologies.Topology,\tparities_as_columns: bool = False,\treallocate: bool = False) -> Tuple[List[Tuple[int]], List[int]]:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer", "kind": "class", "doc": "

Container for a layer of CX gates constrained\nby a given qubit topology.

\n\n

It uses pauliopt.topologies.Matching to keep track of which\ncouplings in the qubit topology are currently occupied by a CX gate,\nand to efficiently determine whether a CX gate can be added to the layer.

\n"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.__init__", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.__init__", "kind": "function", "doc": "

\n", "signature": "(\ttopology: pauliopt.topologies.Topology,\tgates: Collection[Union[List[int], Tuple[int, int]]] = ())"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.topology", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.topology", "kind": "variable", "doc": "

Readonly property exposing the qubit topology\nconstraining this CX circuit layer.

\n", "annotation": ": pauliopt.topologies.Topology"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.num_gates", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.num_gates", "kind": "variable", "doc": "

Readonly property returning the number of gates in this\nCX circuit layer.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.gates", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.gates", "kind": "variable", "doc": "

Readonly property returning the collection of gates in this\nCX circuit layer.

\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[Tuple[int, int]]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.num_flippable_cxs", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.num_flippable_cxs", "kind": "variable", "doc": "

Readonly property returning the number of CX gates in this\nCX circuit layer that can be flipped.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.flippable_cxs", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.flippable_cxs", "kind": "variable", "doc": "

Readonly property returning the collection of CX gates that\nthat can be currently flipped in this layer, namely:

\n\n
    \n
  • all gates currently in the layer (will be removed by flip);
  • \n
  • all gates with both qubits currently not covered by a gate\nalready in the layer (will be added by flip).
  • \n
\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[Tuple[int, int]]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.incident", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.incident", "kind": "function", "doc": "

Returns the CX gate incident to the given qubit in this layer,\nor None if there is no gate incident to the qubit.

\n", "signature": "(self, qubit: int) -> Optional[Tuple[int, int]]:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.has_cx", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.has_cx", "kind": "function", "doc": "

Checks whether the given CX gate is in the layer:

\n", "signature": "(self, ctrl: int, trgt: int) -> bool:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.is_cx_flippable", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.is_cx_flippable", "kind": "function", "doc": "

Checks whether the given CX gate can be flipped in this layer.\nThis is true if:

\n\n
    \n
  • the gate is present (gate can be removed);
  • \n
  • the gate is not present, and neither the control nor the\ntarget are already covered by some other gate (gate can be added).
  • \n
\n", "signature": "(self, ctrl: int, trgt: int) -> bool:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.random_flip_cx", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.random_flip_cx", "kind": "function", "doc": "

Returns a randomly selected flippable CX gate in this CX circuit layer,\nusing the given random number generator.

\n", "signature": "(self, rng: numpy.random._generator.Generator) -> Tuple[int, int]:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.flip_cx", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.flip_cx", "kind": "function", "doc": "

Adds/removes a CX gate with given control and target to/from the layer.\nRaises ValueError if the gate cannot be added/removed.

\n\n

The layer is modified in-place and then returned, as per the\nfluent API pattern.

\n", "signature": "(self, ctrl: int, trgt: int) -> pauliopt.phase.cx_circuits.CXCircuitLayer:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.clone", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.clone", "kind": "function", "doc": "

Returns a copy of this CX layer.

\n", "signature": "(self) -> pauliopt.phase.cx_circuits.CXCircuitLayer:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.to_qiskit", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.draw", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.draw", "kind": "function", "doc": "

Draws this CX circuit layer using NetworkX and Matplotlib.

\n\n

The layout keyword argument can be used to select a NetworkX layout\nfrom the available ones (exposed by Topology.available_nx_layouts).\nThe figsize keyword argument is passed to matplotlib.pyplot.figure:\nif specified, it determines the width and height of the figure being drawn.\nThe zcolor and xcolor keyword arguments are used to determine the colour\nof the Z and X dots in a CX gate (analogous to PhaseCircuit.to_svg).\nKeyword arguments kwargs are those of networkx.draw_networkx.

\n", "signature": "(\tself,\tlayout: str = 'kamada_kawai',\t*,\tfigsize: Optional[Tuple[int, int]] = None,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\tnoshow: bool = False,\t**kwargs):", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerLike", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerLike", "kind": "variable", "doc": "

\n", "default_value": "typing.Union[pauliopt.phase.cx_circuits.CXCircuitLayer, ForwardRef('CXCircuitLayerView'), typing.Sequence[typing.Union[typing.List[int], typing.Tuple[int, int]]]]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLike", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLike", "kind": "variable", "doc": "

\n", "default_value": "typing.Union[ForwardRef('CXCircuit'), ForwardRef('CXCircuitView'), typing.Sequence[typing.Union[pauliopt.phase.cx_circuits.CXCircuitLayer, ForwardRef('CXCircuitLayerView'), typing.Sequence[typing.Union[typing.List[int], typing.Tuple[int, int]]]]]]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit", "kind": "class", "doc": "

Container for a circuit of CX gates, consisting of a given number of layers\nand constrained by a given qubit topology.

\n", "bases": "typing.Sequence[pauliopt.phase.cx_circuits.CXCircuitLayer]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.__init__", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.__init__", "kind": "function", "doc": "

\n", "signature": "(\ttopology: pauliopt.topologies.Topology,\tlayers: Sequence[pauliopt.phase.cx_circuits.CXCircuitLayer] = (),\toutput_mapping: Sequence[int] = None)"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.topology", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.topology", "kind": "variable", "doc": "

Readonly property exposing the qubit topology\nconstraining this CX circuit.

\n", "annotation": ": pauliopt.topologies.Topology"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.num_gates", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.num_gates", "kind": "variable", "doc": "

Readonly property returning the total number of gates in this\nCX circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.parity_matrix", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.parity_matrix", "kind": "function", "doc": "

Generates the parity matrix representing this CX circuit.

\n\n

Args:\n parities_as_columns (bool, optional): Boolean determining whether the\n parity matrix should be represented with parities as columns in the matrix.\n Defaults to False, meaning that the parities are rows in the matrix.

\n\n

Returns:\n numpy.NDArray containing 1s and 0s.

\n", "signature": "(\tself,\tparities_as_columns: bool = False) -> numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.dag", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.dag", "kind": "function", "doc": "

Returns a copy of this CX circuit,\nwith the layers in reverse order.

\n", "signature": "(self) -> pauliopt.phase.cx_circuits.CXCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.clone", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.clone", "kind": "function", "doc": "

Returns a copy of this CX circuit.

\n", "signature": "(self) -> pauliopt.phase.cx_circuits.CXCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.to_qiskit", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(\tself,\tmethod: Literal['permrowcol', 'naive'] = 'naive',\treallocate: bool = False,\tparities_as_columns: bool = False) -> Any:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.draw", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.draw", "kind": "function", "doc": "

Draws this CX circuit using NetworkX and Matplotlib.\nKeyword arguments kwargs are those of networkx.draw_networkx.

\n", "signature": "(\tself,\tlayout: str = 'kamada_kawai',\t*,\tfigsize: Optional[Tuple[int, int]] = None,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\tfilename: Optional[str] = None,\t**kwargs):", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.from_parity_matrix", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.from_parity_matrix", "kind": "function", "doc": "

Generates a CXCircuit from a given parity matrix, constrained by the given topology

\n\n

Args:\n matrix (np.typing.NDArray): The parity matrix to be synthesized\n topology (Topology): The target device topology\n parities_as_columns (bool, optional): Whether the parities in the matrix are column-wise or row-wise. Defaults to False, i.e. row-wise.\n reallocate (bool, optional): Whether the qubits can be reallocated to different registers, i.e. synthesis up to permutation. Defaults to False.\n method (Literal[\"permrowcol\"], optional): Which synthesis method should be used. Currently only permrowcol is available.

\n\n

Returns:\n CXCircuit: Synthesized circuit

\n", "signature": "(\tmatrix: numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]],\ttopology: pauliopt.topologies.Topology,\tparities_as_columns: bool = False,\treallocate: bool = False,\tmethod: Literal['permrowcol'] = 'permrowcol') -> pauliopt.phase.cx_circuits.CXCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView", "kind": "class", "doc": "

Readonly view on a CX circuit layer.

\n"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.__init__", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.__init__", "kind": "function", "doc": "

\n", "signature": "(layer: pauliopt.phase.cx_circuits.CXCircuitLayer)"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.topology", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.topology", "kind": "variable", "doc": "

Readonly property exposing the qubit topology\nconstraining this CX circuit layer.

\n", "annotation": ": pauliopt.topologies.Topology"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.gates", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.gates", "kind": "variable", "doc": "

Readonly property returning the collection of gates in this\nCX circuit layer.

\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[Tuple[int, int]]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.num_gates", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.num_gates", "kind": "variable", "doc": "

Readonly property returning the number of gates in this\nCX circuit layer.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.flippable_cxs", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.flippable_cxs", "kind": "variable", "doc": "

Readonly property returning the collection of CX gates that\nthat can be currently flipped in this layer, namely:

\n\n
    \n
  • all gates currently in the layer (will be removed by flip);
  • \n
  • all gates with both qubits currently not covered by a gate\nalready in the layer (will be added by flip).
  • \n
\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[Tuple[int, int]]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.incident", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.incident", "kind": "function", "doc": "

Returns the CX gate incident to the given qubit in this layer,\nor None if there is no gate incident to the qubit.

\n", "signature": "(self, qubit: int) -> Optional[Tuple[int, int]]:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.has_cx", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.has_cx", "kind": "function", "doc": "

Checks whether the given CX gate is in the layer:

\n", "signature": "(self, ctrl: int, trgt: int) -> bool:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.is_cx_flippable", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.is_cx_flippable", "kind": "function", "doc": "

Checks whether the given CX gate can be flipped in this layer.\nThis is true if:

\n\n
    \n
  • the gate is present (gate can be removed);
  • \n
  • the gate is not present, and neither the control nor the\ntarget are already covered by some other gate (gate can be added).
  • \n
\n", "signature": "(self, ctrl: int, trgt: int) -> bool:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.clone", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.clone", "kind": "function", "doc": "

Returns a copy of this CX layer.

\n", "signature": "(self) -> pauliopt.phase.cx_circuits.CXCircuitLayer:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.draw", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.draw", "kind": "function", "doc": "

Draws this CX circuit layer using NetworkX and Matplotlib.\nKeyword arguments kwargs are those of networkx.draw_networkx.

\n", "signature": "(\tself,\tlayout: str = 'kamada_kawai',\t*,\tfigsize: Optional[Tuple[int, int]] = None,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\t**kwargs):", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView", "kind": "class", "doc": "

Readonly view on a CX circuit.

\n", "bases": "typing.Sequence[pauliopt.phase.cx_circuits.CXCircuitLayerView]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView.__init__", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView.__init__", "kind": "function", "doc": "

\n", "signature": "(circuit: pauliopt.phase.cx_circuits.CXCircuit)"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView.topology", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView.topology", "kind": "variable", "doc": "

Readonly property exposing the qubit topology\nconstraining this CX circuit.

\n", "annotation": ": pauliopt.topologies.Topology"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView.num_gates", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView.num_gates", "kind": "variable", "doc": "

Readonly property returning the number of gates in this\nCX circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView.dag", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView.dag", "kind": "function", "doc": "

Returns a copy of this CX circuit,\nwith the layers in reverse order.

\n", "signature": "(self) -> pauliopt.phase.cx_circuits.CXCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView.clone", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView.clone", "kind": "function", "doc": "

Returns a copy of this CX circuit.

\n", "signature": "(self) -> pauliopt.phase.cx_circuits.CXCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView.draw", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView.draw", "kind": "function", "doc": "

Draws this CX circuit using NetworkX and Matplotlib.\nKeyword arguments kwargs are those of networkx.draw_networkx.

\n", "signature": "(\tself,\tlayout: str = 'kamada_kawai',\t*,\tfigsize: Optional[Tuple[int, int]] = None,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\t**kwargs):", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits", "modulename": "pauliopt.phase.optimized_circuits", "kind": "module", "doc": "

This module contains code to optimize circuits of mixed ZX phase gadgets\nusing topologically-aware circuits of CNOTs.

\n"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingCostLogger", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingCostLogger", "kind": "class", "doc": "

Protocol for logger of initial/final cost in annealing.

\n", "bases": "typing.Protocol"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingCostLogger.__init__", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingCostLogger.__init__", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs)"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingIterLogger", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingIterLogger", "kind": "class", "doc": "

Protocol for logging of iteration info in annealing.

\n", "bases": "typing.Protocol"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingIterLogger.__init__", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingIterLogger.__init__", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs)"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingLoggers", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingLoggers", "kind": "class", "doc": "

Typed dictionary of loggers for annealing.

\n", "bases": "typing.TypedDict"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingLoggers.log_start", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingLoggers.log_start", "kind": "variable", "doc": "

\n", "annotation": ": pauliopt.phase.optimized_circuits.AnnealingCostLogger"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingLoggers.log_iter", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingLoggers.log_iter", "kind": "variable", "doc": "

\n", "annotation": ": pauliopt.phase.optimized_circuits.AnnealingIterLogger"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingLoggers.log_end", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingLoggers.log_end", "kind": "variable", "doc": "

\n", "annotation": ": pauliopt.phase.optimized_circuits.AnnealingCostLogger"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit", "kind": "class", "doc": "

Container for a phase circuit to be progressively optimized.\nThe original phase circuit is passed to the constructor, together\nwith a qubit topology and a fixed number of layers constraining the\nCX circuit to be used for simplification.

\n\n

To understand the structure of the optimized phase circuit,\nconsider the following code snippet:

\n\n
\n
    opt_circ = PhaseCircuitCXBlockOptimizer(orig_circ, topology, num_cx_layers)\n    # perform optimization using the methods of `opt_circ`\n    phase_block = opt_circ.phase_block\n    cx_block = opt_circ.cx_block\n
\n
\n\n

The optimized circuit is obtained by composing three blocks:

\n\n
    \n
  1. a first block of CX gates, given by cx_block.dag()\n(the same CX gates of cx_block, but in reverse order);
  2. \n
  3. a central block of phase gadgets, given by phase_block;
  4. \n
  5. a final block of CX gates, given by cx_block.
  6. \n
\n\n

An optional keyword argument circuit_rep (default: 1) can be passed to the\nconstructor to indicate that the original circuit is to be repeated a certain\nnumber of times (default: 1). In the optimized circuit, this is achieved by\nrepeating the phase_block part (at point 2. above) a number of times\ngiven by the circuit_rep argument.\nThe first and last CX blocks are left unaltered (because the intermediate CX\nblocks would cancel each other out in pairs when repeating the optimized circuit).

\n"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.__init__", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.__init__", "kind": "function", "doc": "

\n", "signature": "(\tphase_block: Union[pauliopt.phase.phase_circuits.PhaseCircuit, pauliopt.phase.phase_circuits.PhaseCircuitView],\ttopology: pauliopt.topologies.Topology,\tcx_block: Union[int, pauliopt.phase.cx_circuits.CXCircuit, pauliopt.phase.cx_circuits.CXCircuitView],\t*,\tcircuit_rep: int = 1,\trng_seed: Optional[int] = None,\tfresh_angle_vars: Union[NoneType, str, Callable[[int], pauliopt.utils.AngleVar]] = None,\tqubit_mapping: Sequence[int] = None,\tphase_method: Literal['naive', 'paritysynth', 'steiner-graysynth'] = 'naive',\tcx_method: Literal['permrowcol', 'naive'] = 'naive',\treallocate: bool = False)"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.topology", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.topology", "kind": "variable", "doc": "

Readonly property exposing the topology constraining the circuit optimization.

\n", "annotation": ": pauliopt.topologies.Topology"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.num_qubits", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.num_qubits", "kind": "variable", "doc": "

Readonly property exposing the number of qubits spanned by the circuit to be optimized.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.circuit_rep", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.circuit_rep", "kind": "variable", "doc": "

Readonly property exposing the number of times that the original circuit is\nto be repeated, for use when computing CX counts.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.phase_block", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.phase_block", "kind": "variable", "doc": "

Readonly property exposing a readonly view on the phase block of the optimized circuit.

\n", "annotation": ": pauliopt.phase.phase_circuits.PhaseCircuitView"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.cx_block", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.cx_block", "kind": "variable", "doc": "

Readonly property exposing a readonly view on the CX block of the optimized circuit.

\n", "annotation": ": pauliopt.phase.cx_circuits.CXCircuitView"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.init_cx_count", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.init_cx_count", "kind": "variable", "doc": "

Readonly property exposing the CX count for the original circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.cx_count", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.cx_count", "kind": "variable", "doc": "

Readonly property exposing the current CX count for the optimized circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.init_cx_blocks_count", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.init_cx_blocks_count", "kind": "variable", "doc": "

Readonly property exposing the overall CX count for the two conjugating\nCX blocks at the time the circuit was instantiated.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.cx_blocks_count", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.cx_blocks_count", "kind": "variable", "doc": "

Readonly property exposing the overall CX count for the conjugating\nCX blocks in the currently optimized circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.init_phase_block_cx_count", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.init_phase_block_cx_count", "kind": "variable", "doc": "

Readonly property exposing the overall CX count for a single\nphase block at the time the circuit was instantiated.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.phase_block_cx_count", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.phase_block_cx_count", "kind": "variable", "doc": "

Readonly property exposing the overall CX count for a single\nphase block in the currently optimized circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.clone", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.clone", "kind": "function", "doc": "

Returns a copy of this optimized phase circuit.

\n", "signature": "(\tself,\trng_seed: Optional[int] = None) -> pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.to_qiskit", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.to_qiskit", "kind": "function", "doc": "

Returns the optimized circuit as a Qiskit circuit.

\n\n

This method relies on the qiskit library being available.\nSpecifically, the circuit argument must be of type\nqiskit.providers.BaseBackend.

\n", "signature": "(self, simplified: bool = True):", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.simplify", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.simplify", "kind": "function", "doc": "

Simplifies the phase block according to the commutation and fusion\nrules for phase gadgets.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.anneal", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.anneal", "kind": "function", "doc": "

Performs a cycle of simulated annealing optimization,\nusing the given number of iterations, temperature schedule,\ninitial/final temperatures.

\n\n

The circuit is modified in-place and then returned, as per the\nfluent API pattern.

\n", "signature": "(\tself,\tnum_iters: int,\t*,\tschedule: Union[Tuple[Literal['linear', 'geometric', 'reciprocal', 'log'], Union[int, float], Union[int, float]], pauliopt.utils.TempSchedule] = ('linear', 1.0, 0.1),\tloggers: pauliopt.phase.optimized_circuits.AnnealingLoggers = {}):", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.random_flip_cx", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.random_flip_cx", "kind": "function", "doc": "

Randomly flips a CX gate in the CX circuit used for the optimization,\nupdating both the CX circuit and the circuit being optimized.

\n\n

Returns the layer index and gate (pair of control and target) that were\nflipped (e.g. in case the flip needs to be subsequently undone).

\n", "signature": "(self) -> Tuple[int, Tuple[int, int]]:", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.is_cx_flippable", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.is_cx_flippable", "kind": "function", "doc": "

Checks whether the given CX gate can be flipped in the given layer.

\n", "signature": "(self, layer_idx: int, ctrl: int, trgt: int) -> bool:", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.flip_cx", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.flip_cx", "kind": "function", "doc": "

Performs the actions needed to flip the given CX gate in the given layer\nof the CX circuit used for the optimization:

\n\n
    \n
  • undoes all gates in layers subsequent to the given layer which are\ncausally following the given gate, starting from the last layer and\nworking backwards towards the gate;
  • \n
  • applies the desired gate;
  • \n
  • redoes all gate undone, in reverse order (starting from the gate and\nworking forwards towards the last layer).
  • \n
\n", "signature": "(self, layer_idx: int, ctrl: int, trgt: int):", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.to_svg", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.to_svg", "kind": "function", "doc": "

Returns an SVG representation of this optimized circuit, using\nthe ZX calculus to express phase gadgets and CX gates.

\n\n

The keyword arguments zcolor and xcolor can be used to\nspecify a colour for the Z and X basis spiders in the circuit.\nThe keyword arguments hscale and vscale can be used to\nscale the circuit representation horizontally and vertically.\nThe keyword argument scale can be used to scale the circuit\nrepresentation isotropically.\nThe keyword argument svg_code_only (default False) can be used\nto specify that the SVG code itself be returned, rather than the\nIPython SVG object.

\n", "signature": "(\tself,\t*,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\thscale: float = 1.0,\tvscale: float = 1.0,\tscale: float = 1.0,\tsvg_code_only: bool = False):", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.iter_anneal", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "iter_anneal", "kind": "function", "doc": "

\n", "signature": "(\tcircuit: pauliopt.phase.phase_circuits.PhaseCircuit,\ttopology: pauliopt.topologies.Topology,\tcx_blocks,\tnum_iters: int,\tnum_anneal_iters: int,\topt_kwargs: Dict = {},\tanneal_kwargs: Dict = {}) -> pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.reverse_traversal_anneal", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "reverse_traversal_anneal", "kind": "function", "doc": "

\n", "signature": "(\tcircuit: pauliopt.phase.phase_circuits.PhaseCircuit,\ttopology: pauliopt.topologies.Topology,\tcx_blocks,\tnum_iters: int,\tnum_anneal_iters: int,\topt_kwargs: Dict = {},\tanneal_kwargs: Dict = {}) -> pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.reverse_traversal", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "reverse_traversal", "kind": "function", "doc": "

\n", "signature": "(\tcircuit: pauliopt.phase.phase_circuits.PhaseCircuit,\ttopology: pauliopt.topologies.Topology,\tcx_blocks,\tnum_iters: int,\tnum_anneal_iters=0,\topt_kwargs: Dict = {},\tanneal_kwargs: Dict = {}) -> pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits", "modulename": "pauliopt.phase.phase_circuits", "kind": "module", "doc": "

This module contains code to create circuits of mixed ZX phase gadgets.

\n"}, {"fullname": "pauliopt.phase.phase_circuits.synthesis_methods", "modulename": "pauliopt.phase.phase_circuits", "qualname": "synthesis_methods", "kind": "variable", "doc": "

\n", "default_value": "['naive', 'paritysynth', 'steiner-graysynth']"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget", "kind": "class", "doc": "

Immutable container class for a phase gadget.

\n"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.__init__", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.__init__", "kind": "function", "doc": "

\n", "signature": "(\tbasis: Literal['Z', 'X'],\tangle: pauliopt.utils.AngleExpr,\tqubits: Collection[int])"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.basis", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.basis", "kind": "variable", "doc": "

Readonly property exposing the basis for this phase gadget.

\n", "annotation": ": Literal['Z', 'X']"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.angle", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.angle", "kind": "variable", "doc": "

Readonly property exposing the angle for this phase gadget.

\n", "annotation": ": pauliopt.utils.AngleExpr"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.qubits", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.qubits", "kind": "variable", "doc": "

Readonly property exposing the qubits spanned by this phase gadget.

\n", "annotation": ": FrozenSet[int]"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.cx_count", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.cx_count", "kind": "function", "doc": "

Returns the CX count for an implementation of this phase gadget\non the given topology based on minimum spanning trees (MST).

\n\n

The optional mapping keyword argument can be used to specify a mapping of\nlogical (circuit) qubits to phyisical (topology) qubits.

\n", "signature": "(\tself,\ttopology: pauliopt.topologies.Topology,\t*,\tmapping: Union[Sequence[int], Dict[int, int], NoneType] = None) -> int:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.on_qiskit_circuit", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.on_qiskit_circuit", "kind": "function", "doc": "

Applies this phase gadget to a given qiskit quantum circuit,\nusing the given topology to determine a minimum spanning\ntree implementation of the gadget.

\n\n

This method relies on the qiskit library being available.\nSpecifically, the circuit argument must be of type\nqiskit.providers.BaseBackend.

\n", "signature": "(self, topology: pauliopt.topologies.Topology, circuit: Any) -> None:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.print_impl_info", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.print_impl_info", "kind": "function", "doc": "

Prints information about an implementation of this phase gadget\non the given topology based on minimum spanning trees (MST).

\n", "signature": "(self, topology: pauliopt.topologies.Topology) -> None:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.Z", "modulename": "pauliopt.phase.phase_circuits", "qualname": "Z", "kind": "class", "doc": "

Constructs a Z phase gadget with the idiomatic syntax:

\n\n
\n
    Z(angle) @ qubits\n
\n
\n"}, {"fullname": "pauliopt.phase.phase_circuits.Z.__init__", "modulename": "pauliopt.phase.phase_circuits", "qualname": "Z.__init__", "kind": "function", "doc": "

\n", "signature": "(angle: pauliopt.utils.AngleExpr)"}, {"fullname": "pauliopt.phase.phase_circuits.X", "modulename": "pauliopt.phase.phase_circuits", "qualname": "X", "kind": "class", "doc": "

Constructs an X phase gadget with the idiomatic syntax:

\n\n
\n
    X(angle) @ qubits\n
\n
\n"}, {"fullname": "pauliopt.phase.phase_circuits.X.__init__", "modulename": "pauliopt.phase.phase_circuits", "qualname": "X.__init__", "kind": "function", "doc": "

\n", "signature": "(angle: pauliopt.utils.AngleExpr)"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit", "kind": "class", "doc": "

Container class for a circuit of mixed ZX phase gadgets.

\n", "bases": "typing.Sequence[pauliopt.phase.phase_circuits.PhaseGadget]"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.__init__", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.__init__", "kind": "function", "doc": "

\n", "signature": "(\tnum_qubits: int,\tgadgets: Sequence[pauliopt.phase.phase_circuits.PhaseGadget] = ())"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.num_qubits", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.num_qubits", "kind": "variable", "doc": "

Readonly property exposing the number of qubits spanned by this phase circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.num_gadgets", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.num_gadgets", "kind": "variable", "doc": "

Readonly property exposing the number of phase gadgets in the circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.gadgets", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.gadgets", "kind": "variable", "doc": "

Readonly property returning the sequence of phase gadgets in this\nphase circuit, in order from first to last.

\n\n

This collection is freshly generated at every call.

\n", "annotation": ": Sequence[pauliopt.phase.phase_circuits.PhaseGadget]"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.as_readonly", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.as_readonly", "kind": "variable", "doc": "

Returns a readonly view on this circuit.

\n", "annotation": ": pauliopt.phase.phase_circuits.PhaseCircuitView"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.set_angles", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.set_angles", "kind": "function", "doc": "

Sets all angles for this circuit.

\n", "signature": "(self, angles: Sequence[pauliopt.utils.AngleExpr]) -> None:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.refresh_angle_vars", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.refresh_angle_vars", "kind": "function", "doc": "

\n", "signature": "(\tself,\tparams: Union[str, Callable[[int], pauliopt.utils.AngleVar]]) -> None:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.rx", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.rx", "kind": "function", "doc": "

Phase gadget implementation of single-qubit X rotation.

\n", "signature": "(\tself,\tqubit: int,\tangle: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.rz", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.rz", "kind": "function", "doc": "

Phase gadget implementation of single-qubit Z rotation.

\n", "signature": "(\tself,\tqubit: int,\tangle: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.ry", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.ry", "kind": "function", "doc": "

Phase gadget implementation of single-qubit Y rotation.

\n", "signature": "(\tself,\tqubit: int,\tangle: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.i", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.i", "kind": "function", "doc": "

Phase gadget implementation of single-qubit I gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.x", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.x", "kind": "function", "doc": "

Phase gadget implementation of single-qubit X gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.z", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.z", "kind": "function", "doc": "

Phase gadget implementation of single-qubit X gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.y", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.y", "kind": "function", "doc": "

Phase gadget implementation of single-qubit Y gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.s", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.s", "kind": "function", "doc": "

Phase gadget implementation of single-qubit S gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.sdg", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.sdg", "kind": "function", "doc": "

Phase gadget implementation of single-qubit Sdg gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.v", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.v", "kind": "function", "doc": "

Phase gadget implementation of single-qubit S gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.vdg", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.vdg", "kind": "function", "doc": "

Phase gadget implementation of single-qubit Sdg gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.t", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.t", "kind": "function", "doc": "

Phase gadget implementation of single-qubit T gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.h", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.h", "kind": "function", "doc": "

Phase gadget implementation of single-qubit Hadamard gate.

\n", "signature": "(\tself,\tqubit: int,\tbasis: Literal['Z', 'X'] = 'Z',\tsign: Literal[1, -1] = 1) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cu1", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cu1", "kind": "function", "doc": "

Phase gadget implementation of CU1 gate.

\n", "signature": "(\tself,\tctrl: int,\ttgt: int,\tangle: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.crz", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.crz", "kind": "function", "doc": "

Phase gadget implementation of CRZ gate.

\n", "signature": "(\tself,\tctrl: int,\ttgt: int,\tangle: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cry", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cry", "kind": "function", "doc": "

Phase gadget implementation of CRY gate.

\n", "signature": "(\tself,\tctrl: int,\ttgt: int,\tangle: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.crx", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.crx", "kind": "function", "doc": "

Phase gadget implementation of CRX gate.

\n", "signature": "(\tself,\tctrl: int,\ttgt: int,\tangle: pauliopt.utils.Angle) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cz", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cz", "kind": "function", "doc": "

Phase gadget implementation of CZ gate.

\n", "signature": "(self, leg1: int, leg2: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cy", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cy", "kind": "function", "doc": "

Phase gadget implementation of CY gate.

\n", "signature": "(self, leg1: int, leg2: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cx", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cx", "kind": "function", "doc": "

Phase gadget implementation of CX gate.

\n", "signature": "(self, ctrl: int, tgt: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.u3", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.u3", "kind": "function", "doc": "

Phase gadget implementation of U3 gate.

\n", "signature": "(\tself,\tqubit: int,\ttheta: pauliopt.utils.AngleExpr,\tphi: pauliopt.utils.AngleExpr,\tlam: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.ccz", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.ccz", "kind": "function", "doc": "

Phase gadget implementation of CCZ gate.

\n", "signature": "(\tself,\tleg1: int,\tleg2: int,\tleg3: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.ccy", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.ccy", "kind": "function", "doc": "

Phase gadget implementation of CCX gate.

\n", "signature": "(\tself,\tleg1: int,\tleg2: int,\tleg3: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.ccx", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.ccx", "kind": "function", "doc": "

Phase gadget implementation of CCX gate.

\n", "signature": "(\tself,\tleg1: int,\tleg2: int,\tleg3: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.add_gadget", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.add_gadget", "kind": "function", "doc": "

Adds a phase gadget to the circuit.\nThis is rather less efficient than passing the gadgets in the constructor,\nbecause the internal numpy arrays have to be copied in the process.

\n\n

The circuit is modified in-place and then returned, as per the\nfluent interface pattern.

\n", "signature": "(\tself,\tgadget: pauliopt.phase.phase_circuits.PhaseGadget) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.copy", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.copy", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cx_count", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cx_count", "kind": "function", "doc": "

Returns the CX count for an implementation of this phase gadget\n on the given topology based on minimum spanning trees (MST).

\n\n
The optional `mapping` keyword argument can be used to specify a mapping of\nlogical (circuit) qubits to phyisical (topology) qubits.\n
\n\n

Args:\n topology (Topology): Target device topology\n mapping (Optional[Union[Sequence[int], Dict[int, int]]], optional): Used qubit mapping. Defaults to None.\n method (Literal[\"naive\", \"paritysynth\", \"steiner\", optional): Synthesis method. Defaults to \"naive\".

\n\n

Raises:\n TypeError: If topology is not a Topology and if mapping is not a permutation of range(self.num_qubits).

\n\n

Returns:\n int: The CX count.

\n", "signature": "(\tself,\ttopology: pauliopt.topologies.Topology,\t*,\tmapping: Union[Sequence[int], Dict[int, int], NoneType] = None,\tmethod: Literal['naive', 'paritysynth', 'steiner-graysynth'] = 'naive') -> int:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.mapped", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.mapped", "kind": "function", "doc": "

Returns a new phase circuit with the same gadgets but having\nqubits remapped according to the given mapping.

\n", "signature": "(\tself,\tmapping: Union[Sequence[int], Mapping[int, int]]) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.color_flip", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.color_flip", "kind": "function", "doc": "

Returns a new phase circuit with the same gadgets but having\nall basis switched from Z to X and vice versa.

\n", "signature": "(self) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.dagger", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.dagger", "kind": "function", "doc": "

Returns a new phase circuit with the same gadgets but having\nall angles negated.

\n", "signature": "(self) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.normalize", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.normalize", "kind": "function", "doc": "

Fuse and reorder gadgets of the same basis.

\n", "signature": "(self) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.to_qiskit", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.to_qiskit", "kind": "function", "doc": "

Generates a qiskit QuantumCircuit equivalent to this PhaseCircuit.

\n\n

Args:\n topology (Topology): Target device topology\n simplified (bool, optional): Simplifiy the PhaseCircuit before synthesis. Defaults to True.\n method (Literal[\"naive\", \"paritysynth\", \"steiner\", optional): Which method of synthesis should be used. Defaults to \"naive\".\n cx_synth (Literal[\"permrowcol\", \"naive\"], optional): Which method should be used for synthesizing the final CXCircuit. Defaults to \"naive\".\n return_cx (bool, optional): Whether to return the final CXCircuit separately without synthesizing it. Defaults to False.\n reallocate (bool, optional): Whether qubit reallocation is allowed when synthesizing the final CXCircuit. Defaults to False.

\n\n

Raises:\n ModuleNotFoundError: Requires Qiskit to be installed

\n\n

Returns:\n qiskit.QuantumCircuit: The synthesized equivalent circuit\n CXCircuit (optional): The final CNOTs of the circuit not yet concatinated to the qiskit circuit.

\n", "signature": "(\tself,\ttopology: pauliopt.topologies.Topology,\tsimplified: bool = True,\tmethod: Literal['naive', 'paritysynth', 'steiner-graysynth'] = 'naive',\tcx_synth: Literal['permrowcol', 'naive'] = 'naive',\treturn_cx: bool = False,\treallocate: bool = False) -> Any:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.to_svg", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.to_svg", "kind": "function", "doc": "

Returns an SVG representation of this circuit, using\nthe ZX calculus to express phase gadgets.

\n\n

The keyword arguments zcolor and xcolor can be used to\nspecify a colour for the Z and X basis spiders in the circuit.\nThe keyword arguments hscale and vscale can be used to\nscale the circuit representation horizontally and vertically.\nThe keyword argument scale can be used to scale the circuit\nrepresentation isotropically.\nThe keyword argument svg_code_only (default False) can be used\nto specify that the SVG code itself be returned, rather than the\nIPython SVG object.

\n", "signature": "(\tself,\t*,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\thscale: float = 1.0,\tvscale: float = 1.0,\tscale: float = 1.0,\tsvg_code_only: bool = False) -> Any:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cloned", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cloned", "kind": "function", "doc": "

Produces an exact copy of this phase circuit.

\n", "signature": "(self) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.conj_by_cx", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.conj_by_cx", "kind": "function", "doc": "

Conjugates this circuit by a CX gate with given control/target.\nThe circuit is modified in-place and then returned, as per the\nfluent interface pattern.

\n", "signature": "(self, ctrl: int, trgt: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.simplified", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.simplified", "kind": "function", "doc": "

Returns a new phase circuit which has been simplified using the\ncommutation and fusion rules for gadgets.

\n", "signature": "(self) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.random", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.random", "kind": "function", "doc": "

Generates a random circuit of mixed ZX phase gadgets on the given number of qubits,\nwith the given number of gadgets.

\n\n

The optional argument angle_subdivision (default: 4) can be used to specify the\ndenominator in the random fractional multiples of pi used as values for the angles.

\n\n

The optional arguments min_legs (default: 1, minimum: 1) and max_legs\n(default: None, minimum min_legs) can be used to specify the minimum and maximum\nnumber of legs for the phase gadgets. If None, max_legs is set to len(qubits).

\n\n

The optional argument rng_seed (default: None) is used as seed for the RNG.

\n", "signature": "(\tnum_qubits: int,\tnum_gadgets: int,\t*,\tparametric: Union[NoneType, str, Callable[[int], pauliopt.utils.AngleVar]] = None,\tangle_subdivision: int = 4,\tmin_legs: int = 1,\tmax_legs: Optional[int] = None,\tdiagonal: bool = False,\trng_seed: Optional[int] = None) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.from_qasm", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.from_qasm", "kind": "function", "doc": "

Constructs a phase circuit from a QASM program.

\n\n

An optional mapping from QASM qubits to circuit qubits can be supplied.

\n", "signature": "(\tqasm: Union[str, pauliopt.qasm.QASM],\t*,\tmapping: Union[Sequence[int], Mapping[int, int], NoneType] = None,\tallow_classical: bool = True) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView", "kind": "class", "doc": "

Readonly view on a phase circuit.

\n"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView.__init__", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView.__init__", "kind": "function", "doc": "

\n", "signature": "(circuit: pauliopt.phase.phase_circuits.PhaseCircuit)"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView.num_qubits", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView.num_qubits", "kind": "variable", "doc": "

Readonly property exposing the number of qubits spanned by the phase circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView.num_gadgets", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView.num_gadgets", "kind": "variable", "doc": "

Readonly property exposing the number of phase gadgets in the circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView.gadgets", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView.gadgets", "kind": "variable", "doc": "

Readonly property returning the sequence of phase gadgets in the\nphase circuit, in order from first to last.

\n\n

This collection is freshly generated at every call.

\n", "annotation": ": Sequence[pauliopt.phase.phase_circuits.PhaseGadget]"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView.to_svg", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView.to_svg", "kind": "function", "doc": "

Returns an SVG representation of this circuit, using\nthe ZX calculus to express phase gadgets.

\n\n

The keyword arguments zcolor and xcolor can be used to\nspecify a colour for the Z and X basis spiders in the circuit.\nThe keyword arguments hscale and vscale can be used to\nscale the circuit representation horizontally and vertically.\nThe keyword argument svg_code_only (default False) can be used\nto specify that the SVG code itself be returned, rather than the\nIPython SVG object.

\n", "signature": "(\tself,\t*,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\thscale: float = 1.0,\tvscale: float = 1.0,\tscale: float = 1.0,\tsvg_code_only: bool = False) -> Any:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView.cloned", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView.cloned", "kind": "function", "doc": "

Produces an exact copy of the phase circuit.

\n", "signature": "(self) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.qasm", "modulename": "pauliopt.qasm", "kind": "module", "doc": "

QASM file parsing

\n"}, {"fullname": "pauliopt.qasm.assert_same_size_targets", "modulename": "pauliopt.qasm", "qualname": "assert_same_size_targets", "kind": "function", "doc": "

Asserts that all register targets have the same size.

\n", "signature": "(*trgts: pauliopt.qasm.QASM.RegTarget):", "funcdef": "def"}, {"fullname": "pauliopt.qasm.QASM", "modulename": "pauliopt.qasm", "qualname": "QASM", "kind": "class", "doc": "

QASM program.\nBased on the QASM spec from arXiv: 1707.03429

\n", "bases": "typing.Sequence[ForwardRef('QASM.Statement')]"}, {"fullname": "pauliopt.qasm.QASM.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.__init__", "kind": "function", "doc": "

\n", "signature": "(*statements: pauliopt.qasm.QASM.Statement)"}, {"fullname": "pauliopt.qasm.QASM.num_qubits", "modulename": "pauliopt.qasm", "qualname": "QASM.num_qubits", "kind": "variable", "doc": "

Number of qubits in this circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.qasm.QASM.num_bits", "modulename": "pauliopt.qasm", "qualname": "QASM.num_bits", "kind": "variable", "doc": "

Number of bits in this circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.qasm.QASM.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.registers", "kind": "variable", "doc": "

Iterator over the registers of this QASM program.

\n", "annotation": ": Iterator[Union[pauliopt.qasm.QASM.QReg, pauliopt.qasm.QASM.CReg]]"}, {"fullname": "pauliopt.qasm.QASM.Statement", "modulename": "pauliopt.qasm", "qualname": "QASM.Statement", "kind": "class", "doc": "

QASM statement.

\n"}, {"fullname": "pauliopt.qasm.QASM.Statement.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Statement.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Statement.parse", "modulename": "pauliopt.qasm", "qualname": "QASM.Statement.parse", "kind": "function", "doc": "

Attempts to parse a QASM statement from a line of code.

\n", "signature": "(line: str) -> pauliopt.qasm.QASM.Statement:", "funcdef": "def"}, {"fullname": "pauliopt.qasm.QASM.Version", "modulename": "pauliopt.qasm", "qualname": "QASM.Version", "kind": "class", "doc": "

QASM version statement.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Version.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Version.__init__", "kind": "function", "doc": "

\n", "signature": "(version: str)"}, {"fullname": "pauliopt.qasm.QASM.Version.version", "modulename": "pauliopt.qasm", "qualname": "QASM.Version.version", "kind": "variable", "doc": "

QASM version.

\n", "annotation": ": str"}, {"fullname": "pauliopt.qasm.QASM.Reg", "modulename": "pauliopt.qasm", "qualname": "QASM.Reg", "kind": "class", "doc": "

Register.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Reg.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Reg.__init__", "kind": "function", "doc": "

\n", "signature": "(name: str, size: int)"}, {"fullname": "pauliopt.qasm.QASM.Reg.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Reg.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Reg.name", "modulename": "pauliopt.qasm", "qualname": "QASM.Reg.name", "kind": "variable", "doc": "

Register name.

\n"}, {"fullname": "pauliopt.qasm.QASM.Reg.size", "modulename": "pauliopt.qasm", "qualname": "QASM.Reg.size", "kind": "variable", "doc": "

Register size.

\n"}, {"fullname": "pauliopt.qasm.QASM.QReg", "modulename": "pauliopt.qasm", "qualname": "QASM.QReg", "kind": "class", "doc": "

Quantum register.

\n", "bases": "QASM.Reg"}, {"fullname": "pauliopt.qasm.QASM.QReg.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.QReg.__init__", "kind": "function", "doc": "

\n", "signature": "(name: str, size: int)"}, {"fullname": "pauliopt.qasm.QASM.CReg", "modulename": "pauliopt.qasm", "qualname": "QASM.CReg", "kind": "class", "doc": "

Classical register.

\n", "bases": "QASM.Reg"}, {"fullname": "pauliopt.qasm.QASM.CReg.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.CReg.__init__", "kind": "function", "doc": "

\n", "signature": "(name: str, size: int)"}, {"fullname": "pauliopt.qasm.QASM.Include", "modulename": "pauliopt.qasm", "qualname": "QASM.Include", "kind": "class", "doc": "

QASM include statement.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Include.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Include.__init__", "kind": "function", "doc": "

\n", "signature": "(filename: str)"}, {"fullname": "pauliopt.qasm.QASM.Include.filename", "modulename": "pauliopt.qasm", "qualname": "QASM.Include.filename", "kind": "variable", "doc": "

Filename.

\n", "annotation": ": str"}, {"fullname": "pauliopt.qasm.QASM.Comment", "modulename": "pauliopt.qasm", "qualname": "QASM.Comment", "kind": "class", "doc": "

QASM comment statement.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Comment.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Comment.__init__", "kind": "function", "doc": "

\n", "signature": "(text: str)"}, {"fullname": "pauliopt.qasm.QASM.Comment.text", "modulename": "pauliopt.qasm", "qualname": "QASM.Comment.text", "kind": "variable", "doc": "

Comment text.

\n", "annotation": ": str"}, {"fullname": "pauliopt.qasm.QASM.RegTarget", "modulename": "pauliopt.qasm", "qualname": "QASM.RegTarget", "kind": "class", "doc": "

A qreg or creg target.

\n"}, {"fullname": "pauliopt.qasm.QASM.RegTarget.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.RegTarget.__init__", "kind": "function", "doc": "

\n", "signature": "(\tregister: Union[pauliopt.qasm.QASM.QReg, pauliopt.qasm.QASM.CReg],\tpos: Optional[int] = None)"}, {"fullname": "pauliopt.qasm.QASM.RegTarget.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.RegTarget.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.RegTarget.register", "modulename": "pauliopt.qasm", "qualname": "QASM.RegTarget.register", "kind": "variable", "doc": "

Register.

\n", "annotation": ": Union[pauliopt.qasm.QASM.QReg, pauliopt.qasm.QASM.CReg]"}, {"fullname": "pauliopt.qasm.QASM.RegTarget.pos", "modulename": "pauliopt.qasm", "qualname": "QASM.RegTarget.pos", "kind": "variable", "doc": "

Optional register position.

\n", "annotation": ": Optional[int]"}, {"fullname": "pauliopt.qasm.QASM.RegTarget.size", "modulename": "pauliopt.qasm", "qualname": "QASM.RegTarget.size", "kind": "variable", "doc": "

Size of this target

\n"}, {"fullname": "pauliopt.qasm.QASM.QRegTarget", "modulename": "pauliopt.qasm", "qualname": "QASM.QRegTarget", "kind": "class", "doc": "

A qreg target.

\n", "bases": "QASM.RegTarget"}, {"fullname": "pauliopt.qasm.QASM.QRegTarget.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.QRegTarget.__init__", "kind": "function", "doc": "

\n", "signature": "(register: pauliopt.qasm.QASM.QReg, pos: Optional[int] = None)"}, {"fullname": "pauliopt.qasm.QASM.QRegTarget.register", "modulename": "pauliopt.qasm", "qualname": "QASM.QRegTarget.register", "kind": "variable", "doc": "

Register.

\n", "annotation": ": pauliopt.qasm.QASM.QReg"}, {"fullname": "pauliopt.qasm.QASM.CRegTarget", "modulename": "pauliopt.qasm", "qualname": "QASM.CRegTarget", "kind": "class", "doc": "

A creg target.

\n", "bases": "QASM.RegTarget"}, {"fullname": "pauliopt.qasm.QASM.CRegTarget.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.CRegTarget.__init__", "kind": "function", "doc": "

\n", "signature": "(register: pauliopt.qasm.QASM.CReg, pos: Optional[int] = None)"}, {"fullname": "pauliopt.qasm.QASM.CRegTarget.register", "modulename": "pauliopt.qasm", "qualname": "QASM.CRegTarget.register", "kind": "variable", "doc": "

Register.

\n", "annotation": ": pauliopt.qasm.QASM.CReg"}, {"fullname": "pauliopt.qasm.QASM.UGate", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate", "kind": "class", "doc": "

Statement for a U3 gate.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.UGate.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate.__init__", "kind": "function", "doc": "

\n", "signature": "(\ttheta: pauliopt.utils.Angle,\tphi: pauliopt.utils.Angle,\tlam: pauliopt.utils.Angle,\tqubit: pauliopt.qasm.QASM.QRegTarget)"}, {"fullname": "pauliopt.qasm.QASM.UGate.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.UGate.theta", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate.theta", "kind": "variable", "doc": "

Theta angle for the U3 gate.

\n", "annotation": ": pauliopt.utils.Angle"}, {"fullname": "pauliopt.qasm.QASM.UGate.phi", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate.phi", "kind": "variable", "doc": "

Phi angle for the U3 gate.

\n", "annotation": ": pauliopt.utils.Angle"}, {"fullname": "pauliopt.qasm.QASM.UGate.lam", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate.lam", "kind": "variable", "doc": "

Lambda angle for the U3 gate.

\n", "annotation": ": pauliopt.utils.Angle"}, {"fullname": "pauliopt.qasm.QASM.UGate.qubit", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate.qubit", "kind": "variable", "doc": "

Qubit/qreg for the U3 gate.

\n", "annotation": ": pauliopt.qasm.QASM.QRegTarget"}, {"fullname": "pauliopt.qasm.QASM.CXGate", "modulename": "pauliopt.qasm", "qualname": "QASM.CXGate", "kind": "class", "doc": "

Statement for a CX gate.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.CXGate.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.CXGate.__init__", "kind": "function", "doc": "

\n", "signature": "(\tcontrol: pauliopt.qasm.QASM.QRegTarget,\ttarget: pauliopt.qasm.QASM.QRegTarget)"}, {"fullname": "pauliopt.qasm.QASM.CXGate.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.CXGate.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.CXGate.control", "modulename": "pauliopt.qasm", "qualname": "QASM.CXGate.control", "kind": "variable", "doc": "

Control qubit/qreg for the CX gate.

\n", "annotation": ": pauliopt.qasm.QASM.QRegTarget"}, {"fullname": "pauliopt.qasm.QASM.CXGate.target", "modulename": "pauliopt.qasm", "qualname": "QASM.CXGate.target", "kind": "variable", "doc": "

Target qubit/qreg for the CX gate.

\n", "annotation": ": pauliopt.qasm.QASM.QRegTarget"}, {"fullname": "pauliopt.qasm.QASM.Measure", "modulename": "pauliopt.qasm", "qualname": "QASM.Measure", "kind": "class", "doc": "

Statement for a measurement.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Measure.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Measure.__init__", "kind": "function", "doc": "

\n", "signature": "(\tqubit: pauliopt.qasm.QASM.QRegTarget,\tbit: pauliopt.qasm.QASM.CRegTarget)"}, {"fullname": "pauliopt.qasm.QASM.Measure.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Measure.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Measure.qubit", "modulename": "pauliopt.qasm", "qualname": "QASM.Measure.qubit", "kind": "variable", "doc": "

Qubit/qreg to be measured.

\n", "annotation": ": pauliopt.qasm.QASM.QRegTarget"}, {"fullname": "pauliopt.qasm.QASM.Measure.bit", "modulename": "pauliopt.qasm", "qualname": "QASM.Measure.bit", "kind": "variable", "doc": "

Bit/creg to store measurement outcome.

\n", "annotation": ": pauliopt.qasm.QASM.CRegTarget"}, {"fullname": "pauliopt.qasm.QASM.Reset", "modulename": "pauliopt.qasm", "qualname": "QASM.Reset", "kind": "class", "doc": "

Statement for a reset.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Reset.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Reset.__init__", "kind": "function", "doc": "

\n", "signature": "(qubit: pauliopt.qasm.QASM.QRegTarget)"}, {"fullname": "pauliopt.qasm.QASM.Reset.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Reset.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Reset.qubit", "modulename": "pauliopt.qasm", "qualname": "QASM.Reset.qubit", "kind": "variable", "doc": "

Qubit/qreg to be measured.

\n", "annotation": ": pauliopt.qasm.QASM.QRegTarget"}, {"fullname": "pauliopt.qasm.QASM.Gate", "modulename": "pauliopt.qasm", "qualname": "QASM.Gate", "kind": "class", "doc": "

Statement for a named gate.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Gate.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Gate.__init__", "kind": "function", "doc": "

\n", "signature": "(\tname: str,\ttargets: Sequence[pauliopt.qasm.QASM.RegTarget],\tparams: Sequence[pauliopt.utils.Angle] = ())"}, {"fullname": "pauliopt.qasm.QASM.Gate.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Gate.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Gate.name", "modulename": "pauliopt.qasm", "qualname": "QASM.Gate.name", "kind": "variable", "doc": "

Name for this gate.

\n", "annotation": ": str"}, {"fullname": "pauliopt.qasm.QASM.Gate.params", "modulename": "pauliopt.qasm", "qualname": "QASM.Gate.params", "kind": "variable", "doc": "

Tuple of angle parameters for this gate.

\n", "annotation": ": Tuple[pauliopt.utils.Angle, ...]"}, {"fullname": "pauliopt.qasm.QASM.Gate.targets", "modulename": "pauliopt.qasm", "qualname": "QASM.Gate.targets", "kind": "variable", "doc": "

Tuple of register targets for this gate.

\n", "annotation": ": Tuple[pauliopt.qasm.QASM.RegTarget, ...]"}, {"fullname": "pauliopt.qasm.QASM.Barrier", "modulename": "pauliopt.qasm", "qualname": "QASM.Barrier", "kind": "class", "doc": "

Statement for a barrier.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Barrier.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Barrier.__init__", "kind": "function", "doc": "

\n", "signature": "(targets: Sequence[pauliopt.qasm.QASM.QRegTarget])"}, {"fullname": "pauliopt.qasm.QASM.Barrier.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Barrier.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Barrier.targets", "modulename": "pauliopt.qasm", "qualname": "QASM.Barrier.targets", "kind": "variable", "doc": "

Tuple of register targets for this barrier.

\n", "annotation": ": Tuple[pauliopt.qasm.QASM.RegTarget, ...]"}, {"fullname": "pauliopt.qasm.QASM.Conditional", "modulename": "pauliopt.qasm", "qualname": "QASM.Conditional", "kind": "class", "doc": "

Statement for a conditional statement.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Conditional.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Conditional.__init__", "kind": "function", "doc": "

\n", "signature": "(\tregister: pauliopt.qasm.QASM.CReg,\tvalue: int,\tstatement: pauliopt.qasm.QASM.Statement)"}, {"fullname": "pauliopt.qasm.QASM.Conditional.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Conditional.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Conditional.register", "modulename": "pauliopt.qasm", "qualname": "QASM.Conditional.register", "kind": "variable", "doc": "

The register being tested in this conditional statement.

\n", "annotation": ": pauliopt.qasm.QASM.CReg"}, {"fullname": "pauliopt.qasm.QASM.Conditional.value", "modulename": "pauliopt.qasm", "qualname": "QASM.Conditional.value", "kind": "variable", "doc": "

The register value being tested in this conditional statement.

\n", "annotation": ": int"}, {"fullname": "pauliopt.qasm.QASM.Conditional.statement", "modulename": "pauliopt.qasm", "qualname": "QASM.Conditional.statement", "kind": "variable", "doc": "

The statement to execute if the given creg has the given value.

\n", "annotation": ": pauliopt.qasm.QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.parse", "modulename": "pauliopt.qasm", "qualname": "QASM.parse", "kind": "function", "doc": "

Parses a QASM program into a QASM object.

\n", "signature": "(program: str):", "funcdef": "def"}, {"fullname": "pauliopt.topologies", "modulename": "pauliopt.topologies", "kind": "module", "doc": "

This module contains utility code to deal with qubit topologies.

\n"}, {"fullname": "pauliopt.topologies.Coupling", "modulename": "pauliopt.topologies", "qualname": "Coupling", "kind": "class", "doc": "

Type for couplings in a qubit topology, i.e. unordered\npairs of adjacent qubits.

\n", "bases": "typing.FrozenSet[int]"}, {"fullname": "pauliopt.topologies.Coupling.as_pair", "modulename": "pauliopt.topologies", "qualname": "Coupling.as_pair", "kind": "variable", "doc": "

Returns the coupling as a (increasingly) ordered pair.

\n", "annotation": ": Tuple[int, int]"}, {"fullname": "pauliopt.topologies.CouplingLike", "modulename": "pauliopt.topologies", "qualname": "CouplingLike", "kind": "variable", "doc": "

Type alias for things that could be used to specify couplings,\nnamely any collection of int (subject to additional restrictions).

\n\n

In an ideal world, this should be \"int collections of len 2\",\nbut static typing does not yet allow for such a constraint.

\n", "default_value": "typing.Collection[int]"}, {"fullname": "pauliopt.topologies.TopologyDict", "modulename": "pauliopt.topologies", "qualname": "TopologyDict", "kind": "class", "doc": "

The type of the dictionary returned by Topology.as_dict,\nsuitable for JSON serialization.

\n", "bases": "typing.TypedDict"}, {"fullname": "pauliopt.topologies.TopologyDict.num_qubits", "modulename": "pauliopt.topologies", "qualname": "TopologyDict.num_qubits", "kind": "variable", "doc": "

Property exposing the number of qubits in the topology.

\n", "annotation": ": int"}, {"fullname": "pauliopt.topologies.TopologyDict.couplings", "modulename": "pauliopt.topologies", "qualname": "TopologyDict.couplings", "kind": "variable", "doc": "

Property exposing the couplings between qubits in the topology.

\n", "annotation": ": List[List[int]]"}, {"fullname": "pauliopt.topologies.Layouts", "modulename": "pauliopt.topologies", "qualname": "Layouts", "kind": "variable", "doc": "

Possible layout values for Topology.draw

\n", "annotation": ": Final[Tuple[str, ...]]", "default_value": "('circular', 'kamada_kawai', 'random', 'shell', 'spring', 'spectral', 'spiral')"}, {"fullname": "pauliopt.topologies.Topology", "modulename": "pauliopt.topologies", "qualname": "Topology", "kind": "class", "doc": "

Container class for a qubit topology.

\n"}, {"fullname": "pauliopt.topologies.Topology.__init__", "modulename": "pauliopt.topologies", "qualname": "Topology.__init__", "kind": "function", "doc": "

\n", "signature": "(num_qubits: int, couplings: Collection[Collection[int]])"}, {"fullname": "pauliopt.topologies.Topology.num_qubits", "modulename": "pauliopt.topologies", "qualname": "Topology.num_qubits", "kind": "variable", "doc": "

Readonly property returning the number of qubits in this topology.

\n", "annotation": ": int"}, {"fullname": "pauliopt.topologies.Topology.qubits", "modulename": "pauliopt.topologies", "qualname": "Topology.qubits", "kind": "variable", "doc": "

Readonly property returning the range of qubits in this topology.

\n", "annotation": ": range"}, {"fullname": "pauliopt.topologies.Topology.couplings", "modulename": "pauliopt.topologies", "qualname": "Topology.couplings", "kind": "variable", "doc": "

Readonly property exposing the couplings between qubits in this topology.

\n", "annotation": ": FrozenSet[pauliopt.topologies.Coupling]"}, {"fullname": "pauliopt.topologies.Topology.as_dict", "modulename": "pauliopt.topologies", "qualname": "Topology.as_dict", "kind": "variable", "doc": "

Readonly property returning this topology as\na dictionary, for serialization purposes.

\n", "annotation": ": Union[str, pauliopt.topologies.TopologyDict]"}, {"fullname": "pauliopt.topologies.Topology.is_planar", "modulename": "pauliopt.topologies", "qualname": "Topology.is_planar", "kind": "variable", "doc": "

Whether this qubit topology is a planar graph.

\n", "annotation": ": bool"}, {"fullname": "pauliopt.topologies.Topology.available_nx_layouts", "modulename": "pauliopt.topologies", "qualname": "Topology.available_nx_layouts", "kind": "variable", "doc": "

Readonly property returning the available layouts for this qubit topology.

\n", "annotation": ": Tuple[str, ...]"}, {"fullname": "pauliopt.topologies.Topology.to_nx", "modulename": "pauliopt.topologies", "qualname": "Topology.to_nx", "kind": "variable", "doc": "

Readonly property returning a NetworkX graph version of this topology.\nRequires the 'networkx' library to work.

\n"}, {"fullname": "pauliopt.topologies.Topology.draw", "modulename": "pauliopt.topologies", "qualname": "Topology.draw", "kind": "function", "doc": "

Draws this qubit topology using NetworkX and Matplotlib.

\n\n

The layout keyword argument can be used to select a NetworkX layout\nfrom the available ones (exposed by Topology.available_nx_layouts).\nThe figsize keyword argument is passed to matplotlib.pyplot.figure:\nif specified, it determines the width and height of the figure being drawn.\nKeyword arguments kwargs are those of networkx.draw_networkx.\nIf the keyword argument filename is set, the figure is also saved.

\n", "signature": "(\tself,\tlayout: str = 'kamada_kawai',\t*,\tfigsize: Optional[Tuple[int, int]] = None,\tfilename: Optional[str] = None,\t**kwargs):", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.adjacent", "modulename": "pauliopt.topologies", "qualname": "Topology.adjacent", "kind": "function", "doc": "

Readonly property exposing the (frozen) set of qubits adjacent\nto (i.e. couple with) the given qubit.

\n", "signature": "(self, qubit: int) -> FrozenSet[int]:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.incident", "modulename": "pauliopt.topologies", "qualname": "Topology.incident", "kind": "function", "doc": "

Readonly property returning an iterator running over all couplings\nincident onto the given qubit.

\n\n

This is returned as an iterator, rather than a collection,\nbecause the couplings are generated on the fly (i.e. this is not\nmerely exposing some internal collection).

\n", "signature": "(self, qubit: int) -> Iterator[pauliopt.topologies.Coupling]:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.dist", "modulename": "pauliopt.topologies", "qualname": "Topology.dist", "kind": "function", "doc": "

Returns the distance between two given qubits in the topology.

\n", "signature": "(self, fro: int, to: int) -> int:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.mapped_fwd", "modulename": "pauliopt.topologies", "qualname": "Topology.mapped_fwd", "kind": "function", "doc": "

Returns a topology with the same couplings, but remapping the qubits using\nthe given mapping.

\n", "signature": "(\tself,\tmapping: Union[Sequence[int], Dict[int, int]]) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.shortest_path", "modulename": "pauliopt.topologies", "qualname": "Topology.shortest_path", "kind": "function", "doc": "

Computes the shortest path using the next lookup table from the Floyd\u2013Warshall algorithm

\n", "signature": "(self, fro: int, to: int):", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.steiner_tree", "modulename": "pauliopt.topologies", "qualname": "Topology.steiner_tree", "kind": "function", "doc": "

Computes the Steiner tree over the topology with given terminals.\nsubgraph can be used to find the Steiner tree of a subgraph of the topology.\nRequires networkx to be installed to work.\nReturns a networkx Graph.

\n", "signature": "(self, terminals: list[int], subgraph: list[int] = []):", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.non_cutting_qubits", "modulename": "pauliopt.topologies", "qualname": "Topology.non_cutting_qubits", "kind": "function", "doc": "

\n", "signature": "(self, subgraph: List[int] = []) -> List[int]:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.mapped_bwd", "modulename": "pauliopt.topologies", "qualname": "Topology.mapped_bwd", "kind": "function", "doc": "

Returns a topology with the same couplings, but remapping the qubits using\nthe inverse of the given mapping.

\n", "signature": "(\tself,\tmapping: Union[Sequence[int], Dict[int, int]]) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.from_dict", "modulename": "pauliopt.topologies", "qualname": "Topology.from_dict", "kind": "function", "doc": "

Creates a Topology instance from a dictionary in the\nformat obtained from Topology.as_dict,\nfor de-serialization purposes.

\n", "signature": "(\ttopology: Union[pauliopt.topologies.TopologyDict, str]) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.line", "modulename": "pauliopt.topologies", "qualname": "Topology.line", "kind": "function", "doc": "

Creates a line topology on the given number of qubits.

\n", "signature": "(num_qubits: int) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.cycle", "modulename": "pauliopt.topologies", "qualname": "Topology.cycle", "kind": "function", "doc": "

Creates a cycle topology on the given number of qubits.

\n", "signature": "(num_qubits: int) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.complete", "modulename": "pauliopt.topologies", "qualname": "Topology.complete", "kind": "function", "doc": "

Creates a complete topology on the given number of qubits.

\n", "signature": "(num_qubits: int) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.grid", "modulename": "pauliopt.topologies", "qualname": "Topology.grid", "kind": "function", "doc": "

Creates a grid topology with the given number of rows and cols.\nQubits are indexed by rows.

\n", "signature": "(num_rows: int, num_cols: int) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.periodic_grid", "modulename": "pauliopt.topologies", "qualname": "Topology.periodic_grid", "kind": "function", "doc": "

Creates a periodic grid topology with the given number of rows and cols.\nQubits are indexed by rows.

\n", "signature": "(num_rows: int, num_cols: int) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.from_qiskit_config", "modulename": "pauliopt.topologies", "qualname": "Topology.from_qiskit_config", "kind": "function", "doc": "

Static method to construct the topology from a\nQiskit backend configuration.

\n\n

This method relies on the qiskit library being available.\nSpecifically, the config argument must be of type\nqiskit.providers.models.QasmBackendConfiguration.

\n", "signature": "(config) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.from_qiskit_backend", "modulename": "pauliopt.topologies", "qualname": "Topology.from_qiskit_backend", "kind": "function", "doc": "

Static method to construct the topology from a Qiskit backend.

\n\n

This method relies on the qiskit library being available.\nSpecifically, the backend argument must be of type\nqiskit.providers.Backend.

\n", "signature": "(backend) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Matching", "modulename": "pauliopt.topologies", "qualname": "Matching", "kind": "class", "doc": "

Mutable container class for a matching on a qubit topology.

\n"}, {"fullname": "pauliopt.topologies.Matching.__init__", "modulename": "pauliopt.topologies", "qualname": "Matching.__init__", "kind": "function", "doc": "

\n", "signature": "(topology: pauliopt.topologies.Topology)"}, {"fullname": "pauliopt.topologies.Matching.topology", "modulename": "pauliopt.topologies", "qualname": "Matching.topology", "kind": "variable", "doc": "

Readonly property exposing the qubit topology\nunderlying this matching.

\n", "annotation": ": pauliopt.topologies.Topology"}, {"fullname": "pauliopt.topologies.Matching.matched_couplings", "modulename": "pauliopt.topologies", "qualname": "Matching.matched_couplings", "kind": "variable", "doc": "

Readonly property returning the collection of couplings\ncurrently in this matching.

\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[pauliopt.topologies.Coupling]"}, {"fullname": "pauliopt.topologies.Matching.matched_qubits", "modulename": "pauliopt.topologies", "qualname": "Matching.matched_qubits", "kind": "variable", "doc": "

Readonly property returning the collection of qubits\ncurrently matched in this matching.

\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[int]"}, {"fullname": "pauliopt.topologies.Matching.flippable_couplings", "modulename": "pauliopt.topologies", "qualname": "Matching.flippable_couplings", "kind": "variable", "doc": "

Readonly property returning the collection of couplings\nthat can be currently flipped in this matching, namely:

\n\n
    \n
  • all couplings currently in the matching (will be removed by flip);
  • \n
  • all couplings with both qubits currently not matched by the matching\n(will be added by flip).
  • \n
\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[pauliopt.topologies.Coupling]"}, {"fullname": "pauliopt.topologies.Matching.incident", "modulename": "pauliopt.topologies", "qualname": "Matching.incident", "kind": "function", "doc": "

Returns the coupling incident to the given qubit in this matching,\nor None if the qubit is not matched.

\n", "signature": "(self, qubit: int) -> Optional[pauliopt.topologies.Coupling]:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Matching.is_flippable", "modulename": "pauliopt.topologies", "qualname": "Matching.is_flippable", "kind": "function", "doc": "

Checks whether the coupling can be flipped:

\n\n
    \n
  • always true if the coupling is already present in the matching;
  • \n
  • otherwise true only if neither qubit in the coupling is currently matched.
  • \n
\n", "signature": "(self, coupling: Collection[int]) -> bool:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Matching.flip", "modulename": "pauliopt.topologies", "qualname": "Matching.flip", "kind": "function", "doc": "

Flips the given coupling in the matching (removes it if it is already present,\nadds it if it is not yed present and can be added).\nRaises ValueError if the coupling is not flippable.

\n\n

The matching is modified in-place and then returned, as per the\nfluent API pattern.

\n", "signature": "(self, coupling: Collection[int]) -> pauliopt.topologies.Matching:", "funcdef": "def"}, {"fullname": "pauliopt.utils", "modulename": "pauliopt.utils", "kind": "module", "doc": "

Utility classes and functions for the pauliopt library.

\n"}, {"fullname": "pauliopt.utils.calculate_orthogonal_point", "modulename": "pauliopt.utils", "qualname": "calculate_orthogonal_point", "kind": "function", "doc": "

\n", "signature": "(a, b, d, left):", "funcdef": "def"}, {"fullname": "pauliopt.utils.AngleInitT", "modulename": "pauliopt.utils", "qualname": "AngleInitT", "kind": "variable", "doc": "

\n", "default_value": "typing.Union[int, fractions.Fraction, str, decimal.Decimal]"}, {"fullname": "pauliopt.utils.AngleExpr", "modulename": "pauliopt.utils", "qualname": "AngleExpr", "kind": "class", "doc": "

A container class for angle expressions.

\n", "bases": "abc.ABC"}, {"fullname": "pauliopt.utils.AngleExpr.repr_latex", "modulename": "pauliopt.utils", "qualname": "AngleExpr.repr_latex", "kind": "variable", "doc": "

LaTeX math mode representation of this number.

\n", "annotation": ": str"}, {"fullname": "pauliopt.utils.AngleExpr.to_qiskit", "modulename": "pauliopt.utils", "qualname": "AngleExpr.to_qiskit", "kind": "variable", "doc": "

\n", "annotation": ": Any"}, {"fullname": "pauliopt.utils.AngleExpr.is_zero", "modulename": "pauliopt.utils", "qualname": "AngleExpr.is_zero", "kind": "variable", "doc": "

\n", "annotation": ": bool"}, {"fullname": "pauliopt.utils.AngleExpr.is_pi", "modulename": "pauliopt.utils", "qualname": "AngleExpr.is_pi", "kind": "variable", "doc": "

\n", "annotation": ": bool"}, {"fullname": "pauliopt.utils.AngleExpr.is_zero_or_pi", "modulename": "pauliopt.utils", "qualname": "AngleExpr.is_zero_or_pi", "kind": "variable", "doc": "

\n", "annotation": ": bool"}, {"fullname": "pauliopt.utils.Angle", "modulename": "pauliopt.utils", "qualname": "Angle", "kind": "class", "doc": "

A container class for angles,\nas rational multiples of PI modulo 2PI.

\n", "bases": "AngleExpr"}, {"fullname": "pauliopt.utils.Angle.__init__", "modulename": "pauliopt.utils", "qualname": "Angle.__init__", "kind": "function", "doc": "

\n", "signature": "(\ttheta: Union[pauliopt.utils.Angle, int, fractions.Fraction, str, decimal.Decimal])"}, {"fullname": "pauliopt.utils.Angle.value", "modulename": "pauliopt.utils", "qualname": "Angle.value", "kind": "variable", "doc": "

The value of this angle as a fraction of PI.

\n", "annotation": ": fractions.Fraction"}, {"fullname": "pauliopt.utils.Angle.as_root_of_unity", "modulename": "pauliopt.utils", "qualname": "Angle.as_root_of_unity", "kind": "variable", "doc": "

Returns (a,n) where n is the smallest such\nthat this angle is an $n$-th root of unity\nand 0 <= a < n such that this is $e^{i 2\\pi \\frac{a}{n}}$

\n", "annotation": ": Tuple[int, int]"}, {"fullname": "pauliopt.utils.Angle.order", "modulename": "pauliopt.utils", "qualname": "Angle.order", "kind": "variable", "doc": "

The order of this angle as a root of unity.

\n", "annotation": ": int"}, {"fullname": "pauliopt.utils.Angle.is_zero_or_pi", "modulename": "pauliopt.utils", "qualname": "Angle.is_zero_or_pi", "kind": "variable", "doc": "

Whether this angle is a multiple of pi.

\n", "annotation": ": bool"}, {"fullname": "pauliopt.utils.Angle.is_zero", "modulename": "pauliopt.utils", "qualname": "Angle.is_zero", "kind": "variable", "doc": "

Whether this angle is a multiple of 2pi.

\n", "annotation": ": bool"}, {"fullname": "pauliopt.utils.Angle.is_pi", "modulename": "pauliopt.utils", "qualname": "Angle.is_pi", "kind": "variable", "doc": "

Whether this angle is an odd multiple of pi.

\n", "annotation": ": bool"}, {"fullname": "pauliopt.utils.Angle.to_qiskit", "modulename": "pauliopt.utils", "qualname": "Angle.to_qiskit", "kind": "variable", "doc": "

\n", "annotation": ": float"}, {"fullname": "pauliopt.utils.Angle.repr_latex", "modulename": "pauliopt.utils", "qualname": "Angle.repr_latex", "kind": "variable", "doc": "

LaTeX math mode representation of this number.

\n", "annotation": ": str"}, {"fullname": "pauliopt.utils.Angle.random", "modulename": "pauliopt.utils", "qualname": "Angle.random", "kind": "function", "doc": "

Generates a random angle with the given subdivision:\nr * pi/subdivision for random r in range(2*subdivision).

\n", "signature": "(\tsubdivision: int = 4,\t*,\tsize: int = 1,\trng_seed: Optional[int] = None,\tnonzero: bool = False) -> Union[pauliopt.utils.Angle, Tuple[pauliopt.utils.Angle, ...]]:", "funcdef": "def"}, {"fullname": "pauliopt.utils.Angle.zero", "modulename": "pauliopt.utils", "qualname": "Angle.zero", "kind": "variable", "doc": "

A constant for the angle 0.

\n", "annotation": ": Final[pauliopt.utils.Angle]", "default_value": "0"}, {"fullname": "pauliopt.utils.Angle.pi", "modulename": "pauliopt.utils", "qualname": "Angle.pi", "kind": "variable", "doc": "

A constant for the angle pi.

\n", "annotation": ": Final[pauliopt.utils.Angle]", "default_value": "pi"}, {"fullname": "pauliopt.utils.pi", "modulename": "pauliopt.utils", "qualname": "pi", "kind": "variable", "doc": "

Constant for Angle.pi.

\n", "annotation": ": Final[pauliopt.utils.Angle]", "default_value": "pi"}, {"fullname": "pauliopt.utils.\u03c0", "modulename": "pauliopt.utils", "qualname": "\u03c0", "kind": "variable", "doc": "

Constant for Angle.pi.

\n", "annotation": ": Final[pauliopt.utils.Angle]", "default_value": "pi"}, {"fullname": "pauliopt.utils.SumprodAngleExpr", "modulename": "pauliopt.utils", "qualname": "SumprodAngleExpr", "kind": "function", "doc": "

\n", "signature": "(\t*exprs: pauliopt.utils.AngleExpr,\tcoeffs: Union[int, fractions.Fraction, Sequence[Union[int, fractions.Fraction]]] = 1) -> pauliopt.utils.AngleExpr:", "funcdef": "def"}, {"fullname": "pauliopt.utils.ModAngleExpr", "modulename": "pauliopt.utils", "qualname": "ModAngleExpr", "kind": "function", "doc": "

\n", "signature": "(\texpr: pauliopt.utils.AngleExpr,\tmod: pauliopt.utils.AngleExpr) -> pauliopt.utils.AngleExpr:", "funcdef": "def"}, {"fullname": "pauliopt.utils.AngleVar", "modulename": "pauliopt.utils", "qualname": "AngleVar", "kind": "class", "doc": "

A container class for angle expressions.

\n", "bases": "AngleExpr"}, {"fullname": "pauliopt.utils.AngleVar.__init__", "modulename": "pauliopt.utils", "qualname": "AngleVar.__init__", "kind": "function", "doc": "

\n", "signature": "(label: str, latex_label: Optional[str] = None)"}, {"fullname": "pauliopt.utils.AngleVar.to_qiskit", "modulename": "pauliopt.utils", "qualname": "AngleVar.to_qiskit", "kind": "variable", "doc": "

\n", "annotation": ": Any"}, {"fullname": "pauliopt.utils.AngleVar.repr_latex", "modulename": "pauliopt.utils", "qualname": "AngleVar.repr_latex", "kind": "variable", "doc": "

LaTeX math mode representation of this number.

\n", "annotation": ": str"}, {"fullname": "pauliopt.utils.SVGBuilder", "modulename": "pauliopt.utils", "qualname": "SVGBuilder", "kind": "class", "doc": "

Utility class for building certain SVG images.\nFollows the Fluent interface pattern.

\n"}, {"fullname": "pauliopt.utils.SVGBuilder.__init__", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.__init__", "kind": "function", "doc": "

\n", "signature": "(width: int, height: int)"}, {"fullname": "pauliopt.utils.SVGBuilder.width", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.width", "kind": "variable", "doc": "

The figure width.

\n", "annotation": ": int"}, {"fullname": "pauliopt.utils.SVGBuilder.height", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.height", "kind": "variable", "doc": "

The figure height.

\n", "annotation": ": int"}, {"fullname": "pauliopt.utils.SVGBuilder.tags", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.tags", "kind": "variable", "doc": "

The current sequence of tags.

\n", "annotation": ": Sequence[str]"}, {"fullname": "pauliopt.utils.SVGBuilder.line", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.line", "kind": "function", "doc": "

Draws a line from given coordinates to given coordinates.

\n", "signature": "(\tself,\tfro: Tuple[int, int],\tto: Tuple[int, int]) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.line_bend", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.line_bend", "kind": "function", "doc": "

\n", "signature": "(\tself,\tfro: Tuple[int, int],\tto: Tuple[int, int],\tleft=False,\tdegree=5):", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.add_diagonal_fill", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.add_diagonal_fill", "kind": "function", "doc": "

\n", "signature": "(self, color_1: str, color_2: str, id: str) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.square", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.square", "kind": "function", "doc": "

\n", "signature": "(\tself,\tcentre: Tuple[int, int],\twidth: int,\theight: int,\tfill) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.text_with_square", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.text_with_square", "kind": "function", "doc": "

\n", "signature": "(\tself,\tcentre: Tuple[int, int],\twidth: int,\theight: int,\ttext: str) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.circle", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.circle", "kind": "function", "doc": "

Draws a circle with given centre and radius.

\n", "signature": "(\tself,\tcentre: Tuple[int, int],\tr: int,\tfill: str) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.rect", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.rect", "kind": "function", "doc": "

Draws a rectangle with given centre, width and height.

\n", "signature": "(\tself,\tcentre: Tuple[int, int],\twidth: int,\theight: int,\tfill: str) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.text", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.text", "kind": "function", "doc": "

Draws text at the given position (stroke/fill not used).

\n", "signature": "(\tself,\tpos: Tuple[int, int],\ttext: str,\t*,\tfont_size: int = 10,\tcenter=False) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.TempSchedule", "modulename": "pauliopt.utils", "qualname": "TempSchedule", "kind": "class", "doc": "

Protocol for a temperature schedule.\nThe temperature is a number (int or float) computed from the iteration\nnumber it (starting from 0) and the total number of iterations num_iter\n(passed as a keyword argument).

\n", "bases": "typing.Protocol"}, {"fullname": "pauliopt.utils.TempSchedule.__init__", "modulename": "pauliopt.utils", "qualname": "TempSchedule.__init__", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs)"}, {"fullname": "pauliopt.utils.TempScheduleProvider", "modulename": "pauliopt.utils", "qualname": "TempScheduleProvider", "kind": "class", "doc": "

Protocol for a function constructing a temperature schedule\nfrom an initial and final temperatures.

\n", "bases": "typing.Protocol"}, {"fullname": "pauliopt.utils.TempScheduleProvider.__init__", "modulename": "pauliopt.utils", "qualname": "TempScheduleProvider.__init__", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs)"}, {"fullname": "pauliopt.utils.linear_temp_schedule", "modulename": "pauliopt.utils", "qualname": "linear_temp_schedule", "kind": "function", "doc": "

Returns a straight/linear temperature schedule for given initial and final temperatures,\nfrom https://link.springer.com/article/10.1007/BF00143921

\n", "signature": "(\tt_init: Union[int, float],\tt_final: Union[int, float]) -> pauliopt.utils.TempSchedule:", "funcdef": "def"}, {"fullname": "pauliopt.utils.geometric_temp_schedule", "modulename": "pauliopt.utils", "qualname": "geometric_temp_schedule", "kind": "function", "doc": "

Returns a geometric temperature schedule for given initial and final temperatures,\nfrom https://link.springer.com/article/10.1007/BF00143921

\n", "signature": "(\tt_init: Union[int, float],\tt_final: Union[int, float]) -> pauliopt.utils.TempSchedule:", "funcdef": "def"}, {"fullname": "pauliopt.utils.reciprocal_temp_schedule", "modulename": "pauliopt.utils", "qualname": "reciprocal_temp_schedule", "kind": "function", "doc": "

Returns a reciprocal temperature schedule for given initial and final temperatures,\nfrom https://link.springer.com/article/10.1007/BF00143921

\n", "signature": "(\tt_init: Union[int, float],\tt_final: Union[int, float]) -> pauliopt.utils.TempSchedule:", "funcdef": "def"}, {"fullname": "pauliopt.utils.log_temp_schedule", "modulename": "pauliopt.utils", "qualname": "log_temp_schedule", "kind": "function", "doc": "

Returns a logarithmic temperature schedule for given initial and final temperatures,\nfrom https://link.springer.com/article/10.1007/BF00143921

\n", "signature": "(\tt_init: Union[int, float],\tt_final: Union[int, float]) -> pauliopt.utils.TempSchedule:", "funcdef": "def"}, {"fullname": "pauliopt.utils.StandardTempScheduleName", "modulename": "pauliopt.utils", "qualname": "StandardTempScheduleName", "kind": "variable", "doc": "

Names of the standard temperature schedules.

\n", "default_value": "typing.Literal['linear', 'geometric', 'reciprocal', 'log']"}, {"fullname": "pauliopt.utils.StandardTempSchedule", "modulename": "pauliopt.utils", "qualname": "StandardTempSchedule", "kind": "variable", "doc": "

Type for standard temperature schedules.

\n", "default_value": "typing.Tuple[typing.Literal['linear', 'geometric', 'reciprocal', 'log'], typing.Union[int, float], typing.Union[int, float]]"}, {"fullname": "pauliopt.utils.StandardTempSchedules", "modulename": "pauliopt.utils", "qualname": "StandardTempSchedules", "kind": "variable", "doc": "

Dictionary of standard temperature schedule providers.

\n", "annotation": ": Final[Mapping[Literal['linear', 'geometric', 'reciprocal', 'log'], pauliopt.utils.TempScheduleProvider]]", "default_value": "{'linear': <function linear_temp_schedule>, 'geometric': <function geometric_temp_schedule>, 'reciprocal': <function reciprocal_temp_schedule>, 'log': <function log_temp_schedule>}"}]; + /** pdoc search index */const docs = [{"fullname": "pauliopt", "modulename": "pauliopt", "kind": "module", "doc": "

A Python library to simplify quantum circuits of Pauli gadgets.\nIt consists of two sub-modules, phase and pauli, detailed below.

\n"}, {"fullname": "pauliopt.circuits", "modulename": "pauliopt.circuits", "kind": "module", "doc": "

A general class for quantum circuits, with a ZX / Gadget representation.

\n"}, {"fullname": "pauliopt.circuits.QISKIT_CONVERSION", "modulename": "pauliopt.circuits", "qualname": "QISKIT_CONVERSION", "kind": "variable", "doc": "

\n", "default_value": "{'h': <function <lambda>>, 'x': <function <lambda>>, 'y': <function <lambda>>, 'z': <function <lambda>>, 's': <function <lambda>>, 'sdg': <function <lambda>>, 't': <function <lambda>>, 'tdg': <function <lambda>>, 'swap': <function <lambda>>, 'cx': <function <lambda>>, 'cy': <function <lambda>>, 'cz': <function <lambda>>, 'ccx': <function <lambda>>, 'ccz': <function <lambda>>, 'rx': <function <lambda>>, 'ry': <function <lambda>>, 'rz': <function <lambda>>, 'crx': <function <lambda>>, 'cry': <function <lambda>>, 'crz': <function <lambda>>}"}, {"fullname": "pauliopt.circuits.Circuit", "modulename": "pauliopt.circuits", "qualname": "Circuit", "kind": "class", "doc": "

Class for representing quantum circuits.

\n"}, {"fullname": "pauliopt.circuits.Circuit.__init__", "modulename": "pauliopt.circuits", "qualname": "Circuit.__init__", "kind": "function", "doc": "

\n", "signature": "(n_qubits, _gates=None)"}, {"fullname": "pauliopt.circuits.Circuit.n_qubits", "modulename": "pauliopt.circuits", "qualname": "Circuit.n_qubits", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.circuits.Circuit.add_gate", "modulename": "pauliopt.circuits", "qualname": "Circuit.add_gate", "kind": "function", "doc": "

\n", "signature": "(self, gate):", "funcdef": "def"}, {"fullname": "pauliopt.circuits.Circuit.add_gates", "modulename": "pauliopt.circuits", "qualname": "Circuit.add_gates", "kind": "function", "doc": "

\n", "signature": "(self, gates):", "funcdef": "def"}, {"fullname": "pauliopt.circuits.Circuit.to_phase_circuit", "modulename": "pauliopt.circuits", "qualname": "Circuit.to_phase_circuit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.circuits.Circuit.from_qiskit", "modulename": "pauliopt.circuits", "qualname": "Circuit.from_qiskit", "kind": "function", "doc": "

\n", "signature": "(qc: qiskit.circuit.quantumcircuit.QuantumCircuit):", "funcdef": "def"}, {"fullname": "pauliopt.circuits.Circuit.to_qiskit", "modulename": "pauliopt.circuits", "qualname": "Circuit.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.clifford", "modulename": "pauliopt.clifford", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.clifford.clifford", "modulename": "pauliopt.clifford.clifford", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.clifford.clifford.mult_paulis", "modulename": "pauliopt.clifford.clifford", "qualname": "mult_paulis", "kind": "function", "doc": "

Small helper function to multiply two Pauli strings and correctly update the sign.

\n\n

Args:\n p1 (np.ndarray): Pauli string 1\n p2 (np.ndarray): Pauli string 2\n sign1 (int): Sign of Pauli string 1\n sign2 (int): Sign of Pauli string 2\n n_qubits (int): Number of qubits in the Pauli strings

\n\n

Returns:\n np.ndarray: Pauli string 1 * Pauli string 2

\n", "signature": "(p1, p2, sign1, sign2, n_qubits):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau", "kind": "class", "doc": "

Class for storing and manipulating Clifford clifford.\nA Clifford clifford is a representation of a Clifford circuit as a\n2n x 2n binary matrix, where n is the number of qubits. The first n rows\nrepresent the stabilizers, and the last n rows represent the destabilizers.\nThe first n columns represent the X operators, and the last n columns\nrepresent the Z operators.\nThe sign of the operator in row i is given by the i-th entry of\nthe sign vector.

\n\n

The clifford is initialized as the identity matrix with a zero sign vector.

\n\n

Args:\n n_qubits (int): Number of qubits in the clifford.

\n\n

A more readable representation of the clifford is given by the string:

\n\n
\n
>>> from pauliopt.clifford.clifford import CliffordTableau\n>>> ct = CliffordTableau(2)\n>>> print(ct)\n# Expected Output:\n# X/Z I/I | +\n# I/I X/Z | +\n>>> ct.append_h(0)\n>>> print(ct)\n# Expected Output:\n# Z/X I/I | +\n# I/I X/Z | +\n
\n
\n\n

To get the raw $2n imes 2n$ matrix representation of the clifford, use:

\n\n
\n
>>> ct.clifford\n# Expected Output:\n# array([[0, 0, 1, 0],\n#        [0, 1, 0, 0],\n#        [1, 0, 0, 0],\n#        [0, 0, 0, 1]], dtype=uint8)\n
\n
\n\n

To get the sign vector, use:

\n\n
\n
>>> ct.signs\n# Expected Output:\n# array([0, 0, 0, 0], dtype=uint8)\n
\n
\n"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.__init__", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.__init__", "kind": "function", "doc": "

\n", "signature": "(n_qubits)"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.clifford", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.clifford", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.signs", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.signs", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.n_qubits", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.n_qubits", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.from_tableau", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.from_tableau", "kind": "function", "doc": "

Create a CliffordTableau from a clifford and sign vector.

\n\n

Args:\n clifford (np.ndarray): $2n imes 2n$ binary matrix representing the clifford.\n signs (np.ndarray): $2n$-dimensional binary vector representing the sign vector.

\n\n

Returns:\n CliffordTableau: CliffordTableau object.

\n", "signature": "(clifford, signs):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.from_qiskit_tableau", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.from_qiskit_tableau", "kind": "function", "doc": "

Create a CliffordTableau from a qiskit Clifford object.

\n\n

Args:\n qiskit_ct (qiskit.quantum_info.Clifford): Clifford object.

\n\n

Returns:\n CliffordTableau: CliffordTableau object.

\n", "signature": "(\tqiskit_ct: qiskit.quantum_info.operators.symplectic.clifford.Clifford):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.string_repr", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.string_repr", "kind": "function", "doc": "

Get a string representation of the clifford.

\n\n

Args:\n sep (str): Separator between the pauli operators\n sign_sep (str): Separator between operators and sign.

\n", "signature": "(self, sep=' ', sign_sep='| '):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.x_out", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.x_out", "kind": "function", "doc": "

Get the X operator in row row and column col.

\n\n

Args:\n row (int): Row index.\n col (int): Column index.

\n", "signature": "(self, row, col):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.z_out", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.z_out", "kind": "function", "doc": "

Get the Z operator in row row and column col.

\n\n

Args:\n row (int): Row index.\n col (int): Column index.

\n", "signature": "(self, row, col):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.prepend_h", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.prepend_h", "kind": "function", "doc": "

Prepend a Hadamard gate to the clifford.

\n\n

Args:\n qubit (int): Qubit the hadamard gate is applied to.

\n", "signature": "(self, qubit):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.append_h", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.append_h", "kind": "function", "doc": "

Append a Hadamard gate to the clifford.

\n\n

Args:\n qubit (int): Qubit the hadamard gate is applied to.

\n", "signature": "(self, qubit):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.prepend_s", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.prepend_s", "kind": "function", "doc": "

Prepend a S gate to the clifford.

\n\n

Args:\n qubit (int): Qubit the S gate is applied to.

\n", "signature": "(self, qubit):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.append_s", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.append_s", "kind": "function", "doc": "

Append a S gate to the clifford.

\n\n

Args:\n qubit (int): Qubit the S gate is applied to.

\n", "signature": "(self, qubit):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.prepend_cnot", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.prepend_cnot", "kind": "function", "doc": "

Prepend a CNOT gate to the clifford.

\n\n

Args:\n control (int): Control qubit.\n target (int): Target qubit.

\n", "signature": "(self, control, target):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.append_cnot", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.append_cnot", "kind": "function", "doc": "

Append a CNOT gate to the clifford.

\n\n

Args:\n control (int): Control qubit.\n target (int): Target qubit.

\n", "signature": "(self, control, target):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.insert_pauli_row", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.insert_pauli_row", "kind": "function", "doc": "

Insert a Pauli row into the clifford.

\n\n

Args:\n pauli (np.array): Pauli to be inserted.\n p_sign (int): Sign of the Pauli.\n row (int): Row to insert the Pauli.

\n", "signature": "(self, pauli, p_sign, row):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.inverse", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.inverse", "kind": "function", "doc": "

Invert the clifford.

\n\n

Note: this is will create a deep copy of the clifford.

\n\n

Returns:\n CliffordTableau: Inverted clifford.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.clifford.CliffordTableau.apply", "modulename": "pauliopt.clifford.clifford", "qualname": "CliffordTableau.apply", "kind": "function", "doc": "

Apply a CliffordTableau to the current clifford.

\n\n

Note: this is will create a deep copy of the clifford.

\n\n

Args:\n other (CliffordTableau): CliffordTableau to apply.

\n\n

Returns:\n CliffordTableau: Applied CliffordTableau.

\n", "signature": "(self, other: pauliopt.clifford.clifford.CliffordTableau):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis", "modulename": "pauliopt.clifford.tableau_synthesis", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.clifford.tableau_synthesis.heurisitc_fkt", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "heurisitc_fkt", "kind": "function", "doc": "

The heuristic function for picking the pivot in the clifford synthesis algorithm.

\n\n
Parameters
\n\n
    \n
  • row: The row to consider
  • \n
  • G: The graph of the topology
  • \n
  • remaining: The remaining clifford
  • \n
\n", "signature": "(row, G, remaining: pauliopt.clifford.clifford.CliffordTableau):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.pick_pivot", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "pick_pivot", "kind": "function", "doc": "

Pick the pivot to eliminate the next column in the clifford synthesis algorithm.

\n\n

We currently use the heuristic function h to pick the pivot,\ni.e choose the row with the smallest heurisitc_fkt value.

\n\n
Parameters
\n\n
    \n
  • G: The graph of the topology
  • \n
  • remaining: The remaining clifford
  • \n
  • possible_swaps: The columns that can be swapped
  • \n
  • include_swaps: Whether to include the columns that can be swapped
  • \n
\n", "signature": "(\tG,\tremaining: pauliopt.clifford.clifford.CliffordTableau,\tpossible_swaps,\tinclude_swaps):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.update_dfs", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "update_dfs", "kind": "function", "doc": "

Helper function to update the dfs list in place. (See compute_steiner_tree)

\n\n
Parameters
\n\n
    \n
  • dfs: The dfs list to update
  • \n
  • parent: The parent node
  • \n
  • child: The child node
  • \n
\n", "signature": "(dfs, parent, child):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.relabel_graph_inplace", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "relabel_graph_inplace", "kind": "function", "doc": "

Helper function to relabel the graph in place. (See compute_steiner_tree)

\n\n
Parameters
\n\n
    \n
  • G: The graph to relabel
  • \n
  • parent: The parent node
  • \n
  • child: The child node
  • \n
\n", "signature": "(G, parent, child):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.compute_steiner_tree", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "compute_steiner_tree", "kind": "function", "doc": "

Compute the steiner tree of the sub_graph with the given nodes.\nThis function is a wrapper around the networkx steiner tree function.

\n\n

It will additionally swap the columns of the remaining clifford to further reduce\nthe amount of CNOTs if include_swaps is True.\nInclude_swaps requires lookup, swappable_nodes, permutation and n_qubits to be set.

\n\n
Parameters
\n\n
    \n
  • root: The root node of the steiner tree
  • \n
  • nodes: The nodes to include in the steiner tree
  • \n
  • sub_graph: The graph of the topology

  • \n
  • include_swaps: Whether to include swaps in the steiner tree

  • \n
  • lookup: The lookup table of the topology
  • \n
  • swappable_nodes: The nodes that can be swapped
  • \n
  • permutation: The permutation of the topology
  • \n
  • n_qubits: The number of qubits
  • \n
\n", "signature": "(\troot: int,\tnodes: [<class 'int'>],\tsub_graph: networkx.classes.graph.Graph,\tinclude_swaps=False,\tlookup=None,\tswappable_nodes=None,\tpermutation=None,\tn_qubits=None):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.is_cutting", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "is_cutting", "kind": "function", "doc": "

Check if the given vertex is a cutting vertex in the given graph.

\n\n
Parameters
\n\n
    \n
  • vertex: The vertex to check
  • \n
  • g: The graph to check
  • \n
\n", "signature": "(vertex, g):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.sanitize_z", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "sanitize_z", "kind": "function", "doc": "

Sanitization process for the stabilizer part.

\n\n

Essentially:

\n\n
    \n
  • If the z_out is Y (=3), then apply S
  • \n
  • If the z_out is X (=1), then apply H
  • \n
\n\n
Parameters
\n\n
    \n
  • row: The row of the clifford
  • \n
  • row_z: The row of the clifford for the stabilizer part
  • \n
  • remaining: The remaining clifford
  • \n
  • apply: The function to apply a gate
  • \n
\n", "signature": "(row, row_z, remaining, apply):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.sanitize_field_x", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "sanitize_field_x", "kind": "function", "doc": "

Sanitization process for the destabilizer part.

\n\n

Essentially:

\n\n
    \n
  • If the x_out is Y (=3), then apply S
  • \n
  • If the x_out is X (=2), then apply H
  • \n
\n\n
Parameters
\n\n
    \n
  • row: The row of the clifford
  • \n
  • row_x: The row of the clifford for the destabilizer part
  • \n
  • remaining: The remaining clifford
  • \n
  • apply: The function to apply a gate
  • \n
\n", "signature": "(row, row_x, remaining, apply):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.remove_interactions", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "remove_interactions", "kind": "function", "doc": "

Remove the interactions of the destabilizer/stabilizer part.\nThis function assumed that all elements are Z or I.

\n\n

Include swaps requires swappable_nodes, permutation and include_swaps to be set.

\n\n
Parameters
\n\n
    \n
  • pivot: The pivot of the clifford
  • \n
  • row: The specific row of the clifford
  • \n
  • sub_graph: The graph of the topology
  • \n
  • remaining: The remaining clifford
  • \n
  • apply: The function to apply a gate
  • \n
  • basis: The basis of the clifford (x for destabilizer or z for stabilizer)
  • \n
  • swappable_nodes: The nodes that can be swapped
  • \n
  • permutation: The permutation of the topology
  • \n
  • include_swaps: Whether to include swaps in the steiner tree
  • \n
\n", "signature": "(\tpivot,\trow,\tsub_graph,\tremaining,\tapply,\tbasis,\tinclude_swaps=False,\tswappable_nodes=None,\tpermutation=None):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.steiner_reduce_column", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "steiner_reduce_column", "kind": "function", "doc": "

Steiner reduce a column of the clifford.

\n\n
Parameters
\n\n
    \n
  • pivot: The pivot of the clifford
  • \n
  • sub_graph: The graph of the topology
  • \n
  • remaining: The remaining clifford
  • \n
  • apply: The function to apply a gate
  • \n
  • swappable_nodes: The nodes that can be swapped
  • \n
  • permutation: The permutation of the topology
  • \n
  • include_swaps: Whether to include swaps in the steiner tree
  • \n
\n", "signature": "(\tpivot,\tsub_graph,\tremaining,\tapply,\tswappable_nodes=None,\tpermutation=None,\tinclude_swaps=False):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.get_non_cutting_vertex", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "get_non_cutting_vertex", "kind": "function", "doc": "

\n", "signature": "(G, pivot_col, swappable_nodes):", "funcdef": "def"}, {"fullname": "pauliopt.clifford.tableau_synthesis.synthesize_tableau", "modulename": "pauliopt.clifford.tableau_synthesis", "qualname": "synthesize_tableau", "kind": "function", "doc": "

Architecture aware synthesis of a Clifford clifford.\nThis is the implementation of the algorithm described in Winderl et. al. [1]

\n\n
Parameters
\n\n
    \n
  • clifford: The Clifford clifford
  • \n
  • topo: The topology
  • \n
  • include_swaps: Whether to allow initial and final measurement permutations
  • \n
\n\n
Returns
\n\n
\n

The synthesized circuit and a inital/final permutation

\n
\n\n

References

\n\n

[1] Winderl, Huang, et al. \"Architecture-Aware Synthesis of Stabilizer Circuits from Clifford Tableaus.\" arXiv preprint arXiv:2309.08972 (2023).

\n", "signature": "(\tclifford: pauliopt.clifford.clifford.CliffordTableau,\ttopo: pauliopt.topologies.Topology,\tinclude_swaps=True):", "funcdef": "def"}, {"fullname": "pauliopt.gates", "modulename": "pauliopt.gates", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.gates.Gate", "modulename": "pauliopt.gates", "qualname": "Gate", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "abc.ABC"}, {"fullname": "pauliopt.gates.Gate.qubits", "modulename": "pauliopt.gates", "qualname": "Gate.qubits", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Gate.name", "modulename": "pauliopt.gates", "qualname": "Gate.name", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Gate.width", "modulename": "pauliopt.gates", "qualname": "Gate.width", "kind": "variable", "doc": "

Width of gate used for drawing.

\n"}, {"fullname": "pauliopt.gates.Gate.draw_zx", "modulename": "pauliopt.gates", "qualname": "Gate.draw_zx", "kind": "function", "doc": "

\n", "signature": "(self, builder, base, row_width, params):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Gate.draw_box", "modulename": "pauliopt.gates", "qualname": "Gate.draw_box", "kind": "function", "doc": "

\n", "signature": "(self, builder, base, row_width, params):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Gate.draw", "modulename": "pauliopt.gates", "qualname": "Gate.draw", "kind": "function", "doc": "

\n", "signature": "(self, builder, base, row_width, params):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Gate.gadgets", "modulename": "pauliopt.gates", "qualname": "Gate.gadgets", "kind": "variable", "doc": "

List of gadgets used to implement this gate.

\n"}, {"fullname": "pauliopt.gates.Gate.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Gate.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.PhaseGate", "modulename": "pauliopt.gates", "qualname": "PhaseGate", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.PhaseGate.phase", "modulename": "pauliopt.gates", "qualname": "PhaseGate.phase", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.H", "modulename": "pauliopt.gates", "qualname": "H", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.H.n_qubits", "modulename": "pauliopt.gates", "qualname": "H.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.H.width", "modulename": "pauliopt.gates", "qualname": "H.width", "kind": "variable", "doc": "

Width of gate used for drawing.

\n", "default_value": "40"}, {"fullname": "pauliopt.gates.H.decomp", "modulename": "pauliopt.gates", "qualname": "H.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.H.draw", "modulename": "pauliopt.gates", "qualname": "H.draw", "kind": "function", "doc": "

\n", "signature": "(self, builder, base, row_width, params):", "funcdef": "def"}, {"fullname": "pauliopt.gates.H.to_qiskit", "modulename": "pauliopt.gates", "qualname": "H.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.X", "modulename": "pauliopt.gates", "qualname": "X", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.X.n_qubits", "modulename": "pauliopt.gates", "qualname": "X.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.X.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "X.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.X.decomp", "modulename": "pauliopt.gates", "qualname": "X.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.X.to_qiskit", "modulename": "pauliopt.gates", "qualname": "X.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Z", "modulename": "pauliopt.gates", "qualname": "Z", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.Z.n_qubits", "modulename": "pauliopt.gates", "qualname": "Z.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Z.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Z.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Z.decomp", "modulename": "pauliopt.gates", "qualname": "Z.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Z.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Z.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Y", "modulename": "pauliopt.gates", "qualname": "Y", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.Y.n_qubits", "modulename": "pauliopt.gates", "qualname": "Y.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Y.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Y.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Y.decomp", "modulename": "pauliopt.gates", "qualname": "Y.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Y.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Y.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.S", "modulename": "pauliopt.gates", "qualname": "S", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.S.n_qubits", "modulename": "pauliopt.gates", "qualname": "S.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.S.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "S.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.S.decomp", "modulename": "pauliopt.gates", "qualname": "S.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.S.to_qiskit", "modulename": "pauliopt.gates", "qualname": "S.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Sdg", "modulename": "pauliopt.gates", "qualname": "Sdg", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.Sdg.n_qubits", "modulename": "pauliopt.gates", "qualname": "Sdg.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Sdg.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Sdg.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Sdg.decomp", "modulename": "pauliopt.gates", "qualname": "Sdg.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Sdg.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Sdg.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.T", "modulename": "pauliopt.gates", "qualname": "T", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.T.n_qubits", "modulename": "pauliopt.gates", "qualname": "T.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.T.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "T.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.T.decomp", "modulename": "pauliopt.gates", "qualname": "T.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.T.to_qiskit", "modulename": "pauliopt.gates", "qualname": "T.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Tdg", "modulename": "pauliopt.gates", "qualname": "Tdg", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.Tdg.n_qubits", "modulename": "pauliopt.gates", "qualname": "Tdg.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Tdg.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Tdg.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Tdg.decomp", "modulename": "pauliopt.gates", "qualname": "Tdg.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Tdg.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Tdg.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.SWAP", "modulename": "pauliopt.gates", "qualname": "SWAP", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.SWAP.n_qubits", "modulename": "pauliopt.gates", "qualname": "SWAP.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.SWAP.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "SWAP.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.SWAP.decomp", "modulename": "pauliopt.gates", "qualname": "SWAP.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.SWAP.to_qiskit", "modulename": "pauliopt.gates", "qualname": "SWAP.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CX", "modulename": "pauliopt.gates", "qualname": "CX", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.CX.n_qubits", "modulename": "pauliopt.gates", "qualname": "CX.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.CX.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "CX.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CX.width", "modulename": "pauliopt.gates", "qualname": "CX.width", "kind": "variable", "doc": "

Width of gate used for drawing.

\n", "default_value": "40"}, {"fullname": "pauliopt.gates.CX.decomp", "modulename": "pauliopt.gates", "qualname": "CX.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CX.draw", "modulename": "pauliopt.gates", "qualname": "CX.draw", "kind": "function", "doc": "

\n", "signature": "(self, builder, base, row_width, params):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CX.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CX.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CY", "modulename": "pauliopt.gates", "qualname": "CY", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.CY.n_qubits", "modulename": "pauliopt.gates", "qualname": "CY.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.CY.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "CY.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CY.decomp", "modulename": "pauliopt.gates", "qualname": "CY.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CY.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CY.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CZ", "modulename": "pauliopt.gates", "qualname": "CZ", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.CZ.n_qubits", "modulename": "pauliopt.gates", "qualname": "CZ.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.CZ.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "CZ.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CZ.decomp", "modulename": "pauliopt.gates", "qualname": "CZ.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CZ.draw", "modulename": "pauliopt.gates", "qualname": "CZ.draw", "kind": "function", "doc": "

\n", "signature": "(self, builder, base, row_width, params):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CZ.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CZ.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CCX", "modulename": "pauliopt.gates", "qualname": "CCX", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.CCX.n_qubits", "modulename": "pauliopt.gates", "qualname": "CCX.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "3"}, {"fullname": "pauliopt.gates.CCX.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "CCX.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CCX.decomp", "modulename": "pauliopt.gates", "qualname": "CCX.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CCX.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CCX.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CCZ", "modulename": "pauliopt.gates", "qualname": "CCZ", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "Gate"}, {"fullname": "pauliopt.gates.CCZ.n_qubits", "modulename": "pauliopt.gates", "qualname": "CCZ.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "3"}, {"fullname": "pauliopt.gates.CCZ.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "CCZ.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CCZ.decomp", "modulename": "pauliopt.gates", "qualname": "CCZ.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CCZ.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CCZ.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Rx", "modulename": "pauliopt.gates", "qualname": "Rx", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "PhaseGate"}, {"fullname": "pauliopt.gates.Rx.n_qubits", "modulename": "pauliopt.gates", "qualname": "Rx.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Rx.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Rx.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Rx.decomp", "modulename": "pauliopt.gates", "qualname": "Rx.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Rx.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Rx.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Ry", "modulename": "pauliopt.gates", "qualname": "Ry", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "PhaseGate"}, {"fullname": "pauliopt.gates.Ry.n_qubits", "modulename": "pauliopt.gates", "qualname": "Ry.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Ry.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Ry.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Ry.decomp", "modulename": "pauliopt.gates", "qualname": "Ry.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Ry.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Ry.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.Rz", "modulename": "pauliopt.gates", "qualname": "Rz", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "PhaseGate"}, {"fullname": "pauliopt.gates.Rz.n_qubits", "modulename": "pauliopt.gates", "qualname": "Rz.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "1"}, {"fullname": "pauliopt.gates.Rz.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "Rz.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.Rz.decomp", "modulename": "pauliopt.gates", "qualname": "Rz.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.Rz.to_qiskit", "modulename": "pauliopt.gates", "qualname": "Rz.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CRx", "modulename": "pauliopt.gates", "qualname": "CRx", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "PhaseGate"}, {"fullname": "pauliopt.gates.CRx.n_qubits", "modulename": "pauliopt.gates", "qualname": "CRx.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.CRx.draw_gadget", "modulename": "pauliopt.gates", "qualname": "CRx.draw_gadget", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CRx.decomp", "modulename": "pauliopt.gates", "qualname": "CRx.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CRx.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CRx.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CRy", "modulename": "pauliopt.gates", "qualname": "CRy", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "PhaseGate"}, {"fullname": "pauliopt.gates.CRy.n_qubits", "modulename": "pauliopt.gates", "qualname": "CRy.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.CRy.draw_gadget", "modulename": "pauliopt.gates", "qualname": "CRy.draw_gadget", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CRy.decomp", "modulename": "pauliopt.gates", "qualname": "CRy.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CRy.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CRy.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CRz", "modulename": "pauliopt.gates", "qualname": "CRz", "kind": "class", "doc": "

Base class for quantum gates.

\n", "bases": "PhaseGate"}, {"fullname": "pauliopt.gates.CRz.n_qubits", "modulename": "pauliopt.gates", "qualname": "CRz.n_qubits", "kind": "variable", "doc": "

\n", "default_value": "2"}, {"fullname": "pauliopt.gates.CRz.draw_as_zx", "modulename": "pauliopt.gates", "qualname": "CRz.draw_as_zx", "kind": "variable", "doc": "

\n", "default_value": "True"}, {"fullname": "pauliopt.gates.CRz.decomp", "modulename": "pauliopt.gates", "qualname": "CRz.decomp", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.gates.CRz.to_qiskit", "modulename": "pauliopt.gates", "qualname": "CRz.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.gates.CNOT", "modulename": "pauliopt.gates", "qualname": "CNOT", "kind": "variable", "doc": "

\n", "default_value": "<class 'pauliopt.gates.CX'>"}, {"fullname": "pauliopt.gates.draw_gadget", "modulename": "pauliopt.gates", "qualname": "draw_gadget", "kind": "function", "doc": "

\n", "signature": "(builder, base, row_width, params, gadget, text_above=True):", "funcdef": "def"}, {"fullname": "pauliopt.pauli", "modulename": "pauliopt.pauli", "kind": "module", "doc": "

This module contains code to create and simplify circuits of Pauli gadgets,\nby conjugation with topologically-aware random circuits of Clifford gates.

\n\n

Currently in development.

\n"}, {"fullname": "pauliopt.pauli.anneal", "modulename": "pauliopt.pauli.anneal", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.pauli.anneal.pick_random_gate", "modulename": "pauliopt.pauli.anneal", "qualname": "pick_random_gate", "kind": "function", "doc": "

\n", "signature": "(num_qubits, gate_set=None):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.anneal.compute_effect", "modulename": "pauliopt.pauli.anneal", "qualname": "compute_effect", "kind": "function", "doc": "

\n", "signature": "(\tpp: pauliopt.pauli.pauli_polynomial.PauliPolynomial,\tgate: pauliopt.pauli.clifford_gates.CliffordGate,\ttopology: pauliopt.topologies.Topology,\tleg_cache=None):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.anneal.anneal", "modulename": "pauliopt.pauli.anneal", "qualname": "anneal", "kind": "function", "doc": "

\n", "signature": "(\tpp: pauliopt.pauli.pauli_polynomial.PauliPolynomial,\ttopology,\tschedule=('geometric', 1.0, 0.1),\tnr_iterations=100):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_gates", "modulename": "pauliopt.pauli.clifford_gates", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType", "kind": "class", "doc": "

An enumeration.

\n", "bases": "enum.Enum"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType.CX", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType.CX", "kind": "variable", "doc": "

\n", "default_value": "<CliffordType.CX: 'cx'>"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType.CY", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType.CY", "kind": "variable", "doc": "

\n", "default_value": "<CliffordType.CY: 'cy'>"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType.CZ", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType.CZ", "kind": "variable", "doc": "

\n", "default_value": "<CliffordType.CZ: 'cz'>"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType.H", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType.H", "kind": "variable", "doc": "

\n", "default_value": "<CliffordType.H: 'h'>"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType.S", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType.S", "kind": "variable", "doc": "

\n", "default_value": "<CliffordType.S: 's'>"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordType.V", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordType.V", "kind": "variable", "doc": "

\n", "default_value": "<CliffordType.V: 'v'>"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordGate", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordGate", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "abc.ABC"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordGate.c_type", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordGate.c_type", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_gates.CliffordGate.propagate_pauli", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CliffordGate.propagate_pauli", "kind": "function", "doc": "

\n", "signature": "(self, gadget: pauliopt.pauli.pauli_gadget.PauliGadget):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_gates.SingleQubitGate", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "SingleQubitGate", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "CliffordGate, abc.ABC"}, {"fullname": "pauliopt.pauli.clifford_gates.SingleQubitGate.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "SingleQubitGate.__init__", "kind": "function", "doc": "

\n", "signature": "(type, qubit)"}, {"fullname": "pauliopt.pauli.clifford_gates.SingleQubitGate.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "SingleQubitGate.rules", "kind": "variable", "doc": "

\n", "default_value": "None"}, {"fullname": "pauliopt.pauli.clifford_gates.SingleQubitGate.qubit", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "SingleQubitGate.qubit", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_gates.SingleQubitGate.propagate_pauli", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "SingleQubitGate.propagate_pauli", "kind": "function", "doc": "

\n", "signature": "(self, gadget: pauliopt.pauli.pauli_gadget.PauliGadget):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_gates.ControlGate", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "ControlGate", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "CliffordGate, abc.ABC"}, {"fullname": "pauliopt.pauli.clifford_gates.ControlGate.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "ControlGate.__init__", "kind": "function", "doc": "

\n", "signature": "(type, control, target)"}, {"fullname": "pauliopt.pauli.clifford_gates.ControlGate.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "ControlGate.rules", "kind": "variable", "doc": "

\n", "default_value": "None"}, {"fullname": "pauliopt.pauli.clifford_gates.ControlGate.control", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "ControlGate.control", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_gates.ControlGate.target", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "ControlGate.target", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_gates.ControlGate.propagate_pauli", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "ControlGate.propagate_pauli", "kind": "function", "doc": "

\n", "signature": "(self, gadget: pauliopt.pauli.pauli_gadget.PauliGadget):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_gates.CX", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CX", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "ControlGate"}, {"fullname": "pauliopt.pauli.clifford_gates.CX.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CX.__init__", "kind": "function", "doc": "

\n", "signature": "(control, target)"}, {"fullname": "pauliopt.pauli.clifford_gates.CX.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CX.rules", "kind": "variable", "doc": "

\n", "default_value": "{'XX': (<Pauli.X: 'X'>, <Pauli.I: 'I'>, 1), 'XY': (<Pauli.Y: 'Y'>, <Pauli.Z: 'Z'>, 1), 'XZ': (<Pauli.Y: 'Y'>, <Pauli.Y: 'Y'>, -1), 'XI': (<Pauli.X: 'X'>, <Pauli.X: 'X'>, 1), 'YX': (<Pauli.Y: 'Y'>, <Pauli.I: 'I'>, 1), 'YY': (<Pauli.X: 'X'>, <Pauli.Z: 'Z'>, -1), 'YZ': (<Pauli.X: 'X'>, <Pauli.Y: 'Y'>, 1), 'YI': (<Pauli.Y: 'Y'>, <Pauli.X: 'X'>, 1), 'ZX': (<Pauli.Z: 'Z'>, <Pauli.X: 'X'>, 1), 'ZY': (<Pauli.I: 'I'>, <Pauli.Y: 'Y'>, 1), 'ZZ': (<Pauli.I: 'I'>, <Pauli.Z: 'Z'>, 1), 'ZI': (<Pauli.Z: 'Z'>, <Pauli.I: 'I'>, 1), 'IX': (<Pauli.I: 'I'>, <Pauli.X: 'X'>, 1), 'IY': (<Pauli.Z: 'Z'>, <Pauli.Y: 'Y'>, 1), 'IZ': (<Pauli.Z: 'Z'>, <Pauli.Z: 'Z'>, 1), 'II': (<Pauli.I: 'I'>, <Pauli.I: 'I'>, 1)}"}, {"fullname": "pauliopt.pauli.clifford_gates.CZ", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CZ", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "ControlGate"}, {"fullname": "pauliopt.pauli.clifford_gates.CZ.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CZ.__init__", "kind": "function", "doc": "

\n", "signature": "(control, target)"}, {"fullname": "pauliopt.pauli.clifford_gates.CZ.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CZ.rules", "kind": "variable", "doc": "

\n", "default_value": "{'XX': (<Pauli.Y: 'Y'>, <Pauli.Y: 'Y'>, 1), 'XY': (<Pauli.Y: 'Y'>, <Pauli.X: 'X'>, -1), 'XZ': (<Pauli.X: 'X'>, <Pauli.I: 'I'>, 1), 'XI': (<Pauli.X: 'X'>, <Pauli.Z: 'Z'>, 1), 'YX': (<Pauli.X: 'X'>, <Pauli.Y: 'Y'>, -1), 'YY': (<Pauli.X: 'X'>, <Pauli.X: 'X'>, 1), 'YZ': (<Pauli.Y: 'Y'>, <Pauli.I: 'I'>, 1), 'YI': (<Pauli.Y: 'Y'>, <Pauli.Z: 'Z'>, 1), 'ZX': (<Pauli.I: 'I'>, <Pauli.X: 'X'>, 1), 'ZY': (<Pauli.I: 'I'>, <Pauli.Y: 'Y'>, 1), 'ZZ': (<Pauli.Z: 'Z'>, <Pauli.Z: 'Z'>, 1), 'ZI': (<Pauli.Z: 'Z'>, <Pauli.I: 'I'>, 1), 'IX': (<Pauli.Z: 'Z'>, <Pauli.X: 'X'>, 1), 'IY': (<Pauli.Z: 'Z'>, <Pauli.Y: 'Y'>, 1), 'IZ': (<Pauli.I: 'I'>, <Pauli.Z: 'Z'>, 1), 'II': (<Pauli.I: 'I'>, <Pauli.I: 'I'>, 1)}"}, {"fullname": "pauliopt.pauli.clifford_gates.CY", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CY", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "ControlGate"}, {"fullname": "pauliopt.pauli.clifford_gates.CY.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CY.__init__", "kind": "function", "doc": "

\n", "signature": "(control, target)"}, {"fullname": "pauliopt.pauli.clifford_gates.CY.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "CY.rules", "kind": "variable", "doc": "

\n", "default_value": "{'XX': (<Pauli.Y: 'Y'>, <Pauli.Z: 'Z'>, -1), 'XY': (<Pauli.X: 'X'>, <Pauli.I: 'I'>, 1), 'XZ': (<Pauli.Y: 'Y'>, <Pauli.X: 'X'>, 1), 'XI': (<Pauli.X: 'X'>, <Pauli.Y: 'Y'>, 1), 'YX': (<Pauli.X: 'X'>, <Pauli.Z: 'Z'>, 1), 'YY': (<Pauli.Y: 'Y'>, <Pauli.I: 'I'>, 1), 'YZ': (<Pauli.X: 'X'>, <Pauli.X: 'X'>, -1), 'YI': (<Pauli.Y: 'Y'>, <Pauli.Y: 'Y'>, 1), 'ZX': (<Pauli.I: 'I'>, <Pauli.X: 'X'>, 1), 'ZY': (<Pauli.Z: 'Z'>, <Pauli.Y: 'Y'>, 1), 'ZZ': (<Pauli.I: 'I'>, <Pauli.Z: 'Z'>, 1), 'ZI': (<Pauli.Z: 'Z'>, <Pauli.I: 'I'>, 1), 'IX': (<Pauli.Z: 'Z'>, <Pauli.X: 'X'>, 1), 'IY': (<Pauli.I: 'I'>, <Pauli.Y: 'Y'>, 1), 'IZ': (<Pauli.Z: 'Z'>, <Pauli.Z: 'Z'>, 1), 'II': (<Pauli.I: 'I'>, <Pauli.I: 'I'>, 1)}"}, {"fullname": "pauliopt.pauli.clifford_gates.H", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "H", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "SingleQubitGate"}, {"fullname": "pauliopt.pauli.clifford_gates.H.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "H.__init__", "kind": "function", "doc": "

\n", "signature": "(qubit)"}, {"fullname": "pauliopt.pauli.clifford_gates.H.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "H.rules", "kind": "variable", "doc": "

\n", "default_value": "{'X': (<Pauli.Z: 'Z'>, 1), 'Y': (<Pauli.Y: 'Y'>, -1), 'Z': (<Pauli.X: 'X'>, 1), 'I': (<Pauli.I: 'I'>, 1)}"}, {"fullname": "pauliopt.pauli.clifford_gates.S", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "S", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "SingleQubitGate"}, {"fullname": "pauliopt.pauli.clifford_gates.S.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "S.__init__", "kind": "function", "doc": "

\n", "signature": "(qubit)"}, {"fullname": "pauliopt.pauli.clifford_gates.S.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "S.rules", "kind": "variable", "doc": "

\n", "default_value": "{'X': (<Pauli.Y: 'Y'>, -1), 'Y': (<Pauli.X: 'X'>, 1), 'Z': (<Pauli.Z: 'Z'>, 1), 'I': (<Pauli.I: 'I'>, 1)}"}, {"fullname": "pauliopt.pauli.clifford_gates.V", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "V", "kind": "class", "doc": "

Helper class that provides a standard way to create an ABC using\ninheritance.

\n", "bases": "SingleQubitGate"}, {"fullname": "pauliopt.pauli.clifford_gates.V.__init__", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "V.__init__", "kind": "function", "doc": "

\n", "signature": "(qubit)"}, {"fullname": "pauliopt.pauli.clifford_gates.V.rules", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "V.rules", "kind": "variable", "doc": "

\n", "default_value": "{'X': (<Pauli.X: 'X'>, 1), 'Y': (<Pauli.Z: 'Z'>, -1), 'Z': (<Pauli.Y: 'Y'>, 1), 'I': (<Pauli.I: 'I'>, 1)}"}, {"fullname": "pauliopt.pauli.clifford_gates.generate_random_clifford", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "generate_random_clifford", "kind": "function", "doc": "

\n", "signature": "(c_type: pauliopt.pauli.clifford_gates.CliffordType, n_qubits: int):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_gates.clifford_to_qiskit", "modulename": "pauliopt.pauli.clifford_gates", "qualname": "clifford_to_qiskit", "kind": "function", "doc": "

\n", "signature": "(clifford: pauliopt.pauli.clifford_gates.CliffordGate):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_region", "modulename": "pauliopt.pauli.clifford_region", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_region.CliffordRegion", "modulename": "pauliopt.pauli.clifford_region", "qualname": "CliffordRegion", "kind": "class", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_region.CliffordRegion.__init__", "modulename": "pauliopt.pauli.clifford_region", "qualname": "CliffordRegion.__init__", "kind": "function", "doc": "

\n", "signature": "(num_qubits, gates=None)"}, {"fullname": "pauliopt.pauli.clifford_region.CliffordRegion.gates", "modulename": "pauliopt.pauli.clifford_region", "qualname": "CliffordRegion.gates", "kind": "variable", "doc": "

\n", "annotation": ": [<class 'pauliopt.pauli.clifford_gates.CliffordGate'>]"}, {"fullname": "pauliopt.pauli.clifford_region.CliffordRegion.num_qubits", "modulename": "pauliopt.pauli.clifford_region", "qualname": "CliffordRegion.num_qubits", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.clifford_region.CliffordRegion.add_gate", "modulename": "pauliopt.pauli.clifford_region", "qualname": "CliffordRegion.add_gate", "kind": "function", "doc": "

\n", "signature": "(self, gate: pauliopt.pauli.clifford_gates.CliffordGate):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.clifford_region.CliffordRegion.to_qiskit", "modulename": "pauliopt.pauli.clifford_region", "qualname": "CliffordRegion.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_gadget", "modulename": "pauliopt.pauli.pauli_gadget", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_gadget.decompose_cnot_ladder_z", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "decompose_cnot_ladder_z", "kind": "function", "doc": "

\n", "signature": "(ctrl: int, trg: int, arch: pauliopt.topologies.Topology):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_gadget.find_minimal_cx_assignment", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "find_minimal_cx_assignment", "kind": "function", "doc": "

\n", "signature": "(\tcolumn: <built-in function array>,\tarch: pauliopt.topologies.Topology):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_gadget.PPhase", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PPhase", "kind": "class", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_gadget.PPhase.__init__", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PPhase.__init__", "kind": "function", "doc": "

\n", "signature": "(angle: pauliopt.utils.AngleExpr)"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget", "kind": "class", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget.__init__", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget.__init__", "kind": "function", "doc": "

\n", "signature": "(\tangle: pauliopt.utils.AngleExpr,\tpaulis: List[pauliopt.pauli.utils.Pauli])"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget.angle", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget.angle", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget.paulis", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget.paulis", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget.copy", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget.copy", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget.two_qubit_count", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget.two_qubit_count", "kind": "function", "doc": "

\n", "signature": "(self, topology, leg_cache=None):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_gadget.PauliGadget.to_qiskit", "modulename": "pauliopt.pauli.pauli_gadget", "qualname": "PauliGadget.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self, topology=None):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_polynomial", "modulename": "pauliopt.pauli.pauli_polynomial", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial", "kind": "class", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.__init__", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.__init__", "kind": "function", "doc": "

\n", "signature": "(num_qubits)"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.num_qubits", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.num_qubits", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.pauli_gadgets", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.pauli_gadgets", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.num_gadgets", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.num_gadgets", "kind": "variable", "doc": "

\n"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.to_qiskit", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self, topology=None):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.propagate", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.propagate", "kind": "function", "doc": "

\n", "signature": "(self, gate: pauliopt.pauli.clifford_gates.CliffordGate):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.copy", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.copy", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.two_qubit_count", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.two_qubit_count", "kind": "function", "doc": "

\n", "signature": "(self, topology, leg_cache=None):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.pauli_polynomial.PauliPolynomial.to_svg", "modulename": "pauliopt.pauli.pauli_polynomial", "qualname": "PauliPolynomial.to_svg", "kind": "function", "doc": "

\n", "signature": "(\tself,\thscale: float = 1.0,\tvscale: float = 1.0,\tscale: float = 1.0,\tsvg_code_only=False):", "funcdef": "def"}, {"fullname": "pauliopt.pauli.utils", "modulename": "pauliopt.pauli.utils", "kind": "module", "doc": "

\n"}, {"fullname": "pauliopt.pauli.utils.Pauli", "modulename": "pauliopt.pauli.utils", "qualname": "Pauli", "kind": "class", "doc": "

An enumeration.

\n", "bases": "enum.Enum"}, {"fullname": "pauliopt.pauli.utils.Pauli.I", "modulename": "pauliopt.pauli.utils", "qualname": "Pauli.I", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.I: 'I'>"}, {"fullname": "pauliopt.pauli.utils.Pauli.X", "modulename": "pauliopt.pauli.utils", "qualname": "Pauli.X", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.X: 'X'>"}, {"fullname": "pauliopt.pauli.utils.Pauli.Y", "modulename": "pauliopt.pauli.utils", "qualname": "Pauli.Y", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.Y: 'Y'>"}, {"fullname": "pauliopt.pauli.utils.Pauli.Z", "modulename": "pauliopt.pauli.utils", "qualname": "Pauli.Z", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.Z: 'Z'>"}, {"fullname": "pauliopt.pauli.utils.I", "modulename": "pauliopt.pauli.utils", "qualname": "I", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.I: 'I'>"}, {"fullname": "pauliopt.pauli.utils.X", "modulename": "pauliopt.pauli.utils", "qualname": "X", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.X: 'X'>"}, {"fullname": "pauliopt.pauli.utils.Y", "modulename": "pauliopt.pauli.utils", "qualname": "Y", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.Y: 'Y'>"}, {"fullname": "pauliopt.pauli.utils.Z", "modulename": "pauliopt.pauli.utils", "qualname": "Z", "kind": "variable", "doc": "

\n", "default_value": "<Pauli.Z: 'Z'>"}, {"fullname": "pauliopt.phase", "modulename": "pauliopt.phase", "kind": "module", "doc": "

This module contains code to create and simplify circuits of mixed ZX phase gadgets,\nby conjugation with topologically-aware random circuits of CX gates.

\n"}, {"fullname": "pauliopt.phase.cx_circuits", "modulename": "pauliopt.phase.cx_circuits", "kind": "module", "doc": "

This module contains code to create CX circuits for the optimization\nof circuits of mixed phase gadgets.

\n"}, {"fullname": "pauliopt.phase.cx_circuits.GateLike", "modulename": "pauliopt.phase.cx_circuits", "qualname": "GateLike", "kind": "variable", "doc": "

\n", "default_value": "typing.Union[typing.List[int], typing.Tuple[int, int]]"}, {"fullname": "pauliopt.phase.cx_circuits.synthesis_methods", "modulename": "pauliopt.phase.cx_circuits", "qualname": "synthesis_methods", "kind": "variable", "doc": "

\n", "default_value": "['permrowcol']"}, {"fullname": "pauliopt.phase.cx_circuits.permrowcol", "modulename": "pauliopt.phase.cx_circuits", "qualname": "permrowcol", "kind": "function", "doc": "

Generates a sequence of CNOTs reallizing the given parity matrix up to permutation (if reallocate=True) using\nthe algorithm from https://arxiv.org/abs/2205.00724.

\n\n

Args:\n matrix (numpy.NDArray): The binary parity matrix\n topology (Topology): The target device topology\n parities_as_columns (bool): Whether the parities in the matrix are row-wise or column-wise. Defaults to False, i.e. row-wise.\n reallocate (bool, optional): Whether to qubits can re reallocated. Defaults to False.

\n\n

Raises:\n ModuleNotFoundError: If 'networkx' or 'galois' is not installed.

\n\n

Returns:\n List[Tuple[int]]: List of CNOTs realizing the given parity matrix\n List[int]: The output permutation of the qubit mapping. Equals [0..n] if reallocate==False.

\n", "signature": "(\tmatrix: numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]],\ttopology: pauliopt.topologies.Topology,\tparities_as_columns: bool = False,\treallocate: bool = False) -> Tuple[List[Tuple[int]], List[int]]:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer", "kind": "class", "doc": "

Container for a layer of CX gates constrained\nby a given qubit topology.

\n\n

It uses pauliopt.topologies.Matching to keep track of which\ncouplings in the qubit topology are currently occupied by a CX gate,\nand to efficiently determine whether a CX gate can be added to the layer.

\n"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.__init__", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.__init__", "kind": "function", "doc": "

\n", "signature": "(\ttopology: pauliopt.topologies.Topology,\tgates: Collection[Union[List[int], Tuple[int, int]]] = ())"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.topology", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.topology", "kind": "variable", "doc": "

Readonly property exposing the qubit topology\nconstraining this CX circuit layer.

\n", "annotation": ": pauliopt.topologies.Topology"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.num_gates", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.num_gates", "kind": "variable", "doc": "

Readonly property returning the number of gates in this\nCX circuit layer.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.gates", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.gates", "kind": "variable", "doc": "

Readonly property returning the collection of gates in this\nCX circuit layer.

\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[Tuple[int, int]]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.num_flippable_cxs", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.num_flippable_cxs", "kind": "variable", "doc": "

Readonly property returning the number of CX gates in this\nCX circuit layer that can be flipped.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.flippable_cxs", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.flippable_cxs", "kind": "variable", "doc": "

Readonly property returning the collection of CX gates that\nthat can be currently flipped in this layer, namely:

\n\n
    \n
  • all gates currently in the layer (will be removed by flip);
  • \n
  • all gates with both qubits currently not covered by a gate\nalready in the layer (will be added by flip).
  • \n
\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[Tuple[int, int]]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.incident", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.incident", "kind": "function", "doc": "

Returns the CX gate incident to the given qubit in this layer,\nor None if there is no gate incident to the qubit.

\n", "signature": "(self, qubit: int) -> Optional[Tuple[int, int]]:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.has_cx", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.has_cx", "kind": "function", "doc": "

Checks whether the given CX gate is in the layer:

\n", "signature": "(self, ctrl: int, trgt: int) -> bool:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.is_cx_flippable", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.is_cx_flippable", "kind": "function", "doc": "

Checks whether the given CX gate can be flipped in this layer.\nThis is true if:

\n\n
    \n
  • the gate is present (gate can be removed);
  • \n
  • the gate is not present, and neither the control nor the\ntarget are already covered by some other gate (gate can be added).
  • \n
\n", "signature": "(self, ctrl: int, trgt: int) -> bool:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.random_flip_cx", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.random_flip_cx", "kind": "function", "doc": "

Returns a randomly selected flippable CX gate in this CX circuit layer,\nusing the given random number generator.

\n", "signature": "(self, rng: numpy.random._generator.Generator) -> Tuple[int, int]:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.flip_cx", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.flip_cx", "kind": "function", "doc": "

Adds/removes a CX gate with given control and target to/from the layer.\nRaises ValueError if the gate cannot be added/removed.

\n\n

The layer is modified in-place and then returned, as per the\nfluent API pattern.

\n", "signature": "(self, ctrl: int, trgt: int) -> pauliopt.phase.cx_circuits.CXCircuitLayer:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.clone", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.clone", "kind": "function", "doc": "

Returns a copy of this CX layer.

\n", "signature": "(self) -> pauliopt.phase.cx_circuits.CXCircuitLayer:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.to_qiskit", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayer.draw", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayer.draw", "kind": "function", "doc": "

Draws this CX circuit layer using NetworkX and Matplotlib.

\n\n

The layout keyword argument can be used to select a NetworkX layout\nfrom the available ones (exposed by Topology.available_nx_layouts).\nThe figsize keyword argument is passed to matplotlib.pyplot.figure:\nif specified, it determines the width and height of the figure being drawn.\nThe zcolor and xcolor keyword arguments are used to determine the colour\nof the Z and X dots in a CX gate (analogous to PhaseCircuit.to_svg).\nKeyword arguments kwargs are those of networkx.draw_networkx.

\n", "signature": "(\tself,\tlayout: str = 'kamada_kawai',\t*,\tfigsize: Optional[Tuple[int, int]] = None,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\tnoshow: bool = False,\t**kwargs):", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerLike", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerLike", "kind": "variable", "doc": "

\n", "default_value": "typing.Union[pauliopt.phase.cx_circuits.CXCircuitLayer, ForwardRef('CXCircuitLayerView'), typing.Sequence[typing.Union[typing.List[int], typing.Tuple[int, int]]]]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLike", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLike", "kind": "variable", "doc": "

\n", "default_value": "typing.Union[ForwardRef('CXCircuit'), ForwardRef('CXCircuitView'), typing.Sequence[typing.Union[pauliopt.phase.cx_circuits.CXCircuitLayer, ForwardRef('CXCircuitLayerView'), typing.Sequence[typing.Union[typing.List[int], typing.Tuple[int, int]]]]]]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit", "kind": "class", "doc": "

Container for a circuit of CX gates, consisting of a given number of layers\nand constrained by a given qubit topology.

\n", "bases": "typing.Sequence[pauliopt.phase.cx_circuits.CXCircuitLayer]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.__init__", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.__init__", "kind": "function", "doc": "

\n", "signature": "(\ttopology: pauliopt.topologies.Topology,\tlayers: Sequence[pauliopt.phase.cx_circuits.CXCircuitLayer] = (),\toutput_mapping: Sequence[int] = None)"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.topology", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.topology", "kind": "variable", "doc": "

Readonly property exposing the qubit topology\nconstraining this CX circuit.

\n", "annotation": ": pauliopt.topologies.Topology"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.num_gates", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.num_gates", "kind": "variable", "doc": "

Readonly property returning the total number of gates in this\nCX circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.parity_matrix", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.parity_matrix", "kind": "function", "doc": "

Generates the parity matrix representing this CX circuit.

\n\n

Args:\n parities_as_columns (bool, optional): Boolean determining whether the\n parity matrix should be represented with parities as columns in the matrix.\n Defaults to False, meaning that the parities are rows in the matrix.

\n\n

Returns:\n numpy.NDArray containing 1s and 0s.

\n", "signature": "(\tself,\tparities_as_columns: bool = False) -> numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.dag", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.dag", "kind": "function", "doc": "

Returns a copy of this CX circuit,\nwith the layers in reverse order.

\n", "signature": "(self) -> pauliopt.phase.cx_circuits.CXCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.clone", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.clone", "kind": "function", "doc": "

Returns a copy of this CX circuit.

\n", "signature": "(self) -> pauliopt.phase.cx_circuits.CXCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.to_qiskit", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.to_qiskit", "kind": "function", "doc": "

\n", "signature": "(\tself,\tmethod: Literal['permrowcol', 'naive'] = 'naive',\treallocate: bool = False,\tparities_as_columns: bool = False) -> Any:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.draw", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.draw", "kind": "function", "doc": "

Draws this CX circuit using NetworkX and Matplotlib.\nKeyword arguments kwargs are those of networkx.draw_networkx.

\n", "signature": "(\tself,\tlayout: str = 'kamada_kawai',\t*,\tfigsize: Optional[Tuple[int, int]] = None,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\tfilename: Optional[str] = None,\t**kwargs):", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuit.from_parity_matrix", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuit.from_parity_matrix", "kind": "function", "doc": "

Generates a CXCircuit from a given parity matrix, constrained by the given topology

\n\n

Args:\n matrix (np.typing.NDArray): The parity matrix to be synthesized\n topology (Topology): The target device topology\n parities_as_columns (bool, optional): Whether the parities in the matrix are column-wise or row-wise. Defaults to False, i.e. row-wise.\n reallocate (bool, optional): Whether the qubits can be reallocated to different registers, i.e. synthesis up to permutation. Defaults to False.\n method (Literal[\"permrowcol\"], optional): Which synthesis method should be used. Currently only permrowcol is available.

\n\n

Returns:\n CXCircuit: Synthesized circuit

\n", "signature": "(\tmatrix: numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]],\ttopology: pauliopt.topologies.Topology,\tparities_as_columns: bool = False,\treallocate: bool = False,\tmethod: Literal['permrowcol'] = 'permrowcol') -> pauliopt.phase.cx_circuits.CXCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView", "kind": "class", "doc": "

Readonly view on a CX circuit layer.

\n"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.__init__", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.__init__", "kind": "function", "doc": "

\n", "signature": "(layer: pauliopt.phase.cx_circuits.CXCircuitLayer)"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.topology", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.topology", "kind": "variable", "doc": "

Readonly property exposing the qubit topology\nconstraining this CX circuit layer.

\n", "annotation": ": pauliopt.topologies.Topology"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.gates", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.gates", "kind": "variable", "doc": "

Readonly property returning the collection of gates in this\nCX circuit layer.

\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[Tuple[int, int]]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.num_gates", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.num_gates", "kind": "variable", "doc": "

Readonly property returning the number of gates in this\nCX circuit layer.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.flippable_cxs", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.flippable_cxs", "kind": "variable", "doc": "

Readonly property returning the collection of CX gates that\nthat can be currently flipped in this layer, namely:

\n\n
    \n
  • all gates currently in the layer (will be removed by flip);
  • \n
  • all gates with both qubits currently not covered by a gate\nalready in the layer (will be added by flip).
  • \n
\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[Tuple[int, int]]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.incident", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.incident", "kind": "function", "doc": "

Returns the CX gate incident to the given qubit in this layer,\nor None if there is no gate incident to the qubit.

\n", "signature": "(self, qubit: int) -> Optional[Tuple[int, int]]:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.has_cx", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.has_cx", "kind": "function", "doc": "

Checks whether the given CX gate is in the layer:

\n", "signature": "(self, ctrl: int, trgt: int) -> bool:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.is_cx_flippable", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.is_cx_flippable", "kind": "function", "doc": "

Checks whether the given CX gate can be flipped in this layer.\nThis is true if:

\n\n
    \n
  • the gate is present (gate can be removed);
  • \n
  • the gate is not present, and neither the control nor the\ntarget are already covered by some other gate (gate can be added).
  • \n
\n", "signature": "(self, ctrl: int, trgt: int) -> bool:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.clone", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.clone", "kind": "function", "doc": "

Returns a copy of this CX layer.

\n", "signature": "(self) -> pauliopt.phase.cx_circuits.CXCircuitLayer:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitLayerView.draw", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitLayerView.draw", "kind": "function", "doc": "

Draws this CX circuit layer using NetworkX and Matplotlib.\nKeyword arguments kwargs are those of networkx.draw_networkx.

\n", "signature": "(\tself,\tlayout: str = 'kamada_kawai',\t*,\tfigsize: Optional[Tuple[int, int]] = None,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\t**kwargs):", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView", "kind": "class", "doc": "

Readonly view on a CX circuit.

\n", "bases": "typing.Sequence[pauliopt.phase.cx_circuits.CXCircuitLayerView]"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView.__init__", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView.__init__", "kind": "function", "doc": "

\n", "signature": "(circuit: pauliopt.phase.cx_circuits.CXCircuit)"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView.topology", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView.topology", "kind": "variable", "doc": "

Readonly property exposing the qubit topology\nconstraining this CX circuit.

\n", "annotation": ": pauliopt.topologies.Topology"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView.num_gates", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView.num_gates", "kind": "variable", "doc": "

Readonly property returning the number of gates in this\nCX circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView.dag", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView.dag", "kind": "function", "doc": "

Returns a copy of this CX circuit,\nwith the layers in reverse order.

\n", "signature": "(self) -> pauliopt.phase.cx_circuits.CXCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView.clone", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView.clone", "kind": "function", "doc": "

Returns a copy of this CX circuit.

\n", "signature": "(self) -> pauliopt.phase.cx_circuits.CXCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.cx_circuits.CXCircuitView.draw", "modulename": "pauliopt.phase.cx_circuits", "qualname": "CXCircuitView.draw", "kind": "function", "doc": "

Draws this CX circuit using NetworkX and Matplotlib.\nKeyword arguments kwargs are those of networkx.draw_networkx.

\n", "signature": "(\tself,\tlayout: str = 'kamada_kawai',\t*,\tfigsize: Optional[Tuple[int, int]] = None,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\t**kwargs):", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits", "modulename": "pauliopt.phase.optimized_circuits", "kind": "module", "doc": "

This module contains code to optimize circuits of mixed ZX phase gadgets\nusing topologically-aware circuits of CNOTs.

\n"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingCostLogger", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingCostLogger", "kind": "class", "doc": "

Protocol for logger of initial/final cost in annealing.

\n", "bases": "typing.Protocol"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingCostLogger.__init__", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingCostLogger.__init__", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs)"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingIterLogger", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingIterLogger", "kind": "class", "doc": "

Protocol for logging of iteration info in annealing.

\n", "bases": "typing.Protocol"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingIterLogger.__init__", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingIterLogger.__init__", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs)"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingLoggers", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingLoggers", "kind": "class", "doc": "

Typed dictionary of loggers for annealing.

\n", "bases": "typing.TypedDict"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingLoggers.log_start", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingLoggers.log_start", "kind": "variable", "doc": "

\n", "annotation": ": pauliopt.phase.optimized_circuits.AnnealingCostLogger"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingLoggers.log_iter", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingLoggers.log_iter", "kind": "variable", "doc": "

\n", "annotation": ": pauliopt.phase.optimized_circuits.AnnealingIterLogger"}, {"fullname": "pauliopt.phase.optimized_circuits.AnnealingLoggers.log_end", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "AnnealingLoggers.log_end", "kind": "variable", "doc": "

\n", "annotation": ": pauliopt.phase.optimized_circuits.AnnealingCostLogger"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit", "kind": "class", "doc": "

Container for a phase circuit to be progressively optimized.\nThe original phase circuit is passed to the constructor, together\nwith a qubit topology and a fixed number of layers constraining the\nCX circuit to be used for simplification.

\n\n

To understand the structure of the optimized phase circuit,\nconsider the following code snippet:

\n\n
\n
    opt_circ = PhaseCircuitCXBlockOptimizer(orig_circ, topology, num_cx_layers)\n    # perform optimization using the methods of `opt_circ`\n    phase_block = opt_circ.phase_block\n    cx_block = opt_circ.cx_block\n
\n
\n\n

The optimized circuit is obtained by composing three blocks:

\n\n
    \n
  1. a first block of CX gates, given by cx_block.dag()\n(the same CX gates of cx_block, but in reverse order);
  2. \n
  3. a central block of phase gadgets, given by phase_block;
  4. \n
  5. a final block of CX gates, given by cx_block.
  6. \n
\n\n

An optional keyword argument circuit_rep (default: 1) can be passed to the\nconstructor to indicate that the original circuit is to be repeated a certain\nnumber of times (default: 1). In the optimized circuit, this is achieved by\nrepeating the phase_block part (at point 2. above) a number of times\ngiven by the circuit_rep argument.\nThe first and last CX blocks are left unaltered (because the intermediate CX\nblocks would cancel each other out in pairs when repeating the optimized circuit).

\n"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.__init__", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.__init__", "kind": "function", "doc": "

\n", "signature": "(\tphase_block: Union[pauliopt.phase.phase_circuits.PhaseCircuit, pauliopt.phase.phase_circuits.PhaseCircuitView],\ttopology: pauliopt.topologies.Topology,\tcx_block: Union[int, pauliopt.phase.cx_circuits.CXCircuit, pauliopt.phase.cx_circuits.CXCircuitView],\t*,\tcircuit_rep: int = 1,\trng_seed: Optional[int] = None,\tfresh_angle_vars: Union[NoneType, str, Callable[[int], pauliopt.utils.AngleVar]] = None,\tqubit_mapping: Sequence[int] = None,\tphase_method: Literal['naive', 'paritysynth', 'steiner-graysynth'] = 'naive',\tcx_method: Literal['permrowcol', 'naive'] = 'naive',\treallocate: bool = False)"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.topology", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.topology", "kind": "variable", "doc": "

Readonly property exposing the topology constraining the circuit optimization.

\n", "annotation": ": pauliopt.topologies.Topology"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.num_qubits", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.num_qubits", "kind": "variable", "doc": "

Readonly property exposing the number of qubits spanned by the circuit to be optimized.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.circuit_rep", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.circuit_rep", "kind": "variable", "doc": "

Readonly property exposing the number of times that the original circuit is\nto be repeated, for use when computing CX counts.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.phase_block", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.phase_block", "kind": "variable", "doc": "

Readonly property exposing a readonly view on the phase block of the optimized circuit.

\n", "annotation": ": pauliopt.phase.phase_circuits.PhaseCircuitView"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.cx_block", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.cx_block", "kind": "variable", "doc": "

Readonly property exposing a readonly view on the CX block of the optimized circuit.

\n", "annotation": ": pauliopt.phase.cx_circuits.CXCircuitView"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.init_cx_count", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.init_cx_count", "kind": "variable", "doc": "

Readonly property exposing the CX count for the original circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.cx_count", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.cx_count", "kind": "variable", "doc": "

Readonly property exposing the current CX count for the optimized circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.init_cx_blocks_count", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.init_cx_blocks_count", "kind": "variable", "doc": "

Readonly property exposing the overall CX count for the two conjugating\nCX blocks at the time the circuit was instantiated.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.cx_blocks_count", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.cx_blocks_count", "kind": "variable", "doc": "

Readonly property exposing the overall CX count for the conjugating\nCX blocks in the currently optimized circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.init_phase_block_cx_count", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.init_phase_block_cx_count", "kind": "variable", "doc": "

Readonly property exposing the overall CX count for a single\nphase block at the time the circuit was instantiated.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.phase_block_cx_count", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.phase_block_cx_count", "kind": "variable", "doc": "

Readonly property exposing the overall CX count for a single\nphase block in the currently optimized circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.clone", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.clone", "kind": "function", "doc": "

Returns a copy of this optimized phase circuit.

\n", "signature": "(\tself,\trng_seed: Optional[int] = None) -> pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.to_qiskit", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.to_qiskit", "kind": "function", "doc": "

Returns the optimized circuit as a Qiskit circuit.

\n\n

This method relies on the qiskit library being available.\nSpecifically, the circuit argument must be of type\nqiskit.providers.BaseBackend.

\n", "signature": "(self, simplified: bool = True):", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.simplify", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.simplify", "kind": "function", "doc": "

Simplifies the phase block according to the commutation and fusion\nrules for phase gadgets.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.anneal", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.anneal", "kind": "function", "doc": "

Performs a cycle of simulated annealing optimization,\nusing the given number of iterations, temperature schedule,\ninitial/final temperatures.

\n\n

The circuit is modified in-place and then returned, as per the\nfluent API pattern.

\n", "signature": "(\tself,\tnum_iters: int,\t*,\tschedule: Union[Tuple[Literal['linear', 'geometric', 'reciprocal', 'log'], Union[int, float], Union[int, float]], pauliopt.utils.TempSchedule] = ('linear', 1.0, 0.1),\tloggers: pauliopt.phase.optimized_circuits.AnnealingLoggers = {}):", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.random_flip_cx", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.random_flip_cx", "kind": "function", "doc": "

Randomly flips a CX gate in the CX circuit used for the optimization,\nupdating both the CX circuit and the circuit being optimized.

\n\n

Returns the layer index and gate (pair of control and target) that were\nflipped (e.g. in case the flip needs to be subsequently undone).

\n", "signature": "(self) -> Tuple[int, Tuple[int, int]]:", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.is_cx_flippable", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.is_cx_flippable", "kind": "function", "doc": "

Checks whether the given CX gate can be flipped in the given layer.

\n", "signature": "(self, layer_idx: int, ctrl: int, trgt: int) -> bool:", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.flip_cx", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.flip_cx", "kind": "function", "doc": "

Performs the actions needed to flip the given CX gate in the given layer\nof the CX circuit used for the optimization:

\n\n
    \n
  • undoes all gates in layers subsequent to the given layer which are\ncausally following the given gate, starting from the last layer and\nworking backwards towards the gate;
  • \n
  • applies the desired gate;
  • \n
  • redoes all gate undone, in reverse order (starting from the gate and\nworking forwards towards the last layer).
  • \n
\n", "signature": "(self, layer_idx: int, ctrl: int, trgt: int):", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit.to_svg", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "OptimizedPhaseCircuit.to_svg", "kind": "function", "doc": "

Returns an SVG representation of this optimized circuit, using\nthe ZX calculus to express phase gadgets and CX gates.

\n\n

The keyword arguments zcolor and xcolor can be used to\nspecify a colour for the Z and X basis spiders in the circuit.\nThe keyword arguments hscale and vscale can be used to\nscale the circuit representation horizontally and vertically.\nThe keyword argument scale can be used to scale the circuit\nrepresentation isotropically.\nThe keyword argument svg_code_only (default False) can be used\nto specify that the SVG code itself be returned, rather than the\nIPython SVG object.

\n", "signature": "(\tself,\t*,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\thscale: float = 1.0,\tvscale: float = 1.0,\tscale: float = 1.0,\tsvg_code_only: bool = False):", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.iter_anneal", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "iter_anneal", "kind": "function", "doc": "

\n", "signature": "(\tcircuit: pauliopt.phase.phase_circuits.PhaseCircuit,\ttopology: pauliopt.topologies.Topology,\tcx_blocks,\tnum_iters: int,\tnum_anneal_iters: int,\topt_kwargs: Dict = {},\tanneal_kwargs: Dict = {}) -> pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.reverse_traversal_anneal", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "reverse_traversal_anneal", "kind": "function", "doc": "

\n", "signature": "(\tcircuit: pauliopt.phase.phase_circuits.PhaseCircuit,\ttopology: pauliopt.topologies.Topology,\tcx_blocks,\tnum_iters: int,\tnum_anneal_iters: int,\topt_kwargs: Dict = {},\tanneal_kwargs: Dict = {}) -> pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.optimized_circuits.reverse_traversal", "modulename": "pauliopt.phase.optimized_circuits", "qualname": "reverse_traversal", "kind": "function", "doc": "

\n", "signature": "(\tcircuit: pauliopt.phase.phase_circuits.PhaseCircuit,\ttopology: pauliopt.topologies.Topology,\tcx_blocks,\tnum_iters: int,\tnum_anneal_iters=0,\topt_kwargs: Dict = {},\tanneal_kwargs: Dict = {}) -> pauliopt.phase.optimized_circuits.OptimizedPhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits", "modulename": "pauliopt.phase.phase_circuits", "kind": "module", "doc": "

This module contains code to create circuits of mixed ZX phase gadgets.

\n"}, {"fullname": "pauliopt.phase.phase_circuits.synthesis_methods", "modulename": "pauliopt.phase.phase_circuits", "qualname": "synthesis_methods", "kind": "variable", "doc": "

\n", "default_value": "['naive', 'paritysynth', 'steiner-graysynth']"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget", "kind": "class", "doc": "

Immutable container class for a phase gadget.

\n"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.__init__", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.__init__", "kind": "function", "doc": "

\n", "signature": "(\tbasis: Literal['Z', 'X'],\tangle: pauliopt.utils.AngleExpr,\tqubits: Collection[int])"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.basis", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.basis", "kind": "variable", "doc": "

Readonly property exposing the basis for this phase gadget.

\n", "annotation": ": Literal['Z', 'X']"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.angle", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.angle", "kind": "variable", "doc": "

Readonly property exposing the angle for this phase gadget.

\n", "annotation": ": pauliopt.utils.AngleExpr"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.qubits", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.qubits", "kind": "variable", "doc": "

Readonly property exposing the qubits spanned by this phase gadget.

\n", "annotation": ": FrozenSet[int]"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.cx_count", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.cx_count", "kind": "function", "doc": "

Returns the CX count for an implementation of this phase gadget\non the given topology based on minimum spanning trees (MST).

\n\n

The optional mapping keyword argument can be used to specify a mapping of\nlogical (circuit) qubits to phyisical (topology) qubits.

\n", "signature": "(\tself,\ttopology: pauliopt.topologies.Topology,\t*,\tmapping: Union[Sequence[int], Dict[int, int], NoneType] = None) -> int:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.on_qiskit_circuit", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.on_qiskit_circuit", "kind": "function", "doc": "

Applies this phase gadget to a given qiskit quantum circuit,\nusing the given topology to determine a minimum spanning\ntree implementation of the gadget.

\n\n

This method relies on the qiskit library being available.\nSpecifically, the circuit argument must be of type\nqiskit.providers.BaseBackend.

\n", "signature": "(self, topology: pauliopt.topologies.Topology, circuit: Any) -> None:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseGadget.print_impl_info", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseGadget.print_impl_info", "kind": "function", "doc": "

Prints information about an implementation of this phase gadget\non the given topology based on minimum spanning trees (MST).

\n", "signature": "(self, topology: pauliopt.topologies.Topology) -> None:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.Z", "modulename": "pauliopt.phase.phase_circuits", "qualname": "Z", "kind": "class", "doc": "

Constructs a Z phase gadget with the idiomatic syntax:

\n\n
\n
    Z(angle) @ qubits\n
\n
\n"}, {"fullname": "pauliopt.phase.phase_circuits.Z.__init__", "modulename": "pauliopt.phase.phase_circuits", "qualname": "Z.__init__", "kind": "function", "doc": "

\n", "signature": "(angle: pauliopt.utils.AngleExpr)"}, {"fullname": "pauliopt.phase.phase_circuits.X", "modulename": "pauliopt.phase.phase_circuits", "qualname": "X", "kind": "class", "doc": "

Constructs an X phase gadget with the idiomatic syntax:

\n\n
\n
    X(angle) @ qubits\n
\n
\n"}, {"fullname": "pauliopt.phase.phase_circuits.X.__init__", "modulename": "pauliopt.phase.phase_circuits", "qualname": "X.__init__", "kind": "function", "doc": "

\n", "signature": "(angle: pauliopt.utils.AngleExpr)"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit", "kind": "class", "doc": "

Container class for a circuit of mixed ZX phase gadgets.

\n", "bases": "typing.Sequence[pauliopt.phase.phase_circuits.PhaseGadget]"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.__init__", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.__init__", "kind": "function", "doc": "

\n", "signature": "(\tnum_qubits: int,\tgadgets: Sequence[pauliopt.phase.phase_circuits.PhaseGadget] = ())"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.num_qubits", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.num_qubits", "kind": "variable", "doc": "

Readonly property exposing the number of qubits spanned by this phase circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.num_gadgets", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.num_gadgets", "kind": "variable", "doc": "

Readonly property exposing the number of phase gadgets in the circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.gadgets", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.gadgets", "kind": "variable", "doc": "

Readonly property returning the sequence of phase gadgets in this\nphase circuit, in order from first to last.

\n\n

This collection is freshly generated at every call.

\n", "annotation": ": Sequence[pauliopt.phase.phase_circuits.PhaseGadget]"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.as_readonly", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.as_readonly", "kind": "variable", "doc": "

Returns a readonly view on this circuit.

\n", "annotation": ": pauliopt.phase.phase_circuits.PhaseCircuitView"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.set_angles", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.set_angles", "kind": "function", "doc": "

Sets all angles for this circuit.

\n", "signature": "(self, angles: Sequence[pauliopt.utils.AngleExpr]) -> None:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.refresh_angle_vars", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.refresh_angle_vars", "kind": "function", "doc": "

\n", "signature": "(\tself,\tparams: Union[str, Callable[[int], pauliopt.utils.AngleVar]]) -> None:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.rx", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.rx", "kind": "function", "doc": "

Phase gadget implementation of single-qubit X rotation.

\n", "signature": "(\tself,\tqubit: int,\tangle: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.rz", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.rz", "kind": "function", "doc": "

Phase gadget implementation of single-qubit Z rotation.

\n", "signature": "(\tself,\tqubit: int,\tangle: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.ry", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.ry", "kind": "function", "doc": "

Phase gadget implementation of single-qubit Y rotation.

\n", "signature": "(\tself,\tqubit: int,\tangle: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.i", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.i", "kind": "function", "doc": "

Phase gadget implementation of single-qubit I gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.x", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.x", "kind": "function", "doc": "

Phase gadget implementation of single-qubit X gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.z", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.z", "kind": "function", "doc": "

Phase gadget implementation of single-qubit X gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.y", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.y", "kind": "function", "doc": "

Phase gadget implementation of single-qubit Y gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.s", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.s", "kind": "function", "doc": "

Phase gadget implementation of single-qubit S gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.sdg", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.sdg", "kind": "function", "doc": "

Phase gadget implementation of single-qubit Sdg gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.v", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.v", "kind": "function", "doc": "

Phase gadget implementation of single-qubit S gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.vdg", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.vdg", "kind": "function", "doc": "

Phase gadget implementation of single-qubit Sdg gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.t", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.t", "kind": "function", "doc": "

Phase gadget implementation of single-qubit T gate.

\n", "signature": "(self, qubit: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.h", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.h", "kind": "function", "doc": "

Phase gadget implementation of single-qubit Hadamard gate.

\n", "signature": "(\tself,\tqubit: int,\tbasis: Literal['Z', 'X'] = 'Z',\tsign: Literal[1, -1] = 1) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cu1", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cu1", "kind": "function", "doc": "

Phase gadget implementation of CU1 gate.

\n", "signature": "(\tself,\tctrl: int,\ttgt: int,\tangle: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.crz", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.crz", "kind": "function", "doc": "

Phase gadget implementation of CRZ gate.

\n", "signature": "(\tself,\tctrl: int,\ttgt: int,\tangle: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cry", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cry", "kind": "function", "doc": "

Phase gadget implementation of CRY gate.

\n", "signature": "(\tself,\tctrl: int,\ttgt: int,\tangle: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.crx", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.crx", "kind": "function", "doc": "

Phase gadget implementation of CRX gate.

\n", "signature": "(\tself,\tctrl: int,\ttgt: int,\tangle: pauliopt.utils.Angle) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cz", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cz", "kind": "function", "doc": "

Phase gadget implementation of CZ gate.

\n", "signature": "(self, leg1: int, leg2: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cy", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cy", "kind": "function", "doc": "

Phase gadget implementation of CY gate.

\n", "signature": "(self, leg1: int, leg2: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cx", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cx", "kind": "function", "doc": "

Phase gadget implementation of CX gate.

\n", "signature": "(self, ctrl: int, tgt: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.u3", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.u3", "kind": "function", "doc": "

Phase gadget implementation of U3 gate.

\n", "signature": "(\tself,\tqubit: int,\ttheta: pauliopt.utils.AngleExpr,\tphi: pauliopt.utils.AngleExpr,\tlam: pauliopt.utils.AngleExpr) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.ccz", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.ccz", "kind": "function", "doc": "

Phase gadget implementation of CCZ gate.

\n", "signature": "(\tself,\tleg1: int,\tleg2: int,\tleg3: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.ccy", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.ccy", "kind": "function", "doc": "

Phase gadget implementation of CCX gate.

\n", "signature": "(\tself,\tleg1: int,\tleg2: int,\tleg3: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.ccx", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.ccx", "kind": "function", "doc": "

Phase gadget implementation of CCX gate.

\n", "signature": "(\tself,\tleg1: int,\tleg2: int,\tleg3: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.add_gadget", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.add_gadget", "kind": "function", "doc": "

Adds a phase gadget to the circuit.\nThis is rather less efficient than passing the gadgets in the constructor,\nbecause the internal numpy arrays have to be copied in the process.

\n\n

The circuit is modified in-place and then returned, as per the\nfluent interface pattern.

\n", "signature": "(\tself,\tgadget: pauliopt.phase.phase_circuits.PhaseGadget) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.copy", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.copy", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cx_count", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cx_count", "kind": "function", "doc": "

Returns the CX count for an implementation of this phase gadget\n on the given topology based on minimum spanning trees (MST).

\n\n
The optional `mapping` keyword argument can be used to specify a mapping of\nlogical (circuit) qubits to phyisical (topology) qubits.\n
\n\n

Args:\n topology (Topology): Target device topology\n mapping (Optional[Union[Sequence[int], Dict[int, int]]], optional): Used qubit mapping. Defaults to None.\n method (Literal[\"naive\", \"paritysynth\", \"steiner\", optional): Synthesis method. Defaults to \"naive\".

\n\n

Raises:\n TypeError: If topology is not a Topology and if mapping is not a permutation of range(self.num_qubits).

\n\n

Returns:\n int: The CX count.

\n", "signature": "(\tself,\ttopology: pauliopt.topologies.Topology,\t*,\tmapping: Union[Sequence[int], Dict[int, int], NoneType] = None,\tmethod: Literal['naive', 'paritysynth', 'steiner-graysynth'] = 'naive') -> int:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.mapped", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.mapped", "kind": "function", "doc": "

Returns a new phase circuit with the same gadgets but having\nqubits remapped according to the given mapping.

\n", "signature": "(\tself,\tmapping: Union[Sequence[int], Mapping[int, int]]) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.color_flip", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.color_flip", "kind": "function", "doc": "

Returns a new phase circuit with the same gadgets but having\nall basis switched from Z to X and vice versa.

\n", "signature": "(self) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.dagger", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.dagger", "kind": "function", "doc": "

Returns a new phase circuit with the same gadgets but having\nall angles negated.

\n", "signature": "(self) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.normalize", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.normalize", "kind": "function", "doc": "

Fuse and reorder gadgets of the same basis.

\n", "signature": "(self) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.to_qiskit", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.to_qiskit", "kind": "function", "doc": "

Generates a qiskit QuantumCircuit equivalent to this PhaseCircuit.

\n\n

Args:\n topology (Topology): Target device topology\n simplified (bool, optional): Simplifiy the PhaseCircuit before synthesis. Defaults to True.\n method (Literal[\"naive\", \"paritysynth\", \"steiner\", optional): Which method of synthesis should be used. Defaults to \"naive\".\n cx_synth (Literal[\"permrowcol\", \"naive\"], optional): Which method should be used for synthesizing the final CXCircuit. Defaults to \"naive\".\n return_cx (bool, optional): Whether to return the final CXCircuit separately without synthesizing it. Defaults to False.\n reallocate (bool, optional): Whether qubit reallocation is allowed when synthesizing the final CXCircuit. Defaults to False.

\n\n

Raises:\n ModuleNotFoundError: Requires Qiskit to be installed

\n\n

Returns:\n qiskit.QuantumCircuit: The synthesized equivalent circuit\n CXCircuit (optional): The final CNOTs of the circuit not yet concatinated to the qiskit circuit.

\n", "signature": "(\tself,\ttopology: pauliopt.topologies.Topology,\tsimplified: bool = True,\tmethod: Literal['naive', 'paritysynth', 'steiner-graysynth'] = 'naive',\tcx_synth: Literal['permrowcol', 'naive'] = 'naive',\treturn_cx: bool = False,\treallocate: bool = False) -> Any:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.to_svg", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.to_svg", "kind": "function", "doc": "

Returns an SVG representation of this circuit, using\nthe ZX calculus to express phase gadgets.

\n\n

The keyword arguments zcolor and xcolor can be used to\nspecify a colour for the Z and X basis spiders in the circuit.\nThe keyword arguments hscale and vscale can be used to\nscale the circuit representation horizontally and vertically.\nThe keyword argument scale can be used to scale the circuit\nrepresentation isotropically.\nThe keyword argument svg_code_only (default False) can be used\nto specify that the SVG code itself be returned, rather than the\nIPython SVG object.

\n", "signature": "(\tself,\t*,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\thscale: float = 1.0,\tvscale: float = 1.0,\tscale: float = 1.0,\tsvg_code_only: bool = False) -> Any:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.cloned", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.cloned", "kind": "function", "doc": "

Produces an exact copy of this phase circuit.

\n", "signature": "(self) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.conj_by_cx", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.conj_by_cx", "kind": "function", "doc": "

Conjugates this circuit by a CX gate with given control/target.\nThe circuit is modified in-place and then returned, as per the\nfluent interface pattern.

\n", "signature": "(self, ctrl: int, trgt: int) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.simplified", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.simplified", "kind": "function", "doc": "

Returns a new phase circuit which has been simplified using the\ncommutation and fusion rules for gadgets.

\n", "signature": "(self) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.random", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.random", "kind": "function", "doc": "

Generates a random circuit of mixed ZX phase gadgets on the given number of qubits,\nwith the given number of gadgets.

\n\n

The optional argument angle_subdivision (default: 4) can be used to specify the\ndenominator in the random fractional multiples of pi used as values for the angles.

\n\n

The optional arguments min_legs (default: 1, minimum: 1) and max_legs\n(default: None, minimum min_legs) can be used to specify the minimum and maximum\nnumber of legs for the phase gadgets. If None, max_legs is set to len(qubits).

\n\n

The optional argument rng_seed (default: None) is used as seed for the RNG.

\n", "signature": "(\tnum_qubits: int,\tnum_gadgets: int,\t*,\tparametric: Union[NoneType, str, Callable[[int], pauliopt.utils.AngleVar]] = None,\tangle_subdivision: int = 4,\tmin_legs: int = 1,\tmax_legs: Optional[int] = None,\tdiagonal: bool = False,\trng_seed: Optional[int] = None) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuit.from_qasm", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuit.from_qasm", "kind": "function", "doc": "

Constructs a phase circuit from a QASM program.

\n\n

An optional mapping from QASM qubits to circuit qubits can be supplied.

\n", "signature": "(\tqasm: Union[str, pauliopt.qasm.QASM],\t*,\tmapping: Union[Sequence[int], Mapping[int, int], NoneType] = None,\tallow_classical: bool = True) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView", "kind": "class", "doc": "

Readonly view on a phase circuit.

\n"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView.__init__", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView.__init__", "kind": "function", "doc": "

\n", "signature": "(circuit: pauliopt.phase.phase_circuits.PhaseCircuit)"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView.num_qubits", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView.num_qubits", "kind": "variable", "doc": "

Readonly property exposing the number of qubits spanned by the phase circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView.num_gadgets", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView.num_gadgets", "kind": "variable", "doc": "

Readonly property exposing the number of phase gadgets in the circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView.gadgets", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView.gadgets", "kind": "variable", "doc": "

Readonly property returning the sequence of phase gadgets in the\nphase circuit, in order from first to last.

\n\n

This collection is freshly generated at every call.

\n", "annotation": ": Sequence[pauliopt.phase.phase_circuits.PhaseGadget]"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView.to_svg", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView.to_svg", "kind": "function", "doc": "

Returns an SVG representation of this circuit, using\nthe ZX calculus to express phase gadgets.

\n\n

The keyword arguments zcolor and xcolor can be used to\nspecify a colour for the Z and X basis spiders in the circuit.\nThe keyword arguments hscale and vscale can be used to\nscale the circuit representation horizontally and vertically.\nThe keyword argument svg_code_only (default False) can be used\nto specify that the SVG code itself be returned, rather than the\nIPython SVG object.

\n", "signature": "(\tself,\t*,\tzcolor: str = '#CCFFCC',\txcolor: str = '#FF8888',\thscale: float = 1.0,\tvscale: float = 1.0,\tscale: float = 1.0,\tsvg_code_only: bool = False) -> Any:", "funcdef": "def"}, {"fullname": "pauliopt.phase.phase_circuits.PhaseCircuitView.cloned", "modulename": "pauliopt.phase.phase_circuits", "qualname": "PhaseCircuitView.cloned", "kind": "function", "doc": "

Produces an exact copy of the phase circuit.

\n", "signature": "(self) -> pauliopt.phase.phase_circuits.PhaseCircuit:", "funcdef": "def"}, {"fullname": "pauliopt.qasm", "modulename": "pauliopt.qasm", "kind": "module", "doc": "

QASM file parsing

\n"}, {"fullname": "pauliopt.qasm.assert_same_size_targets", "modulename": "pauliopt.qasm", "qualname": "assert_same_size_targets", "kind": "function", "doc": "

Asserts that all register targets have the same size.

\n", "signature": "(*trgts: pauliopt.qasm.QASM.RegTarget):", "funcdef": "def"}, {"fullname": "pauliopt.qasm.QASM", "modulename": "pauliopt.qasm", "qualname": "QASM", "kind": "class", "doc": "

QASM program.\nBased on the QASM spec from arXiv: 1707.03429

\n", "bases": "typing.Sequence[ForwardRef('QASM.Statement')]"}, {"fullname": "pauliopt.qasm.QASM.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.__init__", "kind": "function", "doc": "

\n", "signature": "(*statements: pauliopt.qasm.QASM.Statement)"}, {"fullname": "pauliopt.qasm.QASM.num_qubits", "modulename": "pauliopt.qasm", "qualname": "QASM.num_qubits", "kind": "variable", "doc": "

Number of qubits in this circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.qasm.QASM.num_bits", "modulename": "pauliopt.qasm", "qualname": "QASM.num_bits", "kind": "variable", "doc": "

Number of bits in this circuit.

\n", "annotation": ": int"}, {"fullname": "pauliopt.qasm.QASM.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.registers", "kind": "variable", "doc": "

Iterator over the registers of this QASM program.

\n", "annotation": ": Iterator[Union[pauliopt.qasm.QASM.QReg, pauliopt.qasm.QASM.CReg]]"}, {"fullname": "pauliopt.qasm.QASM.Statement", "modulename": "pauliopt.qasm", "qualname": "QASM.Statement", "kind": "class", "doc": "

QASM statement.

\n"}, {"fullname": "pauliopt.qasm.QASM.Statement.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Statement.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Statement.parse", "modulename": "pauliopt.qasm", "qualname": "QASM.Statement.parse", "kind": "function", "doc": "

Attempts to parse a QASM statement from a line of code.

\n", "signature": "(line: str) -> pauliopt.qasm.QASM.Statement:", "funcdef": "def"}, {"fullname": "pauliopt.qasm.QASM.Version", "modulename": "pauliopt.qasm", "qualname": "QASM.Version", "kind": "class", "doc": "

QASM version statement.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Version.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Version.__init__", "kind": "function", "doc": "

\n", "signature": "(version: str)"}, {"fullname": "pauliopt.qasm.QASM.Version.version", "modulename": "pauliopt.qasm", "qualname": "QASM.Version.version", "kind": "variable", "doc": "

QASM version.

\n", "annotation": ": str"}, {"fullname": "pauliopt.qasm.QASM.Reg", "modulename": "pauliopt.qasm", "qualname": "QASM.Reg", "kind": "class", "doc": "

Register.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Reg.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Reg.__init__", "kind": "function", "doc": "

\n", "signature": "(name: str, size: int)"}, {"fullname": "pauliopt.qasm.QASM.Reg.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Reg.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Reg.name", "modulename": "pauliopt.qasm", "qualname": "QASM.Reg.name", "kind": "variable", "doc": "

Register name.

\n"}, {"fullname": "pauliopt.qasm.QASM.Reg.size", "modulename": "pauliopt.qasm", "qualname": "QASM.Reg.size", "kind": "variable", "doc": "

Register size.

\n"}, {"fullname": "pauliopt.qasm.QASM.QReg", "modulename": "pauliopt.qasm", "qualname": "QASM.QReg", "kind": "class", "doc": "

Quantum register.

\n", "bases": "QASM.Reg"}, {"fullname": "pauliopt.qasm.QASM.QReg.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.QReg.__init__", "kind": "function", "doc": "

\n", "signature": "(name: str, size: int)"}, {"fullname": "pauliopt.qasm.QASM.CReg", "modulename": "pauliopt.qasm", "qualname": "QASM.CReg", "kind": "class", "doc": "

Classical register.

\n", "bases": "QASM.Reg"}, {"fullname": "pauliopt.qasm.QASM.CReg.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.CReg.__init__", "kind": "function", "doc": "

\n", "signature": "(name: str, size: int)"}, {"fullname": "pauliopt.qasm.QASM.Include", "modulename": "pauliopt.qasm", "qualname": "QASM.Include", "kind": "class", "doc": "

QASM include statement.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Include.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Include.__init__", "kind": "function", "doc": "

\n", "signature": "(filename: str)"}, {"fullname": "pauliopt.qasm.QASM.Include.filename", "modulename": "pauliopt.qasm", "qualname": "QASM.Include.filename", "kind": "variable", "doc": "

Filename.

\n", "annotation": ": str"}, {"fullname": "pauliopt.qasm.QASM.Comment", "modulename": "pauliopt.qasm", "qualname": "QASM.Comment", "kind": "class", "doc": "

QASM comment statement.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Comment.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Comment.__init__", "kind": "function", "doc": "

\n", "signature": "(text: str)"}, {"fullname": "pauliopt.qasm.QASM.Comment.text", "modulename": "pauliopt.qasm", "qualname": "QASM.Comment.text", "kind": "variable", "doc": "

Comment text.

\n", "annotation": ": str"}, {"fullname": "pauliopt.qasm.QASM.RegTarget", "modulename": "pauliopt.qasm", "qualname": "QASM.RegTarget", "kind": "class", "doc": "

A qreg or creg target.

\n"}, {"fullname": "pauliopt.qasm.QASM.RegTarget.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.RegTarget.__init__", "kind": "function", "doc": "

\n", "signature": "(\tregister: Union[pauliopt.qasm.QASM.QReg, pauliopt.qasm.QASM.CReg],\tpos: Optional[int] = None)"}, {"fullname": "pauliopt.qasm.QASM.RegTarget.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.RegTarget.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.RegTarget.register", "modulename": "pauliopt.qasm", "qualname": "QASM.RegTarget.register", "kind": "variable", "doc": "

Register.

\n", "annotation": ": Union[pauliopt.qasm.QASM.QReg, pauliopt.qasm.QASM.CReg]"}, {"fullname": "pauliopt.qasm.QASM.RegTarget.pos", "modulename": "pauliopt.qasm", "qualname": "QASM.RegTarget.pos", "kind": "variable", "doc": "

Optional register position.

\n", "annotation": ": Optional[int]"}, {"fullname": "pauliopt.qasm.QASM.RegTarget.size", "modulename": "pauliopt.qasm", "qualname": "QASM.RegTarget.size", "kind": "variable", "doc": "

Size of this target

\n"}, {"fullname": "pauliopt.qasm.QASM.QRegTarget", "modulename": "pauliopt.qasm", "qualname": "QASM.QRegTarget", "kind": "class", "doc": "

A qreg target.

\n", "bases": "QASM.RegTarget"}, {"fullname": "pauliopt.qasm.QASM.QRegTarget.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.QRegTarget.__init__", "kind": "function", "doc": "

\n", "signature": "(register: pauliopt.qasm.QASM.QReg, pos: Optional[int] = None)"}, {"fullname": "pauliopt.qasm.QASM.QRegTarget.register", "modulename": "pauliopt.qasm", "qualname": "QASM.QRegTarget.register", "kind": "variable", "doc": "

Register.

\n", "annotation": ": pauliopt.qasm.QASM.QReg"}, {"fullname": "pauliopt.qasm.QASM.CRegTarget", "modulename": "pauliopt.qasm", "qualname": "QASM.CRegTarget", "kind": "class", "doc": "

A creg target.

\n", "bases": "QASM.RegTarget"}, {"fullname": "pauliopt.qasm.QASM.CRegTarget.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.CRegTarget.__init__", "kind": "function", "doc": "

\n", "signature": "(register: pauliopt.qasm.QASM.CReg, pos: Optional[int] = None)"}, {"fullname": "pauliopt.qasm.QASM.CRegTarget.register", "modulename": "pauliopt.qasm", "qualname": "QASM.CRegTarget.register", "kind": "variable", "doc": "

Register.

\n", "annotation": ": pauliopt.qasm.QASM.CReg"}, {"fullname": "pauliopt.qasm.QASM.UGate", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate", "kind": "class", "doc": "

Statement for a U3 gate.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.UGate.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate.__init__", "kind": "function", "doc": "

\n", "signature": "(\ttheta: pauliopt.utils.Angle,\tphi: pauliopt.utils.Angle,\tlam: pauliopt.utils.Angle,\tqubit: pauliopt.qasm.QASM.QRegTarget)"}, {"fullname": "pauliopt.qasm.QASM.UGate.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.UGate.theta", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate.theta", "kind": "variable", "doc": "

Theta angle for the U3 gate.

\n", "annotation": ": pauliopt.utils.Angle"}, {"fullname": "pauliopt.qasm.QASM.UGate.phi", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate.phi", "kind": "variable", "doc": "

Phi angle for the U3 gate.

\n", "annotation": ": pauliopt.utils.Angle"}, {"fullname": "pauliopt.qasm.QASM.UGate.lam", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate.lam", "kind": "variable", "doc": "

Lambda angle for the U3 gate.

\n", "annotation": ": pauliopt.utils.Angle"}, {"fullname": "pauliopt.qasm.QASM.UGate.qubit", "modulename": "pauliopt.qasm", "qualname": "QASM.UGate.qubit", "kind": "variable", "doc": "

Qubit/qreg for the U3 gate.

\n", "annotation": ": pauliopt.qasm.QASM.QRegTarget"}, {"fullname": "pauliopt.qasm.QASM.CXGate", "modulename": "pauliopt.qasm", "qualname": "QASM.CXGate", "kind": "class", "doc": "

Statement for a CX gate.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.CXGate.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.CXGate.__init__", "kind": "function", "doc": "

\n", "signature": "(\tcontrol: pauliopt.qasm.QASM.QRegTarget,\ttarget: pauliopt.qasm.QASM.QRegTarget)"}, {"fullname": "pauliopt.qasm.QASM.CXGate.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.CXGate.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.CXGate.control", "modulename": "pauliopt.qasm", "qualname": "QASM.CXGate.control", "kind": "variable", "doc": "

Control qubit/qreg for the CX gate.

\n", "annotation": ": pauliopt.qasm.QASM.QRegTarget"}, {"fullname": "pauliopt.qasm.QASM.CXGate.target", "modulename": "pauliopt.qasm", "qualname": "QASM.CXGate.target", "kind": "variable", "doc": "

Target qubit/qreg for the CX gate.

\n", "annotation": ": pauliopt.qasm.QASM.QRegTarget"}, {"fullname": "pauliopt.qasm.QASM.Measure", "modulename": "pauliopt.qasm", "qualname": "QASM.Measure", "kind": "class", "doc": "

Statement for a measurement.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Measure.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Measure.__init__", "kind": "function", "doc": "

\n", "signature": "(\tqubit: pauliopt.qasm.QASM.QRegTarget,\tbit: pauliopt.qasm.QASM.CRegTarget)"}, {"fullname": "pauliopt.qasm.QASM.Measure.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Measure.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Measure.qubit", "modulename": "pauliopt.qasm", "qualname": "QASM.Measure.qubit", "kind": "variable", "doc": "

Qubit/qreg to be measured.

\n", "annotation": ": pauliopt.qasm.QASM.QRegTarget"}, {"fullname": "pauliopt.qasm.QASM.Measure.bit", "modulename": "pauliopt.qasm", "qualname": "QASM.Measure.bit", "kind": "variable", "doc": "

Bit/creg to store measurement outcome.

\n", "annotation": ": pauliopt.qasm.QASM.CRegTarget"}, {"fullname": "pauliopt.qasm.QASM.Reset", "modulename": "pauliopt.qasm", "qualname": "QASM.Reset", "kind": "class", "doc": "

Statement for a reset.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Reset.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Reset.__init__", "kind": "function", "doc": "

\n", "signature": "(qubit: pauliopt.qasm.QASM.QRegTarget)"}, {"fullname": "pauliopt.qasm.QASM.Reset.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Reset.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Reset.qubit", "modulename": "pauliopt.qasm", "qualname": "QASM.Reset.qubit", "kind": "variable", "doc": "

Qubit/qreg to be measured.

\n", "annotation": ": pauliopt.qasm.QASM.QRegTarget"}, {"fullname": "pauliopt.qasm.QASM.Gate", "modulename": "pauliopt.qasm", "qualname": "QASM.Gate", "kind": "class", "doc": "

Statement for a named gate.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Gate.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Gate.__init__", "kind": "function", "doc": "

\n", "signature": "(\tname: str,\ttargets: Sequence[pauliopt.qasm.QASM.RegTarget],\tparams: Sequence[pauliopt.utils.Angle] = ())"}, {"fullname": "pauliopt.qasm.QASM.Gate.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Gate.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Gate.name", "modulename": "pauliopt.qasm", "qualname": "QASM.Gate.name", "kind": "variable", "doc": "

Name for this gate.

\n", "annotation": ": str"}, {"fullname": "pauliopt.qasm.QASM.Gate.params", "modulename": "pauliopt.qasm", "qualname": "QASM.Gate.params", "kind": "variable", "doc": "

Tuple of angle parameters for this gate.

\n", "annotation": ": Tuple[pauliopt.utils.Angle, ...]"}, {"fullname": "pauliopt.qasm.QASM.Gate.targets", "modulename": "pauliopt.qasm", "qualname": "QASM.Gate.targets", "kind": "variable", "doc": "

Tuple of register targets for this gate.

\n", "annotation": ": Tuple[pauliopt.qasm.QASM.RegTarget, ...]"}, {"fullname": "pauliopt.qasm.QASM.Barrier", "modulename": "pauliopt.qasm", "qualname": "QASM.Barrier", "kind": "class", "doc": "

Statement for a barrier.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Barrier.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Barrier.__init__", "kind": "function", "doc": "

\n", "signature": "(targets: Sequence[pauliopt.qasm.QASM.QRegTarget])"}, {"fullname": "pauliopt.qasm.QASM.Barrier.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Barrier.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Barrier.targets", "modulename": "pauliopt.qasm", "qualname": "QASM.Barrier.targets", "kind": "variable", "doc": "

Tuple of register targets for this barrier.

\n", "annotation": ": Tuple[pauliopt.qasm.QASM.RegTarget, ...]"}, {"fullname": "pauliopt.qasm.QASM.Conditional", "modulename": "pauliopt.qasm", "qualname": "QASM.Conditional", "kind": "class", "doc": "

Statement for a conditional statement.

\n", "bases": "QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.Conditional.__init__", "modulename": "pauliopt.qasm", "qualname": "QASM.Conditional.__init__", "kind": "function", "doc": "

\n", "signature": "(\tregister: pauliopt.qasm.QASM.CReg,\tvalue: int,\tstatement: pauliopt.qasm.QASM.Statement)"}, {"fullname": "pauliopt.qasm.QASM.Conditional.registers", "modulename": "pauliopt.qasm", "qualname": "QASM.Conditional.registers", "kind": "variable", "doc": "

List of registers involved in this statement.

\n", "annotation": ": Sequence[pauliopt.qasm.QASM.Reg]"}, {"fullname": "pauliopt.qasm.QASM.Conditional.register", "modulename": "pauliopt.qasm", "qualname": "QASM.Conditional.register", "kind": "variable", "doc": "

The register being tested in this conditional statement.

\n", "annotation": ": pauliopt.qasm.QASM.CReg"}, {"fullname": "pauliopt.qasm.QASM.Conditional.value", "modulename": "pauliopt.qasm", "qualname": "QASM.Conditional.value", "kind": "variable", "doc": "

The register value being tested in this conditional statement.

\n", "annotation": ": int"}, {"fullname": "pauliopt.qasm.QASM.Conditional.statement", "modulename": "pauliopt.qasm", "qualname": "QASM.Conditional.statement", "kind": "variable", "doc": "

The statement to execute if the given creg has the given value.

\n", "annotation": ": pauliopt.qasm.QASM.Statement"}, {"fullname": "pauliopt.qasm.QASM.parse", "modulename": "pauliopt.qasm", "qualname": "QASM.parse", "kind": "function", "doc": "

Parses a QASM program into a QASM object.

\n", "signature": "(program: str):", "funcdef": "def"}, {"fullname": "pauliopt.topologies", "modulename": "pauliopt.topologies", "kind": "module", "doc": "

This module contains utility code to deal with qubit topologies.

\n"}, {"fullname": "pauliopt.topologies.Coupling", "modulename": "pauliopt.topologies", "qualname": "Coupling", "kind": "class", "doc": "

Type for couplings in a qubit topology, i.e. unordered\npairs of adjacent qubits.

\n", "bases": "typing.FrozenSet[int]"}, {"fullname": "pauliopt.topologies.Coupling.as_pair", "modulename": "pauliopt.topologies", "qualname": "Coupling.as_pair", "kind": "variable", "doc": "

Returns the coupling as a (increasingly) ordered pair.

\n", "annotation": ": Tuple[int, int]"}, {"fullname": "pauliopt.topologies.CouplingLike", "modulename": "pauliopt.topologies", "qualname": "CouplingLike", "kind": "variable", "doc": "

Type alias for things that could be used to specify couplings,\nnamely any collection of int (subject to additional restrictions).

\n\n

In an ideal world, this should be \"int collections of len 2\",\nbut static typing does not yet allow for such a constraint.

\n", "default_value": "typing.Collection[int]"}, {"fullname": "pauliopt.topologies.TopologyDict", "modulename": "pauliopt.topologies", "qualname": "TopologyDict", "kind": "class", "doc": "

The type of the dictionary returned by Topology.as_dict,\nsuitable for JSON serialization.

\n", "bases": "typing.TypedDict"}, {"fullname": "pauliopt.topologies.TopologyDict.num_qubits", "modulename": "pauliopt.topologies", "qualname": "TopologyDict.num_qubits", "kind": "variable", "doc": "

Property exposing the number of qubits in the topology.

\n", "annotation": ": int"}, {"fullname": "pauliopt.topologies.TopologyDict.couplings", "modulename": "pauliopt.topologies", "qualname": "TopologyDict.couplings", "kind": "variable", "doc": "

Property exposing the couplings between qubits in the topology.

\n", "annotation": ": List[List[int]]"}, {"fullname": "pauliopt.topologies.Layouts", "modulename": "pauliopt.topologies", "qualname": "Layouts", "kind": "variable", "doc": "

Possible layout values for Topology.draw

\n", "annotation": ": Final[Tuple[str, ...]]", "default_value": "('circular', 'kamada_kawai', 'random', 'shell', 'spring', 'spectral', 'spiral')"}, {"fullname": "pauliopt.topologies.Topology", "modulename": "pauliopt.topologies", "qualname": "Topology", "kind": "class", "doc": "

Container class for a qubit topology.

\n"}, {"fullname": "pauliopt.topologies.Topology.__init__", "modulename": "pauliopt.topologies", "qualname": "Topology.__init__", "kind": "function", "doc": "

\n", "signature": "(num_qubits: int, couplings: Collection[Collection[int]])"}, {"fullname": "pauliopt.topologies.Topology.num_qubits", "modulename": "pauliopt.topologies", "qualname": "Topology.num_qubits", "kind": "variable", "doc": "

Readonly property returning the number of qubits in this topology.

\n", "annotation": ": int"}, {"fullname": "pauliopt.topologies.Topology.qubits", "modulename": "pauliopt.topologies", "qualname": "Topology.qubits", "kind": "variable", "doc": "

Readonly property returning the range of qubits in this topology.

\n", "annotation": ": range"}, {"fullname": "pauliopt.topologies.Topology.couplings", "modulename": "pauliopt.topologies", "qualname": "Topology.couplings", "kind": "variable", "doc": "

Readonly property exposing the couplings between qubits in this topology.

\n", "annotation": ": FrozenSet[pauliopt.topologies.Coupling]"}, {"fullname": "pauliopt.topologies.Topology.as_dict", "modulename": "pauliopt.topologies", "qualname": "Topology.as_dict", "kind": "variable", "doc": "

Readonly property returning this topology as\na dictionary, for serialization purposes.

\n", "annotation": ": Union[str, pauliopt.topologies.TopologyDict]"}, {"fullname": "pauliopt.topologies.Topology.is_planar", "modulename": "pauliopt.topologies", "qualname": "Topology.is_planar", "kind": "variable", "doc": "

Whether this qubit topology is a planar graph.

\n", "annotation": ": bool"}, {"fullname": "pauliopt.topologies.Topology.available_nx_layouts", "modulename": "pauliopt.topologies", "qualname": "Topology.available_nx_layouts", "kind": "variable", "doc": "

Readonly property returning the available layouts for this qubit topology.

\n", "annotation": ": Tuple[str, ...]"}, {"fullname": "pauliopt.topologies.Topology.to_nx", "modulename": "pauliopt.topologies", "qualname": "Topology.to_nx", "kind": "variable", "doc": "

Readonly property returning a NetworkX graph version of this topology.\nRequires the 'networkx' library to work.

\n"}, {"fullname": "pauliopt.topologies.Topology.draw", "modulename": "pauliopt.topologies", "qualname": "Topology.draw", "kind": "function", "doc": "

Draws this qubit topology using NetworkX and Matplotlib.

\n\n

The layout keyword argument can be used to select a NetworkX layout\nfrom the available ones (exposed by Topology.available_nx_layouts).\nThe figsize keyword argument is passed to matplotlib.pyplot.figure:\nif specified, it determines the width and height of the figure being drawn.\nKeyword arguments kwargs are those of networkx.draw_networkx.\nIf the keyword argument filename is set, the figure is also saved.

\n", "signature": "(\tself,\tlayout: str = 'kamada_kawai',\t*,\tfigsize: Optional[Tuple[int, int]] = None,\tfilename: Optional[str] = None,\t**kwargs):", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.adjacent", "modulename": "pauliopt.topologies", "qualname": "Topology.adjacent", "kind": "function", "doc": "

Readonly property exposing the (frozen) set of qubits adjacent\nto (i.e. couple with) the given qubit.

\n", "signature": "(self, qubit: int) -> FrozenSet[int]:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.incident", "modulename": "pauliopt.topologies", "qualname": "Topology.incident", "kind": "function", "doc": "

Readonly property returning an iterator running over all couplings\nincident onto the given qubit.

\n\n

This is returned as an iterator, rather than a collection,\nbecause the couplings are generated on the fly (i.e. this is not\nmerely exposing some internal collection).

\n", "signature": "(self, qubit: int) -> Iterator[pauliopt.topologies.Coupling]:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.dist", "modulename": "pauliopt.topologies", "qualname": "Topology.dist", "kind": "function", "doc": "

Returns the distance between two given qubits in the topology.

\n", "signature": "(self, fro: int, to: int) -> int:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.mapped_fwd", "modulename": "pauliopt.topologies", "qualname": "Topology.mapped_fwd", "kind": "function", "doc": "

Returns a topology with the same couplings, but remapping the qubits using\nthe given mapping.

\n", "signature": "(\tself,\tmapping: Union[Sequence[int], Dict[int, int]]) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.shortest_path", "modulename": "pauliopt.topologies", "qualname": "Topology.shortest_path", "kind": "function", "doc": "

Computes the shortest path using the next lookup table from the Floyd\u2013Warshall algorithm

\n", "signature": "(self, fro: int, to: int):", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.steiner_tree", "modulename": "pauliopt.topologies", "qualname": "Topology.steiner_tree", "kind": "function", "doc": "

Computes the Steiner tree over the topology with given terminals.\nsubgraph can be used to find the Steiner tree of a subgraph of the topology.\nRequires networkx to be installed to work.\nReturns a networkx Graph.

\n", "signature": "(self, terminals: list[int], subgraph: list[int] = []):", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.non_cutting_qubits", "modulename": "pauliopt.topologies", "qualname": "Topology.non_cutting_qubits", "kind": "function", "doc": "

\n", "signature": "(self, subgraph: List[int] = []) -> List[int]:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.mapped_bwd", "modulename": "pauliopt.topologies", "qualname": "Topology.mapped_bwd", "kind": "function", "doc": "

Returns a topology with the same couplings, but remapping the qubits using\nthe inverse of the given mapping.

\n", "signature": "(\tself,\tmapping: Union[Sequence[int], Dict[int, int]]) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.from_dict", "modulename": "pauliopt.topologies", "qualname": "Topology.from_dict", "kind": "function", "doc": "

Creates a Topology instance from a dictionary in the\nformat obtained from Topology.as_dict,\nfor de-serialization purposes.

\n", "signature": "(\ttopology: Union[pauliopt.topologies.TopologyDict, str]) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.line", "modulename": "pauliopt.topologies", "qualname": "Topology.line", "kind": "function", "doc": "

Creates a line topology on the given number of qubits.

\n", "signature": "(num_qubits: int) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.cycle", "modulename": "pauliopt.topologies", "qualname": "Topology.cycle", "kind": "function", "doc": "

Creates a cycle topology on the given number of qubits.

\n", "signature": "(num_qubits: int) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.complete", "modulename": "pauliopt.topologies", "qualname": "Topology.complete", "kind": "function", "doc": "

Creates a complete topology on the given number of qubits.

\n", "signature": "(num_qubits: int) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.grid", "modulename": "pauliopt.topologies", "qualname": "Topology.grid", "kind": "function", "doc": "

Creates a grid topology with the given number of rows and cols.\nQubits are indexed by rows.

\n", "signature": "(num_rows: int, num_cols: int) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.periodic_grid", "modulename": "pauliopt.topologies", "qualname": "Topology.periodic_grid", "kind": "function", "doc": "

Creates a periodic grid topology with the given number of rows and cols.\nQubits are indexed by rows.

\n", "signature": "(num_rows: int, num_cols: int) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.from_qiskit_config", "modulename": "pauliopt.topologies", "qualname": "Topology.from_qiskit_config", "kind": "function", "doc": "

Static method to construct the topology from a\nQiskit backend configuration.

\n\n

This method relies on the qiskit library being available.\nSpecifically, the config argument must be of type\nqiskit.providers.models.QasmBackendConfiguration.

\n", "signature": "(config) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Topology.from_qiskit_backend", "modulename": "pauliopt.topologies", "qualname": "Topology.from_qiskit_backend", "kind": "function", "doc": "

Static method to construct the topology from a Qiskit backend.

\n\n

This method relies on the qiskit library being available.\nSpecifically, the backend argument must be of type\nqiskit.providers.Backend.

\n", "signature": "(backend) -> pauliopt.topologies.Topology:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Matching", "modulename": "pauliopt.topologies", "qualname": "Matching", "kind": "class", "doc": "

Mutable container class for a matching on a qubit topology.

\n"}, {"fullname": "pauliopt.topologies.Matching.__init__", "modulename": "pauliopt.topologies", "qualname": "Matching.__init__", "kind": "function", "doc": "

\n", "signature": "(topology: pauliopt.topologies.Topology)"}, {"fullname": "pauliopt.topologies.Matching.topology", "modulename": "pauliopt.topologies", "qualname": "Matching.topology", "kind": "variable", "doc": "

Readonly property exposing the qubit topology\nunderlying this matching.

\n", "annotation": ": pauliopt.topologies.Topology"}, {"fullname": "pauliopt.topologies.Matching.matched_couplings", "modulename": "pauliopt.topologies", "qualname": "Matching.matched_couplings", "kind": "variable", "doc": "

Readonly property returning the collection of couplings\ncurrently in this matching.

\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[pauliopt.topologies.Coupling]"}, {"fullname": "pauliopt.topologies.Matching.matched_qubits", "modulename": "pauliopt.topologies", "qualname": "Matching.matched_qubits", "kind": "variable", "doc": "

Readonly property returning the collection of qubits\ncurrently matched in this matching.

\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[int]"}, {"fullname": "pauliopt.topologies.Matching.flippable_couplings", "modulename": "pauliopt.topologies", "qualname": "Matching.flippable_couplings", "kind": "variable", "doc": "

Readonly property returning the collection of couplings\nthat can be currently flipped in this matching, namely:

\n\n
    \n
  • all couplings currently in the matching (will be removed by flip);
  • \n
  • all couplings with both qubits currently not matched by the matching\n(will be added by flip).
  • \n
\n\n

This collection is freshly generated at every call.

\n", "annotation": ": FrozenSet[pauliopt.topologies.Coupling]"}, {"fullname": "pauliopt.topologies.Matching.incident", "modulename": "pauliopt.topologies", "qualname": "Matching.incident", "kind": "function", "doc": "

Returns the coupling incident to the given qubit in this matching,\nor None if the qubit is not matched.

\n", "signature": "(self, qubit: int) -> Optional[pauliopt.topologies.Coupling]:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Matching.is_flippable", "modulename": "pauliopt.topologies", "qualname": "Matching.is_flippable", "kind": "function", "doc": "

Checks whether the coupling can be flipped:

\n\n
    \n
  • always true if the coupling is already present in the matching;
  • \n
  • otherwise true only if neither qubit in the coupling is currently matched.
  • \n
\n", "signature": "(self, coupling: Collection[int]) -> bool:", "funcdef": "def"}, {"fullname": "pauliopt.topologies.Matching.flip", "modulename": "pauliopt.topologies", "qualname": "Matching.flip", "kind": "function", "doc": "

Flips the given coupling in the matching (removes it if it is already present,\nadds it if it is not yed present and can be added).\nRaises ValueError if the coupling is not flippable.

\n\n

The matching is modified in-place and then returned, as per the\nfluent API pattern.

\n", "signature": "(self, coupling: Collection[int]) -> pauliopt.topologies.Matching:", "funcdef": "def"}, {"fullname": "pauliopt.utils", "modulename": "pauliopt.utils", "kind": "module", "doc": "

Utility classes and functions for the pauliopt library.

\n"}, {"fullname": "pauliopt.utils.calculate_orthogonal_point", "modulename": "pauliopt.utils", "qualname": "calculate_orthogonal_point", "kind": "function", "doc": "

\n", "signature": "(a, b, d, left):", "funcdef": "def"}, {"fullname": "pauliopt.utils.AngleInitT", "modulename": "pauliopt.utils", "qualname": "AngleInitT", "kind": "variable", "doc": "

\n", "default_value": "typing.Union[int, fractions.Fraction, str, decimal.Decimal]"}, {"fullname": "pauliopt.utils.AngleExpr", "modulename": "pauliopt.utils", "qualname": "AngleExpr", "kind": "class", "doc": "

A container class for angle expressions.

\n", "bases": "abc.ABC"}, {"fullname": "pauliopt.utils.AngleExpr.repr_latex", "modulename": "pauliopt.utils", "qualname": "AngleExpr.repr_latex", "kind": "variable", "doc": "

LaTeX math mode representation of this number.

\n", "annotation": ": str"}, {"fullname": "pauliopt.utils.AngleExpr.to_qiskit", "modulename": "pauliopt.utils", "qualname": "AngleExpr.to_qiskit", "kind": "variable", "doc": "

\n", "annotation": ": Any"}, {"fullname": "pauliopt.utils.AngleExpr.is_zero", "modulename": "pauliopt.utils", "qualname": "AngleExpr.is_zero", "kind": "variable", "doc": "

\n", "annotation": ": bool"}, {"fullname": "pauliopt.utils.AngleExpr.is_pi", "modulename": "pauliopt.utils", "qualname": "AngleExpr.is_pi", "kind": "variable", "doc": "

\n", "annotation": ": bool"}, {"fullname": "pauliopt.utils.AngleExpr.is_zero_or_pi", "modulename": "pauliopt.utils", "qualname": "AngleExpr.is_zero_or_pi", "kind": "variable", "doc": "

\n", "annotation": ": bool"}, {"fullname": "pauliopt.utils.Angle", "modulename": "pauliopt.utils", "qualname": "Angle", "kind": "class", "doc": "

A container class for angles,\nas rational multiples of PI modulo 2PI.

\n", "bases": "AngleExpr"}, {"fullname": "pauliopt.utils.Angle.__init__", "modulename": "pauliopt.utils", "qualname": "Angle.__init__", "kind": "function", "doc": "

\n", "signature": "(\ttheta: Union[pauliopt.utils.Angle, int, fractions.Fraction, str, decimal.Decimal])"}, {"fullname": "pauliopt.utils.Angle.value", "modulename": "pauliopt.utils", "qualname": "Angle.value", "kind": "variable", "doc": "

The value of this angle as a fraction of PI.

\n", "annotation": ": fractions.Fraction"}, {"fullname": "pauliopt.utils.Angle.as_root_of_unity", "modulename": "pauliopt.utils", "qualname": "Angle.as_root_of_unity", "kind": "variable", "doc": "

Returns (a,n) where n is the smallest such\nthat this angle is an $n$-th root of unity\nand 0 <= a < n such that this is $e^{i 2\\pi \\frac{a}{n}}$

\n", "annotation": ": Tuple[int, int]"}, {"fullname": "pauliopt.utils.Angle.order", "modulename": "pauliopt.utils", "qualname": "Angle.order", "kind": "variable", "doc": "

The order of this angle as a root of unity.

\n", "annotation": ": int"}, {"fullname": "pauliopt.utils.Angle.is_zero_or_pi", "modulename": "pauliopt.utils", "qualname": "Angle.is_zero_or_pi", "kind": "variable", "doc": "

Whether this angle is a multiple of pi.

\n", "annotation": ": bool"}, {"fullname": "pauliopt.utils.Angle.is_zero", "modulename": "pauliopt.utils", "qualname": "Angle.is_zero", "kind": "variable", "doc": "

Whether this angle is a multiple of 2pi.

\n", "annotation": ": bool"}, {"fullname": "pauliopt.utils.Angle.is_pi", "modulename": "pauliopt.utils", "qualname": "Angle.is_pi", "kind": "variable", "doc": "

Whether this angle is an odd multiple of pi.

\n", "annotation": ": bool"}, {"fullname": "pauliopt.utils.Angle.to_qiskit", "modulename": "pauliopt.utils", "qualname": "Angle.to_qiskit", "kind": "variable", "doc": "

\n", "annotation": ": float"}, {"fullname": "pauliopt.utils.Angle.repr_latex", "modulename": "pauliopt.utils", "qualname": "Angle.repr_latex", "kind": "variable", "doc": "

LaTeX math mode representation of this number.

\n", "annotation": ": str"}, {"fullname": "pauliopt.utils.Angle.random", "modulename": "pauliopt.utils", "qualname": "Angle.random", "kind": "function", "doc": "

Generates a random angle with the given subdivision:\nr * pi/subdivision for random r in range(2*subdivision).

\n", "signature": "(\tsubdivision: int = 4,\t*,\tsize: int = 1,\trng_seed: Optional[int] = None,\tnonzero: bool = False) -> Union[pauliopt.utils.Angle, Tuple[pauliopt.utils.Angle, ...]]:", "funcdef": "def"}, {"fullname": "pauliopt.utils.Angle.zero", "modulename": "pauliopt.utils", "qualname": "Angle.zero", "kind": "variable", "doc": "

A constant for the angle 0.

\n", "annotation": ": Final[pauliopt.utils.Angle]", "default_value": "0"}, {"fullname": "pauliopt.utils.Angle.pi", "modulename": "pauliopt.utils", "qualname": "Angle.pi", "kind": "variable", "doc": "

A constant for the angle pi.

\n", "annotation": ": Final[pauliopt.utils.Angle]", "default_value": "pi"}, {"fullname": "pauliopt.utils.pi", "modulename": "pauliopt.utils", "qualname": "pi", "kind": "variable", "doc": "

Constant for Angle.pi.

\n", "annotation": ": Final[pauliopt.utils.Angle]", "default_value": "pi"}, {"fullname": "pauliopt.utils.\u03c0", "modulename": "pauliopt.utils", "qualname": "\u03c0", "kind": "variable", "doc": "

Constant for Angle.pi.

\n", "annotation": ": Final[pauliopt.utils.Angle]", "default_value": "pi"}, {"fullname": "pauliopt.utils.SumprodAngleExpr", "modulename": "pauliopt.utils", "qualname": "SumprodAngleExpr", "kind": "function", "doc": "

\n", "signature": "(\t*exprs: pauliopt.utils.AngleExpr,\tcoeffs: Union[int, fractions.Fraction, Sequence[Union[int, fractions.Fraction]]] = 1) -> pauliopt.utils.AngleExpr:", "funcdef": "def"}, {"fullname": "pauliopt.utils.ModAngleExpr", "modulename": "pauliopt.utils", "qualname": "ModAngleExpr", "kind": "function", "doc": "

\n", "signature": "(\texpr: pauliopt.utils.AngleExpr,\tmod: pauliopt.utils.AngleExpr) -> pauliopt.utils.AngleExpr:", "funcdef": "def"}, {"fullname": "pauliopt.utils.AngleVar", "modulename": "pauliopt.utils", "qualname": "AngleVar", "kind": "class", "doc": "

A container class for angle expressions.

\n", "bases": "AngleExpr"}, {"fullname": "pauliopt.utils.AngleVar.__init__", "modulename": "pauliopt.utils", "qualname": "AngleVar.__init__", "kind": "function", "doc": "

\n", "signature": "(label: str, latex_label: Optional[str] = None)"}, {"fullname": "pauliopt.utils.AngleVar.to_qiskit", "modulename": "pauliopt.utils", "qualname": "AngleVar.to_qiskit", "kind": "variable", "doc": "

\n", "annotation": ": Any"}, {"fullname": "pauliopt.utils.AngleVar.repr_latex", "modulename": "pauliopt.utils", "qualname": "AngleVar.repr_latex", "kind": "variable", "doc": "

LaTeX math mode representation of this number.

\n", "annotation": ": str"}, {"fullname": "pauliopt.utils.SVGBuilder", "modulename": "pauliopt.utils", "qualname": "SVGBuilder", "kind": "class", "doc": "

Utility class for building certain SVG images.\nFollows the Fluent interface pattern.

\n"}, {"fullname": "pauliopt.utils.SVGBuilder.__init__", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.__init__", "kind": "function", "doc": "

\n", "signature": "(width: int, height: int)"}, {"fullname": "pauliopt.utils.SVGBuilder.width", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.width", "kind": "variable", "doc": "

The figure width.

\n", "annotation": ": int"}, {"fullname": "pauliopt.utils.SVGBuilder.height", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.height", "kind": "variable", "doc": "

The figure height.

\n", "annotation": ": int"}, {"fullname": "pauliopt.utils.SVGBuilder.tags", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.tags", "kind": "variable", "doc": "

The current sequence of tags.

\n", "annotation": ": Sequence[str]"}, {"fullname": "pauliopt.utils.SVGBuilder.line", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.line", "kind": "function", "doc": "

Draws a line from given coordinates to given coordinates.

\n", "signature": "(\tself,\tfro: Tuple[int, int],\tto: Tuple[int, int]) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.line_bend", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.line_bend", "kind": "function", "doc": "

\n", "signature": "(\tself,\tfro: Tuple[int, int],\tto: Tuple[int, int],\tleft=False,\tdegree=5):", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.add_diagonal_fill", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.add_diagonal_fill", "kind": "function", "doc": "

\n", "signature": "(self, color_1: str, color_2: str, id: str) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.square", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.square", "kind": "function", "doc": "

\n", "signature": "(\tself,\tcentre: Tuple[int, int],\twidth: int,\theight: int,\tfill) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.text_with_square", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.text_with_square", "kind": "function", "doc": "

\n", "signature": "(\tself,\tcentre: Tuple[int, int],\twidth: int,\theight: int,\ttext: str) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.circle", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.circle", "kind": "function", "doc": "

Draws a circle with given centre and radius.

\n", "signature": "(\tself,\tcentre: Tuple[int, int],\tr: int,\tfill: str) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.rect", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.rect", "kind": "function", "doc": "

Draws a rectangle with given centre, width and height.

\n", "signature": "(\tself,\tcentre: Tuple[int, int],\twidth: int,\theight: int,\tfill: str) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.SVGBuilder.text", "modulename": "pauliopt.utils", "qualname": "SVGBuilder.text", "kind": "function", "doc": "

Draws text at the given position (stroke/fill not used).

\n", "signature": "(\tself,\tpos: Tuple[int, int],\ttext: str,\t*,\tfont_size: int = 10,\tcenter=False) -> pauliopt.utils.SVGBuilder:", "funcdef": "def"}, {"fullname": "pauliopt.utils.TempSchedule", "modulename": "pauliopt.utils", "qualname": "TempSchedule", "kind": "class", "doc": "

Protocol for a temperature schedule.\nThe temperature is a number (int or float) computed from the iteration\nnumber it (starting from 0) and the total number of iterations num_iter\n(passed as a keyword argument).

\n", "bases": "typing.Protocol"}, {"fullname": "pauliopt.utils.TempSchedule.__init__", "modulename": "pauliopt.utils", "qualname": "TempSchedule.__init__", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs)"}, {"fullname": "pauliopt.utils.TempScheduleProvider", "modulename": "pauliopt.utils", "qualname": "TempScheduleProvider", "kind": "class", "doc": "

Protocol for a function constructing a temperature schedule\nfrom an initial and final temperatures.

\n", "bases": "typing.Protocol"}, {"fullname": "pauliopt.utils.TempScheduleProvider.__init__", "modulename": "pauliopt.utils", "qualname": "TempScheduleProvider.__init__", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs)"}, {"fullname": "pauliopt.utils.linear_temp_schedule", "modulename": "pauliopt.utils", "qualname": "linear_temp_schedule", "kind": "function", "doc": "

Returns a straight/linear temperature schedule for given initial and final temperatures,\nfrom https://link.springer.com/article/10.1007/BF00143921

\n", "signature": "(\tt_init: Union[int, float],\tt_final: Union[int, float]) -> pauliopt.utils.TempSchedule:", "funcdef": "def"}, {"fullname": "pauliopt.utils.geometric_temp_schedule", "modulename": "pauliopt.utils", "qualname": "geometric_temp_schedule", "kind": "function", "doc": "

Returns a geometric temperature schedule for given initial and final temperatures,\nfrom https://link.springer.com/article/10.1007/BF00143921

\n", "signature": "(\tt_init: Union[int, float],\tt_final: Union[int, float]) -> pauliopt.utils.TempSchedule:", "funcdef": "def"}, {"fullname": "pauliopt.utils.reciprocal_temp_schedule", "modulename": "pauliopt.utils", "qualname": "reciprocal_temp_schedule", "kind": "function", "doc": "

Returns a reciprocal temperature schedule for given initial and final temperatures,\nfrom https://link.springer.com/article/10.1007/BF00143921

\n", "signature": "(\tt_init: Union[int, float],\tt_final: Union[int, float]) -> pauliopt.utils.TempSchedule:", "funcdef": "def"}, {"fullname": "pauliopt.utils.log_temp_schedule", "modulename": "pauliopt.utils", "qualname": "log_temp_schedule", "kind": "function", "doc": "

Returns a logarithmic temperature schedule for given initial and final temperatures,\nfrom https://link.springer.com/article/10.1007/BF00143921

\n", "signature": "(\tt_init: Union[int, float],\tt_final: Union[int, float]) -> pauliopt.utils.TempSchedule:", "funcdef": "def"}, {"fullname": "pauliopt.utils.StandardTempScheduleName", "modulename": "pauliopt.utils", "qualname": "StandardTempScheduleName", "kind": "variable", "doc": "

Names of the standard temperature schedules.

\n", "default_value": "typing.Literal['linear', 'geometric', 'reciprocal', 'log']"}, {"fullname": "pauliopt.utils.StandardTempSchedule", "modulename": "pauliopt.utils", "qualname": "StandardTempSchedule", "kind": "variable", "doc": "

Type for standard temperature schedules.

\n", "default_value": "typing.Tuple[typing.Literal['linear', 'geometric', 'reciprocal', 'log'], typing.Union[int, float], typing.Union[int, float]]"}, {"fullname": "pauliopt.utils.StandardTempSchedules", "modulename": "pauliopt.utils", "qualname": "StandardTempSchedules", "kind": "variable", "doc": "

Dictionary of standard temperature schedule providers.

\n", "annotation": ": Final[Mapping[Literal['linear', 'geometric', 'reciprocal', 'log'], pauliopt.utils.TempScheduleProvider]]", "default_value": "{'linear': <function linear_temp_schedule>, 'geometric': <function geometric_temp_schedule>, 'reciprocal': <function reciprocal_temp_schedule>, 'log': <function log_temp_schedule>}"}]; // mirrored in build-search-index.js (part 1) // Also split on html tags. this is a cheap heuristic, but good enough. diff --git a/notebooks/2. Circuits of Phase Gadgets.ipynb b/notebooks/2. Circuits of Phase Gadgets.ipynb index 8754c565..0a40121f 100644 --- a/notebooks/2. Circuits of Phase Gadgets.ipynb +++ b/notebooks/2. Circuits of Phase Gadgets.ipynb @@ -26,15 +26,6 @@ "cell_type": "code", "execution_count": 1, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Current working directory: C:\\Users\\Stefa\\Documents\\git\\pauliopt\n" - ] - } - ], "source": [ "import os\n", "DEBUG = True\n", @@ -48,7 +39,8 @@ " original_wd = os.getcwd()\n", " os.chdir('../')\n", "print(\"Current working directory: %s\"%str(os.getcwd()))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -65,23 +57,14 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - ":4: DeprecationWarning: `set_matplotlib_formats` is deprecated since IPython 7.23, directly use `matplotlib_inline.backend_inline.set_matplotlib_formats()`\n", - " set_matplotlib_formats('svg')\n" - ] - } - ], "source": [ "import matplotlib.pyplot as plt\n", "from IPython.display import set_matplotlib_formats\n", "%matplotlib inline\n", "set_matplotlib_formats('svg')\n", "# import qiskit" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -98,7 +81,6 @@ "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [], "source": [ "from typing import Union\n", "from IPython.display import Image, HTML # type: ignore\n", @@ -116,7 +98,8 @@ " html += f\"\"\n", " html += f\"\"\n", " return HTML(html)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -139,24 +122,13 @@ "cell_type": "code", "execution_count": 4, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "PhaseGadget('Z', π/2, {0, 2, 5})" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "from pauliopt.utils import pi\n", "from pauliopt.phase import PhaseGadget\n", "gadget = PhaseGadget(\"Z\", pi/2, {0, 2, 5})\n", "gadget" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -173,22 +145,12 @@ "cell_type": "code", "execution_count": 5, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "gadget.basis = 'Z'\n", - "gadget.angle = pi/2\n", - "gadget.qubits = frozenset({0, 2, 5})\n" - ] - } - ], "source": [ "print(f\"{gadget.basis = }\")\n", "print(f\"{gadget.angle = }\")\n", "print(f\"{gadget.qubits = }\") " - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -205,24 +167,14 @@ "cell_type": "code", "execution_count": 6, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "hash(gadget) = 624374175457367365\n", - "(gadget == same_gadget) = True\n", - "(gadget == other_gadget) = False\n" - ] - } - ], "source": [ "same_gadget = PhaseGadget(\"Z\", pi/2, {0, 2, 5})\n", "other_gadget = PhaseGadget(\"X\", pi/2, {0, 2, 5})\n", "print(f\"{hash(gadget) = }\")\n", "print(f\"{(gadget == same_gadget) = }\")\n", "print(f\"{(gadget == other_gadget) = }\")" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -239,22 +191,13 @@ "cell_type": "code", "execution_count": 7, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Z(π/2) @ {0, 2, 5}\n", - "PhaseGadget('Z', π/2, {0, 2, 5})\n" - ] - } - ], "source": [ "from pauliopt.phase import Z, X\n", "gadget = Z(pi/2) @ {0, 2, 5}\n", "print(gadget)\n", "print(repr(gadget))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -293,7 +236,6 @@ "cell_type": "code", "execution_count": 8, "metadata": {}, - "outputs": [], "source": [ "from pauliopt.phase import PhaseCircuit\n", "gadgets = [\n", @@ -304,7 +246,8 @@ " X(pi/2) @ {0, 1},\n", "]\n", "phase_circuit = PhaseCircuit(3, gadgets)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -321,24 +264,13 @@ "cell_type": "code", "execution_count": 9, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "phase_circuit.num_qubits = 3\n", - "\n", - "phase_circuit.num_gadgets = 5\n", - "phase_circuit.gadgets = (PhaseGadget('Z', π/2, {0, 1}), PhaseGadget('X', π, {0, 2}), PhaseGadget('X', 7π/4, {1, 2}), PhaseGadget('Z', π/4, {0, 2}), PhaseGadget('X', π/2, {0, 1}))\n" - ] - } - ], "source": [ "print(f\"{phase_circuit.num_qubits = }\")\n", "print()\n", "print(f\"{phase_circuit.num_gadgets = }\")\n", "print(f\"{phase_circuit.gadgets = }\")" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -355,22 +287,13 @@ "cell_type": "code", "execution_count": 10, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Immediately after cloning: (phase_circuit == clone_circuit) = True\n", - "After modifying the clone: (phase_circuit == clone_circuit) = False\n" - ] - } - ], "source": [ "clone_circuit = phase_circuit.cloned()\n", "print(f\"Immediately after cloning: {(phase_circuit == clone_circuit) = }\")\n", "clone_circuit.conj_by_cx(0, 1) # modify the clone\n", "print(f\"After modifying the clone: {(phase_circuit == clone_circuit) = }\")" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -387,21 +310,13 @@ "cell_type": "code", "execution_count": 11, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(phase_circuit == new_phase_circuit) = True\n" - ] - } - ], "source": [ "new_phase_circuit = PhaseCircuit(3)\n", "for gadget in gadgets:\n", " new_phase_circuit.add_gadget(gadget)\n", "print(f\"{(phase_circuit == new_phase_circuit) = }\")" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -418,21 +333,13 @@ "cell_type": "code", "execution_count": 12, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(phase_circuit == new_phase_circuit) = True\n" - ] - } - ], "source": [ "new_phase_circuit = PhaseCircuit(3)\n", "for gadget in gadgets:\n", " new_phase_circuit >>= gadget\n", "print(f\"{(phase_circuit == new_phase_circuit) = }\")" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -449,15 +356,6 @@ "cell_type": "code", "execution_count": 13, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(phase_circuit == new_phase_circuit) = True\n" - ] - } - ], "source": [ "new_phase_circuit = PhaseCircuit(3)\n", "new_phase_circuit >>= Z(pi/2) @ {0, 1}\n", @@ -466,7 +364,8 @@ "new_phase_circuit >>= Z(pi/4) @ {0, 2}\n", "new_phase_circuit >>= X(pi/2) @ {0, 1}\n", "print(f\"{(phase_circuit == new_phase_circuit) = }\")" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -483,21 +382,13 @@ "cell_type": "code", "execution_count": 14, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(phase_circuit == new_phase_circuit) = True\n" - ] - } - ], "source": [ "new_phase_circuit = PhaseCircuit(3)\n", "new_phase_circuit >>= [Z(pi/2) @ {0, 1}, X(pi) @ {0, 2}, X(-pi/4) @ {1, 2},\n", " Z(pi/4) @ {0, 2}, X(pi/2) @ {0, 1}]\n", "print(f\"{(phase_circuit == new_phase_circuit) = }\")" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -514,7 +405,6 @@ "cell_type": "code", "execution_count": 15, "metadata": {}, - "outputs": [], "source": [ "from pauliopt.utils import π\n", "circ = PhaseCircuit(3)\n", @@ -523,7 +413,8 @@ "circ >>= X(-π/4) @ {1, 2}\n", "circ >>= Z(π/4) @ {0, 2}\n", "circ >>= X(π/2) @ {0, 1}" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -542,75 +433,10 @@ "cell_type": "code", "execution_count": 16, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "phase_circuit" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -628,73 +454,10 @@ "cell_type": "code", "execution_count": 17, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "phase_circuit.to_svg(zcolor=\"green\", xcolor=\"red\")" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -711,134 +474,11 @@ "cell_type": "code", "execution_count": 18, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "display(phase_circuit.to_svg())\n", "display(phase_circuit.to_svg(hscale = 1.2, vscale=0.9))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -868,101 +508,11 @@ "slide_type": "subslide" } }, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7π/8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/8\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "PhaseCircuit.random(6, 6, angle_subdivision=8,\n", " min_legs=2, max_legs=4, rng_seed=5)" - ] + ], + "outputs": [] }, { "cell_type": "code", @@ -972,101 +522,11 @@ "slide_type": "subslide" } }, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "θ[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "θ[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "θ[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "θ[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "θ[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "θ[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "PhaseCircuit.random(6, 6, parametric=\"θ\",\n", " min_legs=2, max_legs=4, rng_seed=5)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -1083,97 +543,6 @@ "cell_type": "code", "execution_count": 27, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "θ[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "θ[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "θ[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "θ[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "θ[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "θ[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "from pauliopt.utils import AngleVar\n", "θ = [AngleVar(f\"θ[{i}]\") for i in range(6)]\n", @@ -1185,7 +554,8 @@ "circ >>= X(θ[4]) @ {3, 4, 5}\n", "circ >>= Z(θ[5]) @ {2, 3, 4}\n", "circ" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -1206,44 +576,11 @@ "cell_type": "code", "execution_count": 21, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "simple_circ = PhaseCircuit(3, [Z(pi/2) @ {1, 2}])\n", "simple_circ" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -1260,67 +597,13 @@ "cell_type": "code", "execution_count": 22, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "
 ⎯⎯cx(0,1)⟶   
\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "svg_before = simple_circ.to_svg(svg_code_only=True)\n", "simple_circ.conj_by_cx(0, 1)\n", "svg_after = simple_circ.to_svg(svg_code_only=True)\n", "side_by_side(svg_before, \"
 ⎯⎯cx(0,1)⟶   
\", svg_after)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -1337,61 +620,13 @@ "cell_type": "code", "execution_count": 23, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "
 ⎯⎯cx(0,1)⎯⎯cx(1,2)⟶   
\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "π/2\n", - "
" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "svg_before = simple_circ.to_svg(svg_code_only=True)\n", "simple_circ.conj_by_cx(0, 1).conj_by_cx(1, 2)\n", "svg_after = simple_circ.to_svg(svg_code_only=True)\n", "side_by_side(svg_before, \"
 ⎯⎯cx(0,1)⎯⎯cx(1,2)⟶   
\", svg_after)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -1408,143 +643,12 @@ "cell_type": "code", "execution_count": 24, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Original: \n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Conjugated by CX(0, 1): \n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/4\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "print(\"Original: \"); display(phase_circuit)\n", "phase_circuit.conj_by_cx(0, 1)\n", "print(\"Conjugated by CX(0, 1): \"); display(phase_circuit)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -1561,22 +665,14 @@ "cell_type": "code", "execution_count": 25, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Exception: 'PhaseCircuitView' object has no attribute 'conj_by_cx'\n" - ] - } - ], "source": [ "phase_circuit_view = phase_circuit.as_readonly\n", "try:\n", " phase_circuit_view.conj_by_cx(0, 1)\n", "except Exception as e:\n", " print(\"Exception:\", e)" - ] + ], + "outputs": [] } ], "metadata": { diff --git a/notebooks/3. CX Circuits.ipynb b/notebooks/3. CX Circuits.ipynb index 5e4595ae..6b480c81 100644 --- a/notebooks/3. CX Circuits.ipynb +++ b/notebooks/3. CX Circuits.ipynb @@ -26,15 +26,6 @@ "cell_type": "code", "execution_count": 1, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Current working directory: C:\\Users\\Stefa\\Documents\\git\\pauliopt\n" - ] - } - ], "source": [ "import os\n", "DEBUG = True\n", @@ -48,7 +39,8 @@ " original_wd = os.getcwd()\n", " os.chdir('../')\n", "print(\"Current working directory: %s\"%str(os.getcwd()))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -65,23 +57,14 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - ":4: DeprecationWarning: `set_matplotlib_formats` is deprecated since IPython 7.23, directly use `matplotlib_inline.backend_inline.set_matplotlib_formats()`\n", - " set_matplotlib_formats('svg')\n" - ] - } - ], "source": [ "import matplotlib.pyplot as plt\n", "from IPython.display import set_matplotlib_formats\n", "%matplotlib inline\n", "set_matplotlib_formats('svg')\n", "# import qiskit" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -98,7 +81,6 @@ "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [], "source": [ "from io import BytesIO\n", "from typing import Union\n", @@ -125,7 +107,8 @@ " html += f\"\"\n", " html += f\"\"\n", " return HTML(html)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -146,10 +129,10 @@ "cell_type": "code", "execution_count": 4, "metadata": {}, - "outputs": [], "source": [ "from pauliopt.phase import CXCircuit, CXCircuitLayer" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -169,12 +152,12 @@ "cell_type": "code", "execution_count": 5, "metadata": {}, - "outputs": [], "source": [ "from pauliopt.topologies import Topology\n", "topology = Topology.grid(3,3)\n", "layer = CXCircuitLayer(topology, [[0, 1], [2, 5], [6, 7]])" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -191,22 +174,12 @@ "cell_type": "code", "execution_count": 6, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "layer.topology = Topology(9, [{3, 4}, {1, 4}, {1, 2}, {0, 3}, {4, 5}, {0, 1}, {3, 6}, {6, 7}, {2, 5}, {7, 8}, {5, 8}, {4, 7}])\n", - "layer.num_gates = 3\n", - "layer.gates = frozenset({(0, 1), (6, 7), (2, 5)})\n" - ] - } - ], "source": [ "print(f\"{layer.topology = }\")\n", "print(f\"{layer.num_gates = }\")\n", "print(f\"{layer.gates = }\")" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -223,27 +196,11 @@ "cell_type": "code", "execution_count": 7, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Gate on qubit 0: (0, 1)\n", - "Gate on qubit 1: (0, 1)\n", - "Gate on qubit 2: (2, 5)\n", - "Gate on qubit 3: None\n", - "Gate on qubit 4: None\n", - "Gate on qubit 5: (2, 5)\n", - "Gate on qubit 6: (6, 7)\n", - "Gate on qubit 7: (6, 7)\n", - "Gate on qubit 8: None\n" - ] - } - ], "source": [ "for q in layer.topology.qubits:\n", " print(f\"Gate on qubit {q}: {layer.incident(q)}\")" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -260,488 +217,10 @@ "cell_type": "code", "execution_count": 8, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:00.749655\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "layer.draw(figsize=(4,4))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -776,496 +255,11 @@ "cell_type": "code", "execution_count": 9, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Flippable CX gates: frozenset({(0, 1), (3, 4), (4, 3), (6, 7), (2, 5)})\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:00.849887\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "print(f\"Flippable CX gates: {layer.flippable_cxs}\")\n", "layer.draw(figsize=(3,3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -1282,496 +276,6 @@ "cell_type": "code", "execution_count": 10, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "layer.is_cx_flippable(4, 3) = True\n", - "layer.is_cx_flippable(2, 5) = True\n", - "layer.is_cx_flippable(1, 0) = False\n", - "layer.is_cx_flippable(7, 4) = False\n", - "layer.is_cx_flippable(1, 2) = False\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:00.950152\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "print(f\"{layer.is_cx_flippable(4, 3) = }\") # no incident gates on qubits\n", "print(f\"{layer.is_cx_flippable(2, 5) = }\") # gate in circuit\n", @@ -1779,7 +283,8 @@ "print(f\"{layer.is_cx_flippable(7, 4) = }\") # incident gate on one qubit\n", "print(f\"{layer.is_cx_flippable(1, 2) = }\") # incident gates on both qubits\n", "layer.draw(figsize=(3,3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -1796,983 +301,14 @@ "cell_type": "code", "execution_count": 11, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Before flipping (4,3):\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:01.050623\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After flipping (4,3):\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:01.135200\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "print(\"Before flipping (4,3):\")\n", "layer.draw(figsize=(3,3))\n", "layer.flip_cx(4,3)\n", "print(\"After flipping (4,3):\")\n", "layer.draw(figsize=(3,3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -2789,983 +325,14 @@ "cell_type": "code", "execution_count": 12, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Before flipping (6,7):\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:01.266830\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After flipping (6,7):\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:01.351530\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "print(\"Before flipping (6,7):\")\n", "layer.draw(figsize=(3,3))\n", "layer.flip_cx(6,7)\n", "print(\"After flipping (6,7):\")\n", "layer.draw(figsize=(3,3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -3782,490 +349,12 @@ "cell_type": "code", "execution_count": 13, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:01.451884\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "layer = CXCircuitLayer(topology, [[0, 1], [2, 5], [6, 7]])\n", "layer >>= [4, 3], [6,7]\n", "layer.draw(figsize=(3,3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -4282,490 +371,12 @@ "cell_type": "code", "execution_count": 14, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:01.552281\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "layer = CXCircuitLayer(topology)\n", "layer >>= [0, 1], [2, 5], [6, 7], [4, 3], [6,7]\n", "layer.draw(figsize=(3,3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -4784,14 +395,14 @@ "cell_type": "code", "execution_count": 15, "metadata": {}, - "outputs": [], "source": [ "circuit = CXCircuit(topology, [\n", " CXCircuitLayer(topology, [[0, 1], [2, 5], [6, 7]]),\n", " CXCircuitLayer(topology, [[1, 2], [5, 4], [8, 7], [3, 6]]),\n", " CXCircuitLayer(topology, [[0, 1], [4, 3], [7, 6]]),\n", "])" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -4808,497 +419,6 @@ "cell_type": "code", "execution_count": 16, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of layers in circuit: 3\n", - "Gates in layer 0: frozenset({(0, 1), (6, 7), (2, 5)})\n", - "Gates in layer 1: frozenset({(8, 7), (5, 4), (1, 2), (3, 6)})\n", - "Gates in layer 2: frozenset({(0, 1), (7, 6), (4, 3)})\n", - "\n", - "Layer 0:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:01.652535\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "print(f\"Number of layers in circuit: {len(circuit)}\")\n", "for layer_idx, layer in enumerate(circuit):\n", @@ -5306,7 +426,8 @@ "print()\n", "print(\"Layer 0:\")\n", "circuit[0].draw(figsize=(3, 3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -5325,1026 +446,10 @@ "cell_type": "code", "execution_count": 17, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:01.853199\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "circuit.draw(figsize=(3,3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -6361,818 +466,13 @@ "cell_type": "code", "execution_count": 18, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:02.015983\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "circuit = CXCircuit(topology)\n", "circuit >>= CXCircuitLayer(topology, [[0, 1], [2, 5], [6, 7]])\n", "circuit >>= CXCircuitLayer(topology, [[1, 2], [5, 4], [8, 7], [3, 6]])\n", "circuit.draw(figsize=(3,3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -7189,818 +489,13 @@ "cell_type": "code", "execution_count": 19, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:02.169896\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "circuit = CXCircuit(topology)\n", "circuit >>= [[0, 1], [2, 5], [6, 7]]\n", "circuit >>= [[1, 2], [5, 4], [8, 7], [3, 6]]\n", "circuit.draw(figsize=(3,3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -8017,817 +512,12 @@ "cell_type": "code", "execution_count": 20, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:50:02.370691\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "circuit = CXCircuit(topology)\n", "circuit >>= [[0, 1], [2, 5], [6, 7]], [[1, 2], [5, 4], [8, 7], [3, 6]]\n", "circuit.draw(figsize=(3,3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -8844,22 +534,14 @@ "cell_type": "code", "execution_count": 21, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Error: Cannot add CX gate (1, 2) to the layer: gate is not present, but one of control or target is already involved in some other gate.\n" - ] - } - ], "source": [ "circuit = CXCircuit(topology)\n", "try:\n", " circuit >>= [0, 1], [2, 5], [6, 7], [1, 2], [5, 4], [8, 7], [3, 6]\n", "except Exception as e:\n", " print(\"Error:\", e)" - ] + ], + "outputs": [] } ], "metadata": { diff --git a/notebooks/4. Phase Circuit Optimization.ipynb b/notebooks/4. Phase Circuit Optimization.ipynb index ab0dde71..e1967125 100644 --- a/notebooks/4. Phase Circuit Optimization.ipynb +++ b/notebooks/4. Phase Circuit Optimization.ipynb @@ -26,15 +26,6 @@ "cell_type": "code", "execution_count": 1, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Current working directory: C:\\Users\\Stefa\\Documents\\git\\pauliopt\n" - ] - } - ], "source": [ "import os\n", "DEBUG = True\n", @@ -48,7 +39,8 @@ " original_wd = os.getcwd()\n", " os.chdir('../')\n", "print(\"Current working directory: %s\"%str(os.getcwd()))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -65,16 +57,6 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - ":4: DeprecationWarning: `set_matplotlib_formats` is deprecated since IPython 7.23, directly use `matplotlib_inline.backend_inline.set_matplotlib_formats()`\n", - " set_matplotlib_formats('svg')\n" - ] - } - ], "source": [ "import matplotlib.pyplot as plt\n", "from IPython.display import set_matplotlib_formats\n", @@ -82,7 +64,8 @@ "set_matplotlib_formats('svg')\n", "import numpy as np\n", "# import qiskit" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -99,7 +82,6 @@ "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [], "source": [ "from io import BytesIO\n", "from typing import Union\n", @@ -126,7 +108,8 @@ " html += f\"\"\n", " html += f\"\"\n", " return HTML(html)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -164,10 +147,10 @@ "cell_type": "code", "execution_count": 4, "metadata": {}, - "outputs": [], "source": [ "from pauliopt.phase import OptimizedPhaseCircuit" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -184,474 +167,12 @@ "cell_type": "code", "execution_count": 5, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:59:35.030842\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "from pauliopt.topologies import Topology\n", "topology = Topology.grid(3, 3)\n", "topology.draw(figsize=(3, 3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -670,137 +191,12 @@ "metadata": { "scrolled": true }, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "from pauliopt.phase import PhaseCircuit, CXCircuit\n", "orig_circuit = PhaseCircuit.random(topology.num_qubits, 6, rng_seed=0, parametric=\"t\")\n", "orig_circuit" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -818,10 +214,10 @@ "cell_type": "code", "execution_count": 7, "metadata": {}, - "outputs": [], "source": [ "opt = OptimizedPhaseCircuit(orig_circuit, topology, cx_block=1, rng_seed=0)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -838,22 +234,11 @@ "cell_type": "code", "execution_count": 8, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "opt.num_qubits = 9\n", - "\n", - "opt.topology = Topology(9, [{3, 4}, {1, 4}, {1, 2}, {0, 3}, {4, 5}, {0, 1}, {3, 6}, {6, 7}, {2, 5}, {7, 8}, {5, 8}, {4, 7}])\n", - "\n" - ] - } - ], "source": [ "print(f\"{opt.num_qubits = }\", end=\"\\n\\n\")\n", "print(f\"{opt.topology = }\", end=\"\\n\\n\")" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -883,133 +268,10 @@ "cell_type": "code", "execution_count": 9, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "opt.phase_block.to_svg(scale=0.8)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -1026,604 +288,10 @@ "cell_type": "code", "execution_count": 10, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:59:35.215950\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "opt.cx_block.draw(figsize=(3, 3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -1657,1446 +325,6 @@ "metadata": { "scrolled": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "=== Phase block and CX block before random flip ===\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:59:35.354002\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "=== Phase block and CX block after flipping gate (8, 5) in layer 0 ===\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:59:35.454338\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "opt = OptimizedPhaseCircuit(orig_circuit, topology, cx_block=1, rng_seed=0)\n", "print(\"=== Phase block and CX block before random flip ===\")\n", @@ -3106,7 +334,8 @@ "print(f\"\\n\\n=== Phase block and CX block after flipping gate {gate} in layer {layer_idx} ===\")\n", "display(opt.phase_block.to_svg(scale=0.6))\n", "opt.cx_block.draw(figsize=(3, 3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -3123,1444 +352,6 @@ "cell_type": "code", "execution_count": 12, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "=== Phase block and CX block before random flip ===\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:59:35.585932\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "=== Phase block and CX block after 3 random flips ===\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:59:35.717513\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "opt = OptimizedPhaseCircuit(orig_circuit, topology, cx_block=1, rng_seed=0)\n", "print(\"=== Phase block and CX block before random flip ===\")\n", @@ -4571,7 +362,8 @@ "print(f\"\\n\\n=== Phase block and CX block after 3 random flips ===\")\n", "display(opt.phase_block.to_svg(scale=0.6))\n", "opt.cx_block.draw(figsize=(3, 3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -4606,7 +398,6 @@ "cell_type": "code", "execution_count": 13, "metadata": {}, - "outputs": [], "source": [ "from typing import Protocol\n", "class TempSchedule(Protocol):\n", @@ -4618,7 +409,8 @@ "\n", " def __call__(self, it: int, num_iters: int) -> float:\n", " ..." - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -4635,11 +427,11 @@ "cell_type": "code", "execution_count": 14, "metadata": {}, - "outputs": [], "source": [ "from pauliopt.utils import (linear_temp_schedule, geometric_temp_schedule, \n", " reciprocal_temp_schedule, log_temp_schedule)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -4656,1115 +448,6 @@ "cell_type": "code", "execution_count": 15, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:59:35.870778\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], "source": [ "num_iters = 1000\n", "plt.figure(figsize=(10,5))\n", @@ -5775,7 +458,8 @@ " plt.plot(range(num_iters), temp, label=temp_schedule_maker.__name__)\n", "plt.legend()\n", "plt.show()" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -5810,68 +494,11 @@ "cell_type": "code", "execution_count": 16, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[0]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "test_circ = PhaseCircuit.random(topology.num_qubits, 1, rng_seed=0, parametric=\"t\")\n", "test_circ" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -5895,23 +522,11 @@ "cell_type": "code", "execution_count": 17, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "MST implementation info for X(t[0]) @ {0, 1, 5, 7, 8}:\n", - " - Overall CX count for gadget: 12\n", - " - MST branches: [(0, 1), (1, 5), (5, 8), (8, 7)]\n", - " - CX counts for MST branches: [2, 8, 10, 12]\n", - "\n" - ] - } - ], "source": [ "test_gadget = test_circ.gadgets[0]\n", "test_gadget.print_impl_info(topology)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -5928,72 +543,11 @@ "cell_type": "code", "execution_count": 18, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[0]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "test_circ = PhaseCircuit.random(topology.num_qubits, 1, rng_seed=1, parametric=\"t\")\n", "test_circ" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -6019,23 +573,11 @@ "cell_type": "code", "execution_count": 19, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "MST implementation info for X(t[0]) @ {0, 1, 2, 4, 5, 6, 8}:\n", - " - Overall CX count for gadget: 16\n", - " - MST branches: [(0, 1), (1, 2), (1, 4), (2, 5), (5, 8), (0, 6)]\n", - " - CX counts for MST branches: [2, 4, 6, 8, 10, 16]\n", - "\n" - ] - } - ], "source": [ "test_gadget = test_circ.gadgets[0]\n", "test_gadget.print_impl_info(topology)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -6055,729 +597,6 @@ "metadata": { "scrolled": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CX count before flip: 50\n", - " - Gadget CX counts: [0, 2, 14, 10, 16, 8]\n", - " - CX count for the CX blocks: 0\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:59:36.070940\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "opt = OptimizedPhaseCircuit(orig_circuit, topology, 1, rng_seed=1)\n", "print(f\"CX count before flip: {opt.init_cx_count}\")\n", @@ -6785,7 +604,8 @@ "print(f\" - CX count for the CX blocks: {2*opt.cx_block.num_gates}\")\n", "display(opt.phase_block.to_svg(scale=0.8))\n", "opt.cx_block.draw(figsize=(2, 2))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -6807,725 +627,6 @@ "cell_type": "code", "execution_count": 21, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CX count after flip: 50\n", - " - Gadget CX counts: [0, 2, 12, 10, 14, 8]\n", - " - CX count for the CX blocks: 2\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:59:36.202548\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "opt.flip_cx(0, 1, 0)\n", "print(f\"CX count after flip: {opt.cx_count}\")\n", @@ -7533,7 +634,8 @@ "print(f\" - CX count for the CX blocks: {2*opt.cx_block.num_gates}\")\n", "display(opt.phase_block.to_svg(scale=0.8))\n", "opt.cx_block.draw(figsize=(2, 2))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -7556,719 +658,6 @@ "cell_type": "code", "execution_count": 22, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CX count after second flip: 50\n", - " - Gadget CX counts: [0, 2, 10, 12, 12, 8]\n", - " - CX count for the CX blocks: 4\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T19:59:36.318433\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "opt.flip_cx(0, 2, 5)\n", "print(f\"CX count after second flip: {opt.cx_count}\")\n", @@ -8276,7 +665,8 @@ "print(f\" - CX count for the CX blocks: {2*opt.cx_block.num_gates}\")\n", "display(opt.phase_block.to_svg(scale=0.8))\n", "opt.cx_block.draw(figsize=(2, 2))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -8297,7 +687,6 @@ "cell_type": "code", "execution_count": 23, "metadata": {}, - "outputs": [], "source": [ "from math import log10, ceil\n", "def log_iter(it, prev_cost, new_cost, accepted, flip, t, num_iters):\n", @@ -8308,7 +697,8 @@ " \"log_iter\": log_iter,\n", " \"log_end\": lambda cost, num_iters: print(f\"Final cost: {cost}\"),\n", "}" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -8328,27 +718,13 @@ "cell_type": "code", "execution_count": 47, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Init cost: 50\n", - "Iter #03, new cost: 50\n", - "Iter #07, new cost: 48\n", - "Iter #08, new cost: 46\n", - "Iter #10, new cost: 44\n", - "Iter #13, new cost: 42\n", - "Final cost: 42\n" - ] - } - ], "source": [ "topology = Topology.grid(3, 3)\n", "circuit = PhaseCircuit.random(topology.num_qubits, 6, rng_seed=0, parametric=\"t\")\n", "opt = OptimizedPhaseCircuit(circuit, topology, cx_block=1, circuit_rep=1, rng_seed=1)\n", "opt.anneal(100, schedule=(\"geometric\", 1, 1e-5), loggers=loggers)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -8365,720 +741,6 @@ "cell_type": "code", "execution_count": 48, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CX count before annealing: 50\n", - " - Gadget CX counts: [0, 2, 14, 10, 16, 8]\n", - "\n", - "Cost after annealing: 42 (1 reps: -16.0%, many reps limit: -28.0%)\n", - " - Gadget CX counts: [0, 2, 8, 10, 10, 6]\n", - " - CX blocks CX count: 6\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T20:00:55.561034\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "print(f\"CX count before annealing: {opt.init_cx_count}\")\n", "print(f\" - Gadget CX counts: {[g.cx_count(topology) for g in circuit.gadgets]}\")\n", @@ -9091,7 +753,8 @@ "print(f\" - CX blocks CX count: {2*opt.cx_block.num_gates}\")\n", "display(opt.phase_block.to_svg(scale=0.8))\n", "opt.cx_block.draw(figsize=(3, 3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -9108,27 +771,13 @@ "cell_type": "code", "execution_count": 49, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Init cost: 50\n", - "Iter #000, new cost: 48\n", - "Iter #003, new cost: 46\n", - "Iter #017, new cost: 42\n", - "Iter #082, new cost: 42\n", - "Iter #087, new cost: 38\n", - "Final cost: 38\n" - ] - } - ], "source": [ "topology = Topology.grid(3, 3)\n", "circuit = PhaseCircuit.random(topology.num_qubits, 6, rng_seed=0, parametric=\"t\")\n", "opt = OptimizedPhaseCircuit(circuit, topology, cx_block=4, circuit_rep=1, rng_seed=1)\n", "opt.anneal(1000, schedule=(\"geometric\", 1, 1e-5), loggers=loggers)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -9145,1505 +794,6 @@ "cell_type": "code", "execution_count": 50, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CX count before annealing: 50\n", - " - Gadget CX counts: [0, 2, 14, 10, 16, 8]\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Cost after annealing: 38 (1 reps: -24.0%, many reps limit: -48.0%)\n", - " - Gadget CX counts: [0, 2, 4, 8, 6, 6]\n", - " - CX blocks CX count: 12\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T20:01:00.372612\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "print(f\"CX count before annealing: {opt.init_cx_count}\")\n", "print(f\" - Gadget CX counts: {[g.cx_count(topology) for g in circuit.gadgets]}\")\n", @@ -10656,7 +806,8 @@ "print(f\" - CX blocks CX count: {2*opt.cx_block.num_gates}\")\n", "display(opt.to_svg(scale=0.8))\n", "opt.cx_block.draw(figsize=(3, 3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -10673,562 +824,6 @@ "cell_type": "code", "execution_count": 28, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CX count before annealing: 150\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CX count after annealing: 100 (3 reps: -33.3%)\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "8\n", - "8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "\n", - "t[0]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[1]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[2]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[3]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[4]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "t[5]\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "circuit_3 = circuit >> circuit >> circuit\n", "opt_3 = OptimizedPhaseCircuit(circuit, topology, cx_block=3, circuit_rep=3, rng_seed=4)\n", @@ -11238,7 +833,8 @@ "change_3 = (opt_3.cx_count-opt_3.init_cx_count)/opt_3.init_cx_count\n", "print(f\"CX count after annealing: {opt_3.cx_count} ({opt_3.circuit_rep} reps: {change_3:.1%})\")\n", "display(opt_3.to_svg(hscale=0.42, vscale=0.5))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -11258,59 +854,13 @@ "cell_type": "code", "execution_count": 40, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Init cost: 2900\n", - "Iter #000, new cost: 2822\n", - "Iter #002, new cost: 2794\n", - "Iter #003, new cost: 2786\n", - "Iter #012, new cost: 2778\n", - "Iter #013, new cost: 2750\n", - "Iter #014, new cost: 2742\n", - "Iter #015, new cost: 2734\n", - "Iter #017, new cost: 2718\n", - "Iter #018, new cost: 2706\n", - "Iter #021, new cost: 2698\n", - "Iter #022, new cost: 2690\n", - "Iter #023, new cost: 2682\n", - "Iter #025, new cost: 2674\n", - "Iter #026, new cost: 2666\n", - "Iter #034, new cost: 2656\n", - "Iter #035, new cost: 2648\n", - "Iter #043, new cost: 2640\n", - "Iter #045, new cost: 2632\n", - "Iter #067, new cost: 2624\n", - "Iter #097, new cost: 2622\n", - "Iter #112, new cost: 2614\n", - "Iter #128, new cost: 2606\n", - "Iter #132, new cost: 2594\n", - "Iter #133, new cost: 2582\n", - "Iter #169, new cost: 2574\n", - "Iter #172, new cost: 2536\n", - "Iter #174, new cost: 2534\n", - "Iter #191, new cost: 2526\n", - "Iter #205, new cost: 2508\n", - "Iter #229, new cost: 2500\n", - "Iter #244, new cost: 2488\n", - "Iter #291, new cost: 2470\n", - "Iter #298, new cost: 2444\n", - "Iter #324, new cost: 2442\n", - "Iter #382, new cost: 2442\n", - "Iter #406, new cost: 2424\n", - "Iter #464, new cost: 2416\n", - "Final cost: 2416\n" - ] - } - ], "source": [ "topology = Topology.grid(5, 5)\n", "circuit = PhaseCircuit.random(topology.num_qubits, 50, min_legs=1, max_legs=3, rng_seed=0, parametric=\"t\")\n", "opt = OptimizedPhaseCircuit(circuit, topology, cx_block=3, circuit_rep=5, rng_seed=1)\n", "opt.anneal(1000, schedule=(\"linear\", 1, 1e-5), loggers=loggers)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -11327,1892 +877,6 @@ "cell_type": "code", "execution_count": 41, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CX count before annealing: 2900\n", - " - Gadget CX counts: [10, 14, 20, 24, 24, 18, 20, 12, 18, 12, 20, 16, 6, 28, 0, 10, 20, 12, 22, 10, 0, 14, 6, 28, 24, 0, 16, 2, 6, 16, 2, 0, 0, 12, 6, 14, 6, 8, 10, 0, 24, 0, 0, 24, 14, 0, 0, 2, 20, 10]\n", - "\n", - "Cost after annealing: 2416 (5 reps: -16.7%, many reps limit: -18.3%)\n", - " - Gadget CX counts: [6, 18, 12, 16, 16, 14, 16, 6, 16, 12, 18, 12, 2, 16, 0, 6, 18, 12, 20, 10, 0, 10, 6, 24, 18, 4, 16, 2, 4, 12, 0, 0, 0, 14, 12, 8, 2, 4, 6, 0, 16, 0, 2, 22, 14, 0, 4, 2, 18, 8]\n", - " - CX blocks CX count: 46\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T20:00:17.539143\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "print(f\"CX count before annealing: {opt.init_cx_count}\")\n", "print(f\" - Gadget CX counts: {[g.cx_count(topology) for g in circuit.gadgets]}\")\n", @@ -13224,7 +888,8 @@ "print(f\" - Gadget CX counts: {[g.cx_count(topology) for g in opt.phase_block.gadgets]}\")\n", "print(f\" - CX blocks CX count: {2*opt.cx_block.num_gates}\")\n", "opt.cx_block.draw(figsize=(3, 3))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -13241,7 +906,6 @@ "cell_type": "code", "execution_count": 42, "metadata": {}, - "outputs": [], "source": [ "from time import perf_counter\n", "iter_timestamps = []\n", @@ -13263,7 +927,8 @@ " \"log_iter\": log_iter_time,\n", " \"log_end\": log_end_time,\n", "}" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -13280,22 +945,13 @@ "cell_type": "code", "execution_count": 43, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average iter time: 643 μs (13 μs/gadget)\n", - "Iter time std dev: 275 μs\n" - ] - } - ], "source": [ "topology = Topology.grid(3, 3)\n", "circuit = PhaseCircuit.random(topology.num_qubits, 50, min_legs=1, max_legs=3, rng_seed=0)\n", "opt = OptimizedPhaseCircuit(circuit, topology, cx_block=4, circuit_rep=1, rng_seed=1)\n", "opt.anneal(100, schedule=(\"geometric\", 1, 1e-5), loggers=time_loggers)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -13314,22 +970,13 @@ "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average iter time: 698 μs (14 μs/gadget)\n", - "Iter time std dev: 295 μs\n" - ] - } - ], "source": [ "topology = Topology.grid(5, 5)\n", "circuit = PhaseCircuit.random(topology.num_qubits, 50, min_legs=1, max_legs=3, rng_seed=0)\n", "opt = OptimizedPhaseCircuit(circuit, topology, cx_block=4, circuit_rep=1, rng_seed=1)\n", "opt.anneal(100, schedule=(\"linear\", 1, 1e-5), loggers=time_loggers)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -13346,22 +993,13 @@ "cell_type": "code", "execution_count": 45, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average iter time: 364 μs (7 μs/gadget)\n", - "Iter time std dev: 83 μs\n" - ] - } - ], "source": [ "topology = Topology.grid(9, 9)\n", "circuit = PhaseCircuit.random(topology.num_qubits, 50, min_legs=1, max_legs=3, rng_seed=0)\n", "opt = OptimizedPhaseCircuit(circuit, topology, cx_block=4, circuit_rep=1, rng_seed=0)\n", "opt.anneal(100, schedule=(\"linear\", 1, 1e-5), loggers=time_loggers)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -13380,22 +1018,13 @@ "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average iter time: 372 μs (7 μs/gadget)\n", - "Iter time std dev: 89 μs\n" - ] - } - ], "source": [ "topology = Topology.grid(12, 12)\n", "circuit = PhaseCircuit.random(topology.num_qubits, 50, min_legs=1, max_legs=3, rng_seed=0)\n", "opt = OptimizedPhaseCircuit(circuit, topology, cx_block=4, circuit_rep=1, rng_seed=0)\n", "opt.anneal(10, schedule=(\"linear\", 1, 1e-5), loggers=time_loggers)" - ] + ], + "outputs": [] } ], "metadata": { diff --git a/notebooks/5. Phase Circuit Simplification.ipynb b/notebooks/5. Phase Circuit Simplification.ipynb index 02e280a4..2dcbaedf 100644 --- a/notebooks/5. Phase Circuit Simplification.ipynb +++ b/notebooks/5. Phase Circuit Simplification.ipynb @@ -26,15 +26,6 @@ "cell_type": "code", "execution_count": 1, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Current working directory: C:\\Users\\Stefa\\Documents\\git\\pauliopt\n" - ] - } - ], "source": [ "import os\n", "DEBUG = True\n", @@ -48,7 +39,8 @@ " original_wd = os.getcwd()\n", " os.chdir('../')\n", "print(\"Current working directory: %s\"%str(os.getcwd()))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -65,16 +57,6 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - ":4: DeprecationWarning: `set_matplotlib_formats` is deprecated since IPython 7.23, directly use `matplotlib_inline.backend_inline.set_matplotlib_formats()`\n", - " set_matplotlib_formats('svg')\n" - ] - } - ], "source": [ "import matplotlib.pyplot as plt\n", "from IPython.display import set_matplotlib_formats\n", @@ -82,7 +64,8 @@ "set_matplotlib_formats('svg')\n", "import numpy as np\n", "# import qiskit" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -99,7 +82,6 @@ "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [], "source": [ "from io import BytesIO\n", "from typing import Union\n", @@ -126,7 +108,8 @@ " html += f\"\"\n", " html += f\"\"\n", " return HTML(html)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -143,12 +126,12 @@ "cell_type": "code", "execution_count": 4, "metadata": {}, - "outputs": [], "source": [ "from pauliopt.phase import PhaseCircuit, PhaseGadget, Z, X\n", "from pauliopt.utils import pi, Angle\n", "from pauliopt.topologies import Topology" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -165,7 +148,6 @@ "cell_type": "code", "execution_count": 5, "metadata": {}, - "outputs": [], "source": [ "from typing import Dict, FrozenSet, List, Literal, Tuple\n", "def display_step(num_qubits, pi_gates, groups):\n", @@ -296,7 +278,8 @@ " pi_gates[basis][q] += 1\n", " print(f\"After Step {step}, pi-gadget handling performed:\")\n", " display_step(num_qubits, pi_gates, groups)\n" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -326,45 +309,14 @@ "cell_type": "code", "execution_count": 6, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "circ = PhaseCircuit(3)\n", "circ.x(0)\n", "circ.y(1)\n", "circ.z(2)\n", "circ.to_svg()" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -381,47 +333,14 @@ "cell_type": "code", "execution_count": 7, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/4\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "circ = PhaseCircuit(3)\n", "circ.h(0)\n", "circ.s(1)\n", "circ.t(2)\n", "circ.to_svg()" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -438,47 +357,14 @@ "cell_type": "code", "execution_count": 8, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "13π/8\n", - "\n", - "3π/2\n", - "\n", - "3π/4\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "circ = PhaseCircuit(3)\n", "circ.rx(0, pi/2)\n", "circ.ry(1, 13*pi/8)\n", "circ.rz(2, 3*pi/4)\n", "circ.to_svg()" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -495,82 +381,14 @@ "cell_type": "code", "execution_count": 9, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "circ = PhaseCircuit(6)\n", "circ.cx(0, 1)\n", "# circ.cy(2, 3) # to be implemented\n", "circ.cz(4, 5)\n", "circ.to_svg(scale=0.9)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -587,89 +405,6 @@ "cell_type": "code", "execution_count": 10, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "4\n", - "4\n", - "\n", - "5\n", - "5\n", - "\n", - "6\n", - "6\n", - "\n", - "7\n", - "7\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7π/4\n", - "\n", - "π/4\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "13π/8\n", - "\n", - "3π/8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "3π/4\n", - "\n", - "3π/4\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "circ = PhaseCircuit(8)\n", "circ.crx(0, 1, pi/2)\n", @@ -677,7 +412,8 @@ "circ.crz(4, 5, 3*pi/4)\n", "circ.cu1(6, 7, 3*pi/4)\n", "circ.to_svg(scale=0.8)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -694,134 +430,12 @@ "cell_type": "code", "execution_count": 11, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "15π/8\n", - "\n", - "π/8\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "circ = PhaseCircuit(4)\n", "circ.crx(0,2,pi).crx(0,2,pi).crz(3,1,pi/4).cx(2,1).cz(1,2).h(0)\n", "circ.to_svg(vscale=0.8, hscale=0.5)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -862,107 +476,6 @@ "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Original:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Simplified:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "circ = PhaseCircuit(2)\n", "circ.cx(0, 1).h(1).cz(0, 1)\n", @@ -971,7 +484,8 @@ "print(\"\\nSimplified:\")\n", "circ_simplified = circ.simplified()\n", "display(circ_simplified.to_svg(vscale=0.8, hscale=0.5))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -988,220 +502,6 @@ "cell_type": "code", "execution_count": 14, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Original:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "15π/8\n", - "\n", - "π/8\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "Simplified:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "2\n", - "2\n", - "\n", - "3\n", - "3\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "15π/8\n", - "\n", - "π/8\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "circ = PhaseCircuit(4)\n", "circ.crx(0,2,pi).crx(0,2,pi).crz(3,1,pi/4).cx(2,1).cz(1,2).h(0)\n", @@ -1210,7 +510,8 @@ "print(\"\\n\\nSimplified:\")\n", "circ_simplified = circ.simplified()\n", "display(circ_simplified.to_svg(vscale=0.7, hscale=0.6))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -1229,1167 +530,12 @@ "metadata": { "scrolled": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Original circuit:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/4\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "7π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "In the first phase of the algorithm, we progressively grow groups of gadgets of the same colour, fusing where possible.\n", - "We start with an empty group for the Z basis.\n", - "\n", - "\n", - "After Step 1, created new gadget group:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 2, created new gadget group:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/4\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 3, added gadget to current group:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/4\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 4, fused gadget into current group:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/4\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 5, fused gadget into current group:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 6, added gadget to current group:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "\n", - "3π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 7, fused gadget into current group:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "\n", - "5π/4\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 8, created new gadget group:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 9, added gadget to current group:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 10, fused gadget into current group:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 11, fused gadget into current group:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/4\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 12, fused gadget into current group:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "In the second phase of the algorithm, we commute gadgets to the left.\n", - "We fuse gadgets into new groups if possible and apply pi-gadget simplification.\n", - "\n", - "After Step 13, no commutation performed, no pi-gadget handling:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 14, commutation performed, no pi-gadget handling:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "π\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Middle of Step 15, no commutation performed, but pi-gadget handling to follow:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "π\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 15, pi-gadget handling performed:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 16, no commutation performed, no pi-gadget handling:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 17, no commutation performed, no pi-gadget handling:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "π\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Middle of Step 18, commutation performed, pi-gadget handling to follow:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After Step 18, pi-gadget handling performed:\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "0\n", - "0\n", - "\n", - "1\n", - "1\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "5π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5π/4\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "topology = Topology.line(2)\n", "circuit = PhaseCircuit.random(topology.num_qubits, 12, min_legs=1, max_legs=2, rng_seed=6)\n", "display_simplification(circuit)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -2419,7 +565,6 @@ "cell_type": "code", "execution_count": 16, "metadata": {}, - "outputs": [], "source": [ "qasm_code = \"\"\"\n", "OPENQASM 2.0;\n", @@ -2499,7 +644,8 @@ "cx q[3], q[5];\n", "cx q[8], q[4];\n", "\"\"\"" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -2516,590 +662,6 @@ "cell_type": "code", "execution_count": 17, "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " 2022-04-21T20:01:44.441180\n", - " image/svg+xml\n", - " \n", - " \n", - " Matplotlib v3.5.1, https://matplotlib.org/\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "rigetti_16q_topology = Topology(16,\n", " [[i, (i+1)%8] for i in range(0,8)]\n", @@ -3107,7 +669,8 @@ " +[[2, 13], [1, 14]]\n", ")\n", "rigetti_16q_topology.draw()" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -3124,10 +687,10 @@ "cell_type": "code", "execution_count": 18, "metadata": {}, - "outputs": [], "source": [ "optimal_mapping = [1, 10, 5, 15, 7, 14, 8, 12, 6, 13, 9, 2, 11, 0, 3, 4]" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -3144,1086 +707,6 @@ "cell_type": "code", "execution_count": 19, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Original number of gadgets: 305\n", - "Original CX count: 118\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - " 0\n", - " 0\n", - "\n", - " 1\n", - " 1\n", - "\n", - " 2\n", - " 2\n", - "\n", - " 3\n", - " 3\n", - "\n", - " 4\n", - " 4\n", - "\n", - " 5\n", - " 5\n", - "\n", - " 6\n", - " 6\n", - "\n", - " 7\n", - " 7\n", - "\n", - " 8\n", - " 8\n", - "\n", - " 9\n", - " 9\n", - "\n", - "10\n", - "10\n", - "\n", - "11\n", - "11\n", - "\n", - "12\n", - "12\n", - "\n", - "13\n", - "13\n", - "\n", - "14\n", - "14\n", - "\n", - "15\n", - "15\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "Simplified number of gadgets: 57 (change: -81.3%)\n", - "Simplified CX count: 26 (change: -78.0%)\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - " 0\n", - " 0\n", - "\n", - " 1\n", - " 1\n", - "\n", - " 2\n", - " 2\n", - "\n", - " 3\n", - " 3\n", - "\n", - " 4\n", - " 4\n", - "\n", - " 5\n", - " 5\n", - "\n", - " 6\n", - " 6\n", - "\n", - " 7\n", - " 7\n", - "\n", - " 8\n", - " 8\n", - "\n", - " 9\n", - " 9\n", - "\n", - "10\n", - "10\n", - "\n", - "11\n", - "11\n", - "\n", - "12\n", - "12\n", - "\n", - "13\n", - "13\n", - "\n", - "14\n", - "14\n", - "\n", - "15\n", - "15\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "3π/2\n", - "\n", - "π/2\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "circuit = PhaseCircuit.from_qasm(qasm_code)\n", "orig_len = len(circuit)\n", @@ -4240,7 +723,8 @@ "print(f\"Simplified number of gadgets: {simpl_len} (change: {len_change:.1%})\")\n", "print(f\"Simplified CX count: {simpl_count} (change: {count_change:.1%})\")\n", "display(circuit_simplified.to_svg(vscale=0.6, hscale=0.4))" - ] + ], + "outputs": [] } ], "metadata": { diff --git a/notebooks/6. Pauli Polynomials.ipynb b/notebooks/6. Pauli Polynomials.ipynb index e5edd004..6e4863ef 100644 --- a/notebooks/6. Pauli Polynomials.ipynb +++ b/notebooks/6. Pauli Polynomials.ipynb @@ -5,14 +5,14 @@ "execution_count": 1, "id": "4abbaa6c", "metadata": {}, - "outputs": [], "source": [ "from pauliopt.pauli.pauli_polynomial import PauliPolynomial\n", "from pauliopt.pauli.pauli_gadget import PPhase\n", "from pauliopt.pauli.utils import I, Z, X, Y\n", "from pauliopt.utils import Angle, pi\n", "from pauliopt.topologies import Topology" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -63,22 +63,11 @@ "execution_count": 2, "id": "a22d780c", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0.5) @ { I, Z, X, Y }" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "pauli_gadget = PPhase(0.5) @ [I, Z, X, Y] # TODO Angle(pi)\n", "pauli_gadget" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -107,26 +96,10 @@ "execution_count": 3, "id": "71d6fc47", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \n", - "q_0: ──────────────────────────────────────────────────────\n", - " ┌───┐┌─────────┐┌───┐ \n", - "q_1: ────────────────┤ X ├┤ Rz(0.5) ├┤ X ├─────────────────\n", - " ┌───┐ ┌───┐└─┬─┘└─────────┘└─┬─┘┌───┐ ┌───┐ \n", - "q_2: ───┤ H ├───┤ X ├──■───────────────■──┤ X ├───┤ H ├────\n", - " ┌──┴───┴──┐└─┬─┘ └─┬─┘┌──┴───┴───┐\n", - "q_3: ┤ Rx(π/2) ├──■─────────────────────────■──┤ Rx(-π/2) ├\n", - " └─────────┘ └──────────┘\n" - ] - } - ], "source": [ "print(pauli_gadget.to_qiskit(Topology.line(4)))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -145,20 +118,6 @@ "execution_count": 4, "id": "1c72d4e0", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(π) @ { I, I, X, Z, Y }\n", - "(π/2) @ { X, X, I, I, Y }\n", - "(π/256) @ { X, I, I, Z, Y }\n", - "(π/8) @ { X, X, X, Z, Y }\n", - "(π/4) @ { X, Z, I, I, Y }\n", - "(π/2) @ { X, I, I, Y, Y }\n" - ] - } - ], "source": [ "pp = PauliPolynomial(5)\n", "\n", @@ -171,111 +130,19 @@ "\n", "# Representation in CLI applications\n", "print(pp)" - ] + ], + "outputs": [] }, { "cell_type": "code", "execution_count": 5, "id": "f2007e30", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/256\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "π/2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "(π) @ { I, I, X, Z, Y }\n", - "(π/2) @ { X, X, I, I, Y }\n", - "(π/256) @ { X, I, I, Z, Y }\n", - "(π/8) @ { X, X, X, Z, Y }\n", - "(π/4) @ { X, Z, I, I, Y }\n", - "(π/2) @ { X, I, I, Y, Y }" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "# SVG representation in e.g. Jupyter notebooks\n", "pp" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -292,72 +159,10 @@ "metadata": { "scrolled": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ┌───┐ ┌───┐┌───┐»\n", - "q_0: ───┤ H ├───────────────────────────────────────────────────────┤ X ├┤ X ├»\n", - " ├───┤ └─┬─┘└─┬─┘»\n", - "q_1: ───┤ H ├─────────────────────────────────────────────────────────┼────■──»\n", - " ├───┤ ┌───┐┌───┐┌───────┐┌───┐┌───┐ ┌───┐ ┌───┐ │ »\n", - "q_2: ───┤ H ├───┤ X ├┤ X ├┤ Rz(π) ├┤ X ├┤ X ├───┤ H ├───────┤ H ├─────┼───────»\n", - " └───┘ └─┬─┘└─┬─┘└───────┘└─┬─┘└─┬─┘ └───┘ └───┘ │ »\n", - "q_3: ─────────────┼────■─────────────■────┼───────────────────────────┼───────»\n", - " ┌─────────┐ │ │ ┌──────────┐┌─────────┐ │ »\n", - "q_4: ┤ Rx(π/2) ├──■───────────────────────■──┤ Rx(-π/2) ├┤ Rx(π/2) ├──■───────»\n", - " └─────────┘ └──────────┘└─────────┘ »\n", - "« ┌─────────┐┌───┐┌───┐ ┌───┐ ┌───┐ ┌───┐┌───┐┌───────────┐┌───┐»\n", - "«q_0: ┤ Rz(π/2) ├┤ X ├┤ X ├───┤ H ├───────┤ H ├───┤ X ├┤ X ├┤ Rz(π/256) ├┤ X ├»\n", - "« └─────────┘└─┬─┘└─┬─┘ ├───┤ ├───┤ └─┬─┘└─┬─┘└───────────┘└─┬─┘»\n", - "«q_1: ─────────────■────┼─────┤ H ├───────┤ H ├─────┼────┼─────────────────┼──»\n", - "« │ └───┘ └───┘ │ │ │ »\n", - "«q_2: ──────────────────┼───────────────────────────┼────┼─────────────────┼──»\n", - "« │ │ │ │ »\n", - "«q_3: ──────────────────┼───────────────────────────┼────■─────────────────■──»\n", - "« │ ┌──────────┐┌─────────┐ │ »\n", - "«q_4: ──────────────────■──┤ Rx(-π/2) ├┤ Rx(π/2) ├──■─────────────────────────»\n", - "« └──────────┘└─────────┘ »\n", - "« ┌───┐ ┌───┐ ┌───┐ ┌───┐┌───┐┌───┐┌───┐┌─────────┐┌───┐┌───┐»\n", - "«q_0: ┤ X ├───┤ H ├───────┤ H ├───┤ X ├┤ X ├┤ X ├┤ X ├┤ Rz(π/8) ├┤ X ├┤ X ├»\n", - "« └─┬─┘ └───┘ └───┘ └─┬─┘└─┬─┘└─┬─┘└─┬─┘└─────────┘└─┬─┘└─┬─┘»\n", - "«q_1: ──┼───────────────────────────┼────┼────┼────■───────────────■────┼──»\n", - "« │ │ │ │ │ »\n", - "«q_2: ──┼───────────────────────────┼────┼────■─────────────────────────■──»\n", - "« │ │ │ »\n", - "«q_3: ──┼───────────────────────────┼────■─────────────────────────────────»\n", - "« │ ┌──────────┐┌─────────┐ │ »\n", - "«q_4: ──■──┤ Rx(-π/2) ├┤ Rx(π/2) ├──■──────────────────────────────────────»\n", - "« └──────────┘└─────────┘ »\n", - "« ┌───┐┌───┐ ┌───┐ ┌───┐ ┌───┐┌───┐┌─────────┐┌───┐┌───┐»\n", - "«q_0: ─────┤ X ├┤ X ├───┤ H ├───────┤ H ├───┤ X ├┤ X ├┤ Rz(π/4) ├┤ X ├┤ X ├»\n", - "« ┌───┐└─┬─┘└─┬─┘ └───┘ └───┘ └─┬─┘└─┬─┘└─────────┘└─┬─┘└─┬─┘»\n", - "«q_1: ┤ H ├──┼────┼───────────────────────────┼────■───────────────■────┼──»\n", - "« ├───┤ │ │ │ │ »\n", - "«q_2: ┤ H ├──┼────┼───────────────────────────┼─────────────────────────┼──»\n", - "« └───┘ │ │ ┌─────────┐ │ │ »\n", - "«q_3: ───────■────┼──┤ Rx(π/2) ├──────────────┼─────────────────────────┼──»\n", - "« │ ├─────────┴┐┌─────────┐ │ │ »\n", - "«q_4: ────────────■──┤ Rx(-π/2) ├┤ Rx(π/2) ├──■─────────────────────────■──»\n", - "« └──────────┘└─────────┘ »\n", - "« ┌───┐ ┌───┐ ┌───┐┌───┐┌─────────┐┌───┐┌───┐ ┌───┐ \n", - "«q_0: ───┤ H ├───────┤ H ├───┤ X ├┤ X ├┤ Rz(π/2) ├┤ X ├┤ X ├───┤ H ├────\n", - "« └───┘ └───┘ └─┬─┘└─┬─┘└─────────┘└─┬─┘└─┬─┘ └───┘ \n", - "«q_1: ─────────────────────────┼────┼───────────────┼────┼──────────────\n", - "« │ │ │ │ \n", - "«q_2: ─────────────────────────┼────┼───────────────┼────┼──────────────\n", - "« │ │ │ │ ┌──────────┐\n", - "«q_3: ─────────────────────────┼────■───────────────■────┼──┤ Rx(-π/2) ├\n", - "« ┌──────────┐┌─────────┐ │ │ ├──────────┤\n", - "«q_4: ┤ Rx(-π/2) ├┤ Rx(π/2) ├──■─────────────────────────■──┤ Rx(-π/2) ├\n", - "« └──────────┘└─────────┘ └──────────┘\n" - ] - } - ], "source": [ "print(pp.to_qiskit())" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -372,113 +177,18 @@ "execution_count": 7, "id": "774fb7c8", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ┌───┐ »\n", - "q_0: ───┤ H ├─────────────────────────────────────────────────────────────────»\n", - " ├───┤ »\n", - "q_1: ───┤ H ├─────────────────────────────────────────────────────────────────»\n", - " ├───┤ ┌───┐┌───────┐┌───┐┌───┐ »\n", - "q_2: ───┤ H ├────────┤ X ├┤ Rz(π) ├┤ X ├┤ H ├─────────────────────────────────»\n", - " └───┘ ┌───┐└─┬─┘└───────┘└─┬─┘├───┤ ┌───┐»\n", - "q_3: ───────────┤ X ├──■─────────────■──┤ X ├─────────────────────────■──┤ X ├»\n", - " ┌─────────┐└─┬─┘ └─┬─┘┌──────────┐┌─────────┐┌─┴─┐└─┬─┘»\n", - "q_4: ┤ Rx(π/2) ├──■───────────────────────■──┤ Rx(-π/2) ├┤ Rx(π/2) ├┤ X ├──■──»\n", - " └─────────┘ └──────────┘└─────────┘└───┘ »\n", - "« ┌───┐┌─────────┐┌───┐┌───┐┌───┐ »\n", - "«q_0: ───────────────┤ X ├┤ Rz(π/2) ├┤ X ├┤ H ├┤ H ├───────────────────────────»\n", - "« ┌───┐└─┬─┘└─────────┘└─┬─┘├───┤├───┤ »\n", - "«q_1: ──────────┤ X ├──■───────────────■──┤ X ├┤ H ├───────────────────────────»\n", - "« ┌───┐└─┬─┘ └─┬─┘├───┤ »\n", - "«q_2: ──■──┤ X ├──■─────────────────────────■──┤ X ├──■────────────────────────»\n", - "« ┌─┴─┐└─┬─┘ └─┬─┘┌─┴─┐┌───┐ »\n", - "«q_3: ┤ X ├──■───────────────────────────────────■──┤ X ├┤ X ├──■──────────────»\n", - "« └───┘ └───┘└─┬─┘┌─┴─┐┌──────────┐»\n", - "«q_4: ─────────────────────────────────────────────────────■──┤ X ├┤ Rx(-π/2) ├»\n", - "« └───┘└──────────┘»\n", - "« ┌───┐┌───────────┐┌───┐┌───┐┌───┐»\n", - "«q_0: ────────────────────────────────────┤ X ├┤ Rz(π/256) ├┤ X ├┤ H ├┤ H ├»\n", - "« ┌───┐└─┬─┘└───────────┘└─┬─┘├───┤└───┘»\n", - "«q_1: ────────────────────────────■──┤ X ├──■─────────────────■──┤ X ├──■──»\n", - "« ┌───┐┌─┴─┐└─┬─┘ └─┬─┘┌─┴─┐»\n", - "«q_2: ──────────────────■──┤ X ├┤ X ├──■───────────────────────────■──┤ X ├»\n", - "« ┌───┐┌─┴─┐└─┬─┘└───┘ └───┘»\n", - "«q_3: ───────────┤ X ├┤ X ├──■─────────────────────────────────────────────»\n", - "« ┌─────────┐└─┬─┘└───┘ »\n", - "«q_4: ┤ Rx(π/2) ├──■───────────────────────────────────────────────────────»\n", - "« └─────────┘ »\n", - "« ┌───┐┌─────────┐»\n", - "«q_0: ─────────────────────────────────────────────────────┤ X ├┤ Rz(π/8) ├»\n", - "« ┌───┐ ┌───┐└─┬─┘└─────────┘»\n", - "«q_1: ┤ H ├───────────────────────────────────────────┤ X ├──■─────────────»\n", - "« ├───┤ ┌───┐ ┌───┐└─┬─┘ »\n", - "«q_2: ┤ X ├──■──┤ H ├────────────────────────────┤ X ├──■──────────────────»\n", - "« └─┬─┘┌─┴─┐├───┤ ┌───┐└─┬─┘ »\n", - "«q_3: ──■──┤ X ├┤ X ├───────────────────────┤ X ├──■───────────────────────»\n", - "« └───┘└─┬─┘┌──────────┐┌─────────┐└─┬─┘ »\n", - "«q_4: ────────────■──┤ Rx(-π/2) ├┤ Rx(π/2) ├──■────────────────────────────»\n", - "« └──────────┘└─────────┘ »\n", - "« ┌───┐┌───┐┌───┐ ┌───┐»\n", - "«q_0: ┤ X ├┤ H ├┤ H ├─────────────────────────────────────────────────────┤ X ├»\n", - "« └─┬─┘├───┤├───┤ ┌───┐└─┬─┘»\n", - "«q_1: ──■──┤ X ├┤ H ├────────────────────────────────────────────────┤ X ├──■──»\n", - "« └─┬─┘├───┤┌───┐ ┌───┐└─┬─┘ »\n", - "«q_2: ───────■──┤ X ├┤ H ├───────────────────────────────────■──┤ X ├──■───────»\n", - "« └─┬─┘├───┤ ┌───┐┌─┴─┐└─┬─┘ »\n", - "«q_3: ────────────■──┤ X ├─────────────────────────■──┤ X ├┤ X ├──■────────────»\n", - "« └─┬─┘┌──────────┐┌─────────┐┌─┴─┐└─┬─┘└───┘ »\n", - "«q_4: ─────────────────■──┤ Rx(-π/2) ├┤ Rx(π/2) ├┤ X ├──■──────────────────────»\n", - "« └──────────┘└─────────┘└───┘ »\n", - "« ┌─────────┐┌───┐┌───┐┌───┐ »\n", - "«q_0: ┤ Rz(π/4) ├┤ X ├┤ H ├┤ H ├───────────────────────────────────────────»\n", - "« └─────────┘└─┬─┘├───┤└───┘ »\n", - "«q_1: ─────────────■──┤ X ├────────────────────────────────────────────────»\n", - "« └─┬─┘┌───┐ »\n", - "«q_2: ──────────────────■──┤ X ├──■────────────────────────────────────────»\n", - "« └─┬─┘┌─┴─┐┌───┐ ┌─────────┐ ┌───┐»\n", - "«q_3: ───────────────────────■──┤ X ├┤ X ├──■──┤ Rx(π/2) ├────────────┤ X ├»\n", - "« └───┘└─┬─┘┌─┴─┐├─────────┴┐┌─────────┐└─┬─┘»\n", - "«q_4: ─────────────────────────────────■──┤ X ├┤ Rx(-π/2) ├┤ Rx(π/2) ├──■──»\n", - "« └───┘└──────────┘└─────────┘ »\n", - "« ┌───┐┌─────────┐┌───┐┌───┐ »\n", - "«q_0: ────────────────────┤ X ├┤ Rz(π/2) ├┤ X ├┤ H ├────────────────────»\n", - "« ┌───┐└─┬─┘└─────────┘└─┬─┘├───┤ »\n", - "«q_1: ────────────■──┤ X ├──■───────────────■──┤ X ├──■─────────────────»\n", - "« ┌───┐┌─┴─┐└─┬─┘ └─┬─┘┌─┴─┐┌───┐ »\n", - "«q_2: ──■──┤ X ├┤ X ├──■─────────────────────────■──┤ X ├┤ X ├──■───────»\n", - "« ┌─┴─┐└─┬─┘└───┘ └───┘└─┬─┘┌─┴─┐┌───┐»\n", - "«q_3: ┤ X ├──■─────────────────────────────────────────────■──┤ X ├┤ X ├»\n", - "« └───┘ └───┘└─┬─┘»\n", - "«q_4: ───────────────────────────────────────────────────────────────■──»\n", - "« »\n", - "« \n", - "«q_0: ────────────\n", - "« \n", - "«q_1: ────────────\n", - "« \n", - "«q_2: ────────────\n", - "« ┌──────────┐\n", - "«q_3: ┤ Rx(-π/2) ├\n", - "« ├──────────┤\n", - "«q_4: ┤ Rx(-π/2) ├\n", - "« └──────────┘\n" - ] - } - ], "source": [ "print(pp.to_qiskit(Topology.line(pp.num_qubits)))" - ] + ], + "outputs": [] }, { "cell_type": "code", "execution_count": null, "id": "a674d6c8", "metadata": {}, - "outputs": [], - "source": [] + "source": [], + "outputs": [] } ], "metadata": { diff --git a/notebooks/7. Tableaus.ipynb b/notebooks/7. Tableaus.ipynb index f714a147..855033d2 100644 --- a/notebooks/7. Tableaus.ipynb +++ b/notebooks/7. Tableaus.ipynb @@ -5,7 +5,6 @@ "execution_count": 1, "id": "5897e427-ba10-44b9-a36b-b0f6eab99539", "metadata": {}, - "outputs": [], "source": [ "from pauliopt.clifford.tableau import CliffordTableau\n", "import qiskit\n", @@ -15,7 +14,8 @@ "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "import numpy as np" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -49,25 +49,12 @@ "execution_count": 2, "id": "2c5d9a64-89ee-4a41-9d6a-a7d0427d4408", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "X/Z I/I I/I I/I I/I | + \n", - "I/I X/Z I/I I/I I/I | + \n", - "I/I I/I X/Z I/I I/I | + \n", - "I/I I/I I/I X/Z I/I | + \n", - "I/I I/I I/I I/I X/Z | + \n", - "\n" - ] - } - ], "source": [ "ct = CliffordTableau(5)\n", "\n", "print(ct)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -82,75 +69,36 @@ "execution_count": 3, "id": "22484d08-76cb-495a-9166-3f0d7f196ca0", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Z/X I/I I/I I/I I/I | + \n", - "I/I X/Z I/I I/I I/I | + \n", - "I/I I/I X/Z I/I I/I | + \n", - "I/I I/I I/I X/Z I/I | + \n", - "I/I I/I I/I I/I X/Z | + \n", - "\n" - ] - } - ], "source": [ "ct.append_h(0)\n", "\n", "print(ct)" - ] + ], + "outputs": [] }, { "cell_type": "code", "execution_count": 4, "id": "c8ce6f29-14aa-4ea8-9e2e-2ea1bcd1bf5c", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Z/X X/I I/I I/I I/I | + \n", - "I/X X/Z I/I I/I I/I | + \n", - "I/I I/I X/Z I/I I/I | + \n", - "I/I I/I I/I X/Z I/I | + \n", - "I/I I/I I/I I/I X/Z | + \n", - "\n" - ] - } - ], "source": [ "ct.prepend_cnot(0, 1)\n", "\n", "print(ct)" - ] + ], + "outputs": [] }, { "cell_type": "code", "execution_count": 5, "id": "44106b1d-fff9-49a1-9edf-d6c2b790565b", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Y/X X/I I/I I/I I/I | - \n", - "I/X X/Z I/I I/I I/I | + \n", - "I/I I/I X/Z I/I I/I | + \n", - "I/I I/I I/I X/Z I/I | + \n", - "I/I I/I I/I I/I X/Z | + \n", - "\n" - ] - } - ], "source": [ "ct.prepend_s(0)\n", "\n", "print(ct)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -165,51 +113,20 @@ "execution_count": 6, "id": "fdeb3e45-e4bf-409e-bcd8-b41ed8455d57", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[1, 1, 0, 0, 0, 1, 0, 0, 0, 0],\n", - " [0, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n", - " [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],\n", - " [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],\n", - " [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],\n", - " [1, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n", - " [1, 0, 0, 0, 0, 0, 1, 0, 0, 0],\n", - " [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],\n", - " [0, 0, 0, 0, 0, 0, 0, 0, 1, 0],\n", - " [0, 0, 0, 0, 0, 0, 0, 0, 0, 1]], dtype=uint8)" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "ct.tableau" - ] + ], + "outputs": [] }, { "cell_type": "code", "execution_count": 7, "id": "4174ecb7-a4d4-4a9a-9707-46f885d1014d", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=uint8)" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "ct.signs" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -230,7 +147,6 @@ "execution_count": 8, "id": "ea27fe40-fe38-43bf-a029-b0edb984ae53", "metadata": {}, - "outputs": [], "source": [ "def tableau_from_circuit(tableau, circ):\n", " qreg = circ.qregs[0]\n", @@ -246,27 +162,14 @@ " raise TypeError(\n", " f\"Unrecongnized Gate type: {op.operation.name} for Clifford Tableaus\")\n", " return tableau\n" - ] + ], + "outputs": [] }, { "cell_type": "code", "execution_count": 9, "id": "2153ff91-82c9-41ed-b82e-dc19c23da2c9", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Z/I X/X I/Z Z/X X/I | + \n", - "X/X X/Z Y/Z Y/Z I/I | - \n", - "I/I Y/X X/X I/Z Y/I | - \n", - "Z/Z Y/Z Z/I Z/Y Z/X | + \n", - "Y/X Y/I X/I X/I Y/Y | + \n", - "\n" - ] - } - ], "source": [ "n_qubits = 5\n", "\n", @@ -275,7 +178,8 @@ "ct = CliffordTableau(n_qubits)\n", "ct = tableau_from_circuit(ct, tableau.to_circuit())\n", "print(ct)" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -290,25 +194,14 @@ "execution_count": 10, "id": "382518df-ddd8-405f-90f1-cfef98f3b1a8", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Topology(5, [{3, 4}, {0, 1}, {2, 3}, {1, 2}])" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "from pauliopt.topologies import Topology\n", "\n", "topo = Topology.line(n_qubits)\n", "\n", "topo" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -325,61 +218,6 @@ "execution_count": 11, "id": "2b251361-989b-42fd-942b-bd057ea1f1e3", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[3, 4], [0, 1], [2, 3], [1, 2]]\n", - " ┌───┐┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ »\n", - "q_0 -> 0 ┤ H ├┤ H ├──■──┤ H ├──■──┤ H ├──■──┤ H ├──■──┤ H ├────────────────────»\n", - " ├───┤├───┤┌─┴─┐├───┤┌─┴─┐├───┤┌─┴─┐├───┤┌─┴─┐├───┤ »\n", - "q_1 -> 1 ┤ S ├┤ H ├┤ X ├┤ H ├┤ X ├┤ H ├┤ X ├┤ H ├┤ X ├┤ H ├────────────────────»\n", - " ├───┤└───┘└───┘└───┘├───┤├───┤├───┤├───┤└───┘├───┤ ┌───┐ ┌───┐»\n", - "q_2 -> 2 ┤ H ├────────────■──┤ H ├┤ S ├┤ H ├┤ S ├──■──┤ H ├──■──┤ H ├──■──┤ H ├»\n", - " ├───┤┌───┐┌───┐┌─┴─┐├───┤├───┤└───┘├───┤┌─┴─┐├───┤┌─┴─┐├───┤┌─┴─┐└───┘»\n", - "q_3 -> 3 ┤ H ├┤ S ├┤ H ├┤ X ├┤ H ├┤ H ├──■──┤ H ├┤ X ├┤ H ├┤ X ├┤ H ├┤ X ├──■──»\n", - " ├───┤└───┘└───┘└───┘└───┘└───┘┌─┴─┐├───┤├───┤└───┘└───┘└───┘└───┘┌─┴─┐»\n", - "q_4 -> 4 ┤ H ├─────────────────────────┤ X ├┤ H ├┤ H ├────────────────────┤ X ├»\n", - " └───┘ └───┘└───┘└───┘ └───┘»\n", - "« ┌───┐┌───┐ ┌───┐ ┌───┐ »\n", - "«q_0 -> 0 ──────────────────────■──┤ H ├┤ S ├──■──┤ H ├──■──┤ H ├──■───────»\n", - "« ┌───┐ ┌───┐┌─┴─┐├───┤└───┘┌─┴─┐├───┤┌─┴─┐├───┤┌─┴─┐ »\n", - "«q_1 -> 1 ──■──┤ H ├──■──┤ H ├┤ X ├┤ H ├─────┤ X ├┤ H ├┤ X ├┤ H ├┤ X ├──■──»\n", - "« ┌─┴─┐├───┤┌─┴─┐└───┘└───┘└───┘ └───┘└───┘└───┘└───┘└───┘┌─┴─┐»\n", - "«q_2 -> 2 ┤ X ├┤ H ├┤ X ├─────────────────────────────────────────────┤ X ├»\n", - "« ├───┤└───┘└───┘ └───┘»\n", - "«q_3 -> 3 ┤ H ├────────────────────────────────────────────────────────────»\n", - "« ├───┤┌───┐┌───┐ »\n", - "«q_4 -> 4 ┤ S ├┤ H ├┤ H ├──────────────────────────────────────────────────»\n", - "« └───┘└───┘└───┘ »\n", - "« »\n", - "«q_0 -> 0 ─────────────────────────────────────────────────────────────────»\n", - "« ┌───┐ ┌───┐┌───┐┌───┐ ┌───┐»\n", - "«q_1 -> 1 ┤ H ├──────────────────────■──┤ H ├┤ S ├┤ H ├────────────■──┤ H ├»\n", - "« ├───┤ ┌───┐ ┌───┐┌─┴─┐├───┤├───┤├───┤┌───┐┌───┐┌─┴─┐├───┤»\n", - "«q_2 -> 2 ┤ H ├──■──┤ H ├──■──┤ H ├┤ X ├┤ H ├┤ H ├┤ S ├┤ S ├┤ H ├┤ X ├┤ H ├»\n", - "« └───┘┌─┴─┐├───┤┌─┴─┐└───┘└───┘└───┘└───┘└───┘└───┘└───┘└───┘└───┘»\n", - "«q_3 -> 3 ─────┤ X ├┤ H ├┤ X ├─────────────────────────────────────────────»\n", - "« └───┘└───┘└───┘ »\n", - "«q_4 -> 4 ─────────────────────────────────────────────────────────────────»\n", - "« »\n", - "« \n", - "«q_0 -> 0 ─────────────────────────────────────────────\n", - "« ┌───┐ \n", - "«q_1 -> 1 ──■──┤ H ├──■────────────────────────────────\n", - "« ┌─┴─┐├───┤┌─┴─┐ ┌───┐┌───┐┌───┐┌───┐┌───┐\n", - "«q_2 -> 2 ┤ X ├┤ H ├┤ X ├──■──┤ H ├┤ H ├┤ S ├┤ S ├┤ H ├\n", - "« └───┘└───┘└───┘┌─┴─┐├───┤└───┘├───┤└───┘└───┘\n", - "«q_3 -> 3 ───────────────┤ X ├┤ H ├──■──┤ H ├──────────\n", - "« └───┘└───┘┌─┴─┐├───┤┌───┐ \n", - "«q_4 -> 4 ─────────────────────────┤ X ├┤ H ├┤ H ├─────\n", - "« └───┘└───┘└───┘ \n", - "Operations: OrderedDict([('h', 60), ('cx', 25), ('s', 11)])\n", - "Depth: 49\n" - ] - } - ], "source": [ "couplings = [[i, j] for i, j in topo.couplings]\n", "print(couplings)\n", @@ -394,7 +232,8 @@ "print(qc)\n", "print(\"Operations: \", qc.count_ops())\n", "print(\"Depth: \", qc.depth())" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -409,59 +248,16 @@ "execution_count": 12, "id": "a454549c-f43f-4ae2-aaec-ceec61e71688", "metadata": {}, - "outputs": [], "source": [ "from pauliopt.clifford.tableau_synthesis import synthesize_tableau" - ] + ], + "outputs": [] }, { "cell_type": "code", "execution_count": 13, "id": "015b1352-346c-4f0b-931c-74feb7dc2598", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ┌───┐ ┌───┐ »\n", - "q_0: ┤ X ├──■──────────────────────────────────────────┤ X ├───────■───────»\n", - " └─┬─┘┌─┴─┐ ┌───┐└─┬─┘ ┌─┴─┐┌───┐»\n", - "q_1: ──■──┤ X ├───────■───────────────────────────┤ X ├──■────■──┤ X ├┤ H ├»\n", - " ┌───┐├───┤┌───┐┌─┴─┐ ┌───┐└─┬─┘ ┌─┴─┐├───┤└───┘»\n", - "q_2: ┤ H ├┤ X ├┤ H ├┤ X ├───────■────────────┤ X ├──■────■──┤ X ├┤ X ├──■──»\n", - " ├───┤└─┬─┘├───┤├───┤┌───┐┌─┴─┐ ┌───┐└─┬─┘ ┌─┴─┐├───┤└─┬─┘┌─┴─┐»\n", - "q_3: ┤ H ├──■──┤ X ├┤ S ├┤ H ├┤ X ├──■──┤ H ├──■───────┤ X ├┤ H ├──■──┤ X ├»\n", - " ├───┤ └─┬─┘├───┤├───┤├───┤┌─┴─┐└───┘ └───┘└───┘ └───┘»\n", - "q_4: ┤ S ├───────■──┤ S ├┤ H ├┤ S ├┤ X ├───────────────────────────────────»\n", - " └───┘ └───┘└───┘└───┘└───┘ »\n", - "« ┌───┐ »\n", - "«q_0: ┤ X ├─────────────────────────────────────────────────────────────────»\n", - "« └─┬─┘┌───┐ ┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐ »\n", - "«q_1: ──■──┤ H ├──■──┤ S ├┤ H ├┤ S ├┤ X ├┤ H ├┤ S ├┤ S ├┤ H ├───────────────»\n", - "« └───┘┌─┴─┐├───┤├───┤└───┘└─┬─┘├───┤└───┘├───┤├───┤┌───┐┌───┐┌───┐»\n", - "«q_2: ──────────┤ X ├┤ H ├┤ X ├───────■──┤ H ├──■──┤ S ├┤ H ├┤ S ├┤ X ├┤ H ├»\n", - "« ┌───┐ └───┘└───┘└─┬─┘ └───┘┌─┴─┐└───┘└───┘└───┘└─┬─┘├───┤»\n", - "«q_3: ┤ H ├─────────────────■─────────────────┤ X ├─────────────────■──┤ S ├»\n", - "« └───┘ └───┘ └───┘»\n", - "«q_4: ──────────────────────────────────────────────────────────────────────»\n", - "« »\n", - "« \n", - "«q_0: ───────────────\n", - "« \n", - "«q_1: ───────────────\n", - "« ┌───┐┌───┐┌───┐\n", - "«q_2: ┤ S ├┤ S ├┤ H ├\n", - "« └───┘└───┘└───┘\n", - "«q_3: ───────────────\n", - "« \n", - "«q_4: ───────────────\n", - "« \n", - "Operations: OrderedDict([('cx', 21), ('h', 18), ('s', 13)])\n", - "Depth: 31\n" - ] - } - ], "source": [ "qc_po, _ = synthesize_tableau(ct, topo, include_swaps=False)\n", "qc_po = qc_po.to_qiskit()\n", @@ -469,25 +265,18 @@ "print(qc_po)\n", "print(\"Operations: \", qc_po.count_ops())\n", "print(\"Depth: \", qc_po.depth())" - ] + ], + "outputs": [] }, { "cell_type": "code", "execution_count": 14, "id": "bc6b3fb4-4a2e-4995-9114-89ff21041f81", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Circuits Match: True\n" - ] - } - ], "source": [ "print(\"Circuits Match: \", Operator.from_circuit(qc_po).equiv(Operator.from_circuit(inital_circuit)))" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -514,55 +303,14 @@ "execution_count": 15, "id": "11b72639-a5c9-4416-b295-8ae1e4888a29", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ┌───┐ ┌───┐ ┌───┐┌───┐ »\n", - "q_0: ────────────■──┤ X ├───────■────────────┤ X ├──■──┤ S ├┤ X ├──────────»\n", - " ┌───┐ │ └─┬─┘┌───┐ │ ┌───┐ └─┬─┘┌─┴─┐└───┘└─┬─┘┌───┐ »\n", - "q_1: ┤ S ├──■────┼────■──┤ X ├──┼──┤ H ├───────┼──┤ X ├──■────┼──┤ H ├─────»\n", - " └───┘┌─┴─┐ │ └─┬─┘ │ ├───┤┌───┐ │ ├───┤┌─┴─┐ │ ├───┤┌───┐»\n", - "q_2: ─────┤ X ├──┼─────────■────┼──┤ S ├┤ H ├──┼──┤ S ├┤ X ├──┼──┤ H ├┤ S ├»\n", - " ┌───┐└───┘┌─┴─┐ ┌─┴─┐├───┤└───┘ │ └───┘└───┘ │ ├───┤├───┤»\n", - "q_3: ┤ H ├─────┤ X ├──■───────┤ X ├┤ X ├───────■────■─────────■──┤ X ├┤ H ├»\n", - " └───┘ └───┘┌─┴─┐ └───┘└─┬─┘ ┌─┴─┐ └─┬─┘└───┘»\n", - "q_4: ───────────────┤ X ├────────────■────────────┤ X ├────────────■───────»\n", - " └───┘ └───┘ »\n", - "« ┌───┐ ┌───┐┌───┐ ┌───┐┌───┐┌───┐ »\n", - "«q_0: ───────■──┤ S ├──■───────┤ X ├┤ X ├────────────■──┤ X ├┤ S ├┤ H ├─────»\n", - "« │ └───┘┌─┴─┐┌───┐└─┬─┘└─┬─┘┌───┐ │ └─┬─┘├───┤├───┤┌───┐»\n", - "«q_1: ───────┼───────┤ X ├┤ H ├──┼────■──┤ S ├───────┼────■──┤ S ├┤ H ├┤ S ├»\n", - "« ┌───┐ │ ┌───┐├───┤├───┤ │ └───┘ │ └───┘└───┘└───┘»\n", - "«q_2: ┤ S ├──┼──┤ H ├┤ S ├┤ S ├──┼───────────────────┼──────────────────────»\n", - "« └───┘┌─┴─┐└───┘├───┤└───┘ │ ┌───┐┌───┐┌───┐┌─┴─┐┌───┐┌───┐ »\n", - "«q_3: ─────┤ X ├──■──┤ H ├───────■──┤ S ├┤ H ├┤ S ├┤ X ├┤ S ├┤ S ├──────────»\n", - "« └───┘┌─┴─┐├───┤┌───┐┌───┐├───┤└───┘└───┘└───┘└───┘└───┘ »\n", - "«q_4: ──────────┤ X ├┤ H ├┤ S ├┤ S ├┤ H ├───────────────────────────────────»\n", - "« └───┘└───┘└───┘└───┘└───┘ »\n", - "« ┌───┐┌───┐┌───┐┌───┐┌───┐ \n", - "«q_0: ──■──┤ H ├┤ H ├┤ S ├┤ S ├┤ H ├─────\n", - "« ┌─┴─┐├───┤├───┤├───┤├───┤├───┤┌───┐\n", - "«q_1: ┤ X ├┤ H ├┤ S ├┤ S ├┤ H ├┤ S ├┤ S ├\n", - "« └───┘└───┘└───┘└───┘└───┘└───┘└───┘\n", - "«q_2: ───────────────────────────────────\n", - "« \n", - "«q_3: ───────────────────────────────────\n", - "« \n", - "«q_4: ───────────────────────────────────\n", - "« \n", - "OrderedDict([('s', 25), ('cx', 21), ('h', 19)])\n" - ] - } - ], "source": [ "qc_po, _ = synthesize_tableau(ct, topo, include_swaps=True)\n", "qc_po = qc_po.to_qiskit()\n", "\n", "print(qc_po)\n", "print(qc_po.count_ops())\n" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -581,7 +329,6 @@ "execution_count": 16, "id": "cbb5a60f-dd4d-4ef6-ba21-03299e6980af", "metadata": {}, - "outputs": [], "source": [ "def random_clifford_circuit(nr_gates=20, nr_qubits=4, gate_choice=None):\n", " qc = QuantumCircuit(nr_qubits)\n", @@ -653,14 +400,14 @@ "\n", " column = get_ops_count(circ_out)\n", " return column" - ] + ], + "outputs": [] }, { "cell_type": "code", "execution_count": 17, "id": "4dc25ce4-4982-4363-bdd6-a760c4941417", "metadata": {}, - "outputs": [], "source": [ "# see our paper for an outline of all connectivity graphs.\n", "guadalupe_connectivity = [[0, 1], [1, 0], [1, 2], [1, 4], [2, 1], [2, 3], [3, 2], [3, 5], [4, 1], [4, 7], [5, 3], [5, 8], [6, 7], [7, 4], [7, 6], [7, 10], [8, 5], [8, 9], [8, 11], [9, 8], [10, 7], [10, 12], [11, 8], [11, 14], [12, 10], [12, 13], [12, 15], [13, 12], [13, 14], [14, 11], [14, 13], [15, 12]]\n", @@ -668,14 +415,14 @@ "topo = Topology.from_dict({\n", " \"num_qubits\": 16,\n", " \"couplings\": guadalupe_connectivity})" - ] + ], + "outputs": [] }, { "cell_type": "code", "execution_count": 18, "id": "d5bce23e-52ef-4cfd-a10c-141d13eebac8", "metadata": {}, - "outputs": [], "source": [ "df = pd.DataFrame(columns=[\"n_rep\", \"nr_gates\", \"method\", \"h\", \"s\", \"cx\", \"depth\"])\n", "\n", @@ -690,55 +437,14 @@ " column = {\"n_rep\": _, \"nr_gates\": num_gates, \"method\": \"qiskit\"} | qiskit_compilation(circ, topo)\n", "\n", " df.loc[len(df)] = column\n" - ] + ], + "outputs": [] }, { "cell_type": "code", "execution_count": 19, "id": "4080f94d-fbb0-41cd-b1cf-6a627ae030bb", "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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q5e2fv16r8/at2+fNnLkSC0kJESLi4vT7rnnHu38+fOe8zfccIM2ZcoU7bHHHtOio6O1YcOGVXi/DodDmzdvntamTRvNaDRqffv21b7++mvPecrstzVnzpwKr3PDDTdojz32mOd1UlKS9uKLL2oTJ07UQkNDtXbt2ml//vOfa3SfH330kRYREeH1OaV/Dh999FGVe6GV9uCDD2ohISHamTNnKjzvdDo9z//6179q/fv310JDQ7X4+Hjt7rvv1jIzM736DeX33HM4HNpLL72kdejQQQsMDNSuvPJK7Z///KfnutnZ2drvfvc7LSYmRgsMDNQ6d+7s9bMXoqmTESIhmhmDwcBLL73E22+/zenTpy/rWmvXruXs2bNs3LiR119/nTlz5vCrX/2KVq1asXXrVv7whz/w4IMPlvuc6dOn8+STT7J7926Sk5MZPXo0Fy9eBCA3N5ebbrqJq666ih07drBq1SoyMzO58847va6xbNkyjEYjP/74I0uWLKmwf2+99RavvfYar776Knv37iU1NZVf//rXHD16FIBz587Rq1cvnnzySc6dO8dTTz3l872/9tprDBgwgN27d/Pwww/z0EMPcfjwYZ/vszp33XUXTz75JL169eLcuXOcO3eOu+66q1w7p9PJ3//+d+655x4SExMrvFbp6VCbzcYLL7zATz/9xFdffcWJEye47777AGjXrh1ffPEFAIcPH+bcuXO89dZbAMyfP5+//vWvLFmyhAMHDvDEE09wzz33sGHDBgCee+45fv75Z77++msOHjzI4sWLiYmJ8elehWgSGjoiE0LUHveojqZp2uDBg7X7779f07RLHyFKSkrSHA6H51i3bt2066+/3vPabrdrISEh2meffaZpWskIxIIFCzxtbDab1rZtW+3ll1/WNE3TXnjhBW3EiBFen33q1CkN0A4fPqxpmhqxueqqq6q938TERO3FF1/0OnbNNddoDz/8sOd13759Kx0ZcqtohOiee+7xvHY6nVpcXJy2ePFin++zuhEiTav451BWRkaGBmivv/661/Grr75aCwkJ0UJCQrRx48ZV+v7t27drgJaXl6dpmqatW7dOA7ScnBxPm+LiYi04OFjbtGmT13snTZqk3X333Zqmadro0aO1iRMnVtlXIZoyGSESopl6+eWXWbZsGQcPHrzka/Tq1Qu9vuSvifj4ePr06eN5bTAYiI6OJisry+t9ycnJnud+fn4MGDDA04+ffvqJdevWERoa6nl0794dUPk+bv3796+yb2azmbNnzzJkyBCv40OGDLmse3a78sorPc91Oh0JCQk1us+6tnz5cvbs2UNqaipFRUWe4zt37mT06NG0b9+esLAwbrjhBgDS09MrvdaxY8coLCzk5ptv9vq5/PWvf/X8TB566CE+//xz+vXrx9NPP82mTZvq9gaFqGd+Dd0BIUTdGDp0KKmpqcyaNcszZeKm1+vRNM3rmM1mK3cNf39/r9c6na7CY06n0+d+5efnM3r0aF5++eVy51q3bu15HhIS4vM168Ll3qevv8fViY2NJTIystx0Xfv27QEICwvzrBgrKCggNTWV1NRUPvnkE2JjY0lPTyc1NbXKxPT8/HwA/vvf/9KmTRuvcwEBAQCMGjWKkydP8r///Y/Vq1czfPhwpkyZwquvvlrjexKiMZIRIiGasQULFrBixQo2b97sdTw2NpaMjAyvL+zarB20ZcsWz3O73c7OnTvp0aMHAFf//3buHqRxOAwD+KOFCIIiShAsYgsKthALN9RJ0UW6C4oIiq4Vv4UqKFVBoy5iqYOCtBCs4lAs9Wu3CBW0CIUKRsXBpX4M6uBQ7gY5ofaId1C4O/P8oEv4hzdvujy8/yTfviEej8NkMqGysjLt9ychqLCwEGVlZYhEImnHI5EIrFZrdhr5hFafoiji6ekJLy8v72s+3mNBEJBKpTRr5ObmoqWlBYqi4Pb2VnNtIpHA/f09ZFlGXV0dqqurM6ZagiAAQFpdq9WKvLw83NzcZPwn5eXl7+tEUURnZycURcHi4iJWVlY0r4fof8JARPSFSZKE9vZ2LC0tpR1vaGhAMpnE/Pw8VFWF1+vF3t5e1up6vV4Eg0EkEgk4nU48Pj6iu7sbAOB0OvHw8IC2tjYcHx9DVVUcHBygq6vr03Dw0cjICObm5rC5uYnz83O4XC7EYjH09fVlrRctWn3W1tYiPz8fY2NjUFUV6+vr8Pl8aeebTCZcXV0hFovh7u4Or6+vv6wzMzMDo9EIu92OtbU1nJ2dQVVVBINBHB0dwWAwAHibGgmCAI/Hg8vLS4RCoYzvK1VUVCAnJwfhcBjJZBLPz88oKCjA8PAwBgYG4Pf7oaoqTk5O4PF44Pf7AQATExPY3t7GxcUF4vE4wuHwe/gj+goYiIi+uKmpqYytHovFguXlZXi9XthsNkSj0T96A+szsixDlmXYbDYcHh4iFAq9v5H0c6qTSqXQ1NQESZLQ39+PoqKitOeVfkdvby8GBwcxNDQESZKwv7+PUCiEqqqqrPWiRavP4uJiKIqC3d1dSJKEQCAAt9uddn5zczMcDgcaGxshiiICgcAv65SUlCAajaKjowMLCwuw2+2QJAlutxutra1YXV0F8DbB8fl82NragtVqhSzLGVtaRqMRk5OTcLlcKC0tRU9PDwBgenoa4+PjmJ2dhcVigcPhwM7ODsxmM4C3ydLo6ChqampQX18Pg8GAjY2NbN5Oor8q5/vHTW4iItJ0fX0Ns9mM09PT3/7SNBH92zghIiIiIt1jICIiIiLd45YZERER6R4nRERERKR7DERERESkewxEREREpHsMRERERKR7DERERESkewxEREREpHsMRERERKR7DERERESkewxEREREpHs/AHH7/dSFFMxTAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHHCAYAAABZbpmkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAC0g0lEQVR4nOydd5ycdbm3r+l9Z3tLNptNL4SETghCgEgVRVAPHlQEFEWqCEjviAQ5Ir4IiijYz1GKgPTeQiCEQEJ6sunb2/TylPeP32wj2d3ZsD339flMMk+/Z2Z3n+/c1WKapokgCIIgCMIYxTrcBgiCIAiCIAwmInYEQRAEQRjTiNgRBEEQBGFMI2JHEARBEIQxjYgdQRAEQRDGNCJ2BEEQBEEY04jYEQRBEARhTCNiRxAEQRCEMY2IHUEQBEEQxjQidgRBEARBGNOI2BEEYUhYuXIlX/va16isrMTtdjNu3Di++MUv8utf/zrrc1RXV3PRRRcxbdo0vF4vXq+XWbNmceGFF/LJJ5/slV3vvvsuN998M62trXt1vCAIIx+LzMYSBGGweffddznmmGOYMGECZ599NqWlpWzfvp333nuPTZs2sXHjxj7P8cwzz/Bf//Vf2O12zjrrLObOnYvVamXt2rU8/vjjbN26lerqaiorK/tl2y9+8QuuvPJKqqurmThx4l6+QkEQRjL24TZAEISxzx133EEwGOSDDz4gNze327b6+vo+j9+0aRNnnnkmlZWVvPLKK5SVlXXbftddd/Gb3/wGq1Wc1YIg7I78ZRAEYdDZtGkTs2fP3k3oABQXF/d5/OLFi4lGo/zxj3/cTegA2O12LrnkEioqKjrWffLJJ3z3u99l0qRJuN1uSktLOffcc2lqaurY5+abb+bKK68EoKqqCovFgsViYcuWLR37/OUvf+Gggw7C4/GQn5/PmWeeyfbt27tdf8OGDZxxxhmUlpbidrsZP348Z555Jm1tbX2+NkEQBh/x7AiCMOhUVlayZMkSVq1axX777dfv45955hmmTJnCYYcdlvUxL730Eps3b+acc86htLSUTz/9lN/97nd8+umnvPfee1gsFk4//XTWr1/P3//+d375y19SWFgIQFFREaA8UjfccAPf+MY3+N73vkdDQwO//vWvOeqoo/joo4/Izc0llUpxwgknkEwmufjiiyktLWXnzp0888wztLa2EgwG+/16BUEYYExBEIRB5sUXXzRtNptps9nM+fPnm1dddZX5wgsvmKlUqs9j29raTMA87bTTdtvW0tJiNjQ0dDxisVjHtq7P2/n73/9uAuabb77Zse7uu+82AbO6urrbvlu2bDFtNpt5xx13dFu/cuVK0263d6z/6KOPTMD85z//2edrEQRheJAwliAIg84Xv/hFlixZwpe//GU+/vhjFi9ezAknnMC4ceN46qmnej02FAoB4Pf7d9u2cOFCioqKOh73339/xzaPx9PxPJFI0NjYyOGHHw7A8uXL+7T58ccfxzAMvvGNb9DY2NjxKC0tZerUqbz22msAHZ6bF154gVgs1ud5BUEYekTsCIIwJBxyyCE8/vjjtLS08P7773PNNdcQDof52te+xurVq2lubqa2trbj0Z7vEggEAIhEIrud87e//S0vvfQSf/nLX3bb1tzczKWXXkpJSQkej4eioiKqqqoAssql2bBhA6ZpMnXq1G6CqqioiDVr1nQkVldVVXH55Zfz+9//nsLCQk444QTuv/9+ydcRhBGE5OwIgjCkOJ1ODjnkEA455BCmTZvGOeecwz//+U9ee+013njjjY79zj77bB555BGCwSBlZWWsWrVqt3O15/B0TShu5xvf+AbvvvsuV155JfPmzcPv92MYBieeeCKGYfRpp2EYWCwWnnvuOWw2227bu3qa7rnnHr773e/y73//mxdffJFLLrmEO++8k/fee4/x48dn87YIgjCIiNgRBGHYOPjggwGoqanhnnvuoaWlpWNbeXl5x/NTTjmF3//+97z//vsceuihfZ63paWFV155hVtuuYUbb7yxY/2GDRt229disezxHJMnT8Y0Taqqqpg2bVqf15wzZw5z5szh+uuv591332XBggU8+OCD3H777X0eKwjC4CJhLEEQBp3XXnsNcw/9S5999lkApk+fzkEHHcSiRYs6HrNmzerY76qrrsLr9XLuuedSV1e323k+e+52T8xn19977727Hevz+QB266B8+umnY7PZuOWWW3Y7j2maHSXsoVAITdO6bZ8zZw5Wq5VkMrnb9QRBGHrEsyMIwqBz8cUXE4vF+OpXv8qMGTNIpVK8++67/O///i8TJ07knHPO6fX4qVOn8re//Y1vfvObTJ8+vaODsmmaVFdX87e//Q2r1doRMsrJyeGoo45i8eLFpNNpxo0b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2REREZGApmSng4SGhjJnzhxCQ0N93ZROd77Gfr7GDedv7Odr3KDYz8fY/TluDVAWERGRgKY7OyIiIhLQlOyIiIhIQFOyIyIiIgFNyY6IiIgENCU7HWDRokX06NEDp9PJyJEj+fDDD33dpHb34IMPYrPZvB7Z2dme8vr6eqZNm0ZCQgKRkZFcc801lJWV+bDFZ2/dunVcccUVpKenY7PZeO2117zKjTE88MADpKWlERYWRn5+Pjt37vSqc+TIEa6//nqio6OJjY3lpptuoqamphOj+PbOFPfUqVNP+g5MmjTJq44/xj1//nyGDx9OVFQUycnJXHXVVRQVFXnVacv3e9++fXzve98jPDyc5ORkZs2ahcvl6sxQvrW2xD527NiTrvutt97qVccfY3/66acZNGiQZ8G8vLw83nnnHU95oF7zM8UdKNdbyU47e/nll5kxYwZz5szh448/ZvDgwUycOJGDBw/6umntbsCAAZSUlHge77//vqfsnnvu4c033+SVV15h7dq1HDhwgKuvvtqHrT17tbW1DB48mEWLFrVa/sgjj/DEE0/wzDPPsHHjRiIiIpg4cSL19fWeOtdffz3bt29nxYoVvPXWW6xbt45bbrmls0I4K2eKG2DSpEle34GXXnrJq9wf4167di3Tpk1jw4YNrFixgqamJiZMmEBtba2nzpm+383NzXzve9+jsbGRDz74gOeff54lS5bwwAMP+CKkNmtL7AA333yz13V/5JFHPGX+GntGRgYLFiygsLCQTZs2MW7cOK688kq2b98OBO41P1PcECDX20i7GjFihJk2bZrndXNzs0lPTzfz58/3Yava35w5c8zgwYNbLauoqDAhISHmlVde8Rz7/PPPDWAKCgo6qYUdAzDLli3zvHa73SY1NdU8+uijnmMVFRUmNDTUvPTSS8YYYz777DMDmI8++shT55133jE2m8189dVXndb2c/HNuI0xZsqUKebKK6885XsCIW5jjDl48KABzNq1a40xbft+v/3228Zut5vS0lJPnaefftpER0ebhoaGzg3gHHwzdmOMGTNmjLnrrrtO+Z5Aid0YY+Li4sxzzz13Xl1zY07EbUzgXG/d2WlHjY2NFBYWkp+f7zlmt9vJz8+noKDAhy3rGDt37iQ9PZ1evXpx/fXXs2/fPgAKCwtpamry+jtkZ2eTmZkZcH+H4uJiSktLvWKNiYlh5MiRnlgLCgqIjY1l2LBhnjr5+fnY7XY2btzY6W1uT2vWrCE5OZl+/fpx2223UV5e7ikLlLgrKysBiI+PB9r2/S4oKCA3N5eUlBRPnYkTJ1JVVeX1f8xd3Tdjb/HCCy+QmJjIwIEDmT17NnV1dZ6yQIi9ubmZpUuXUltbS15e3nlzzb8Zd4tAuN7aCLQdHT58mObmZq+LDpCSksKOHTt81KqOMXLkSJYsWUK/fv0oKSlh7ty5XHrppWzbto3S0lIcDgexsbFe70lJSaG0tNQ3De4gLfG0ds1bykpLS0lOTvYqDw4OJj4+3q//HpMmTeLqq6+mZ8+e7N69m1/96ldcfvnlFBQUEBQUFBBxu91u7r77bkaNGsXAgQMB2vT9Li0tbfU70VLmD1qLHeDHP/4xWVlZpKen8+mnn3LvvfdSVFTEq6++Cvh37Fu3biUvL4/6+noiIyNZtmwZ/fv3Z8uWLQF9zU8VNwTO9VayI2fl8ssv9zwfNGgQI0eOJCsri7/+9a+EhYX5sGXSWX70ox95nufm5jJo0CB69+7NmjVrGD9+vA9b1n6mTZvGtm3bvMajnS9OFfvXx1zl5uaSlpbG+PHj2b17N7179+7sZrarfv36sWXLFiorK/nb3/7GlClTWLt2ra+b1eFOFXf//v0D5nqrG6sdJSYmEhQUdNII/bKyMlJTU33Uqs4RGxvLBRdcwK5du0hNTaWxsZGKigqvOoH4d2iJ53TXPDU19aQB6i6XiyNHjgTU36NXr14kJiaya9cuwP/jnj59Om+99RbvvfceGRkZnuNt+X6npqa2+p1oKevqThV7a0aOHAngdd39NXaHw0GfPn0YOnQo8+fPZ/DgwfzhD38I+Gt+qrhb46/XW8lOO3I4HAwdOpRVq1Z5jrndblatWuXV/xmIampq2L17N2lpaQwdOpSQkBCvv0NRURH79u0LuL9Dz549SU1N9Yq1qqqKjRs3emLNy8ujoqKCwsJCT53Vq1fjdrs9/3AEgi+//JLy8nLS0tIA/43bGMP06dNZtmwZq1evpmfPnl7lbfl+5+XlsXXrVq9kb8WKFURHR3u6B7qiM8Xemi1btgB4XXd/jL01brebhoaGgL7mrWmJuzV+e719PUI60CxdutSEhoaaJUuWmM8++8zccsstJjY21mukeiCYOXOmWbNmjSkuLjbr1683+fn5JjEx0Rw8eNAYY8ytt95qMjMzzerVq82mTZtMXl6eycvL83Grz051dbXZvHmz2bx5swHMY489ZjZv3mz27t1rjDFmwYIFJjY21rz++uvm008/NVdeeaXp2bOnOXbsmOcckyZNMkOGDDEbN24077//vunbt6+57rrrfBVSm5wu7urqavOLX/zCFBQUmOLiYrNy5Upz0UUXmb59+5r6+nrPOfwx7ttuu83ExMSYNWvWmJKSEs+jrq7OU+dM32+Xy2UGDhxoJkyYYLZs2WKWL19ukpKSzOzZs30RUpudKfZdu3aZefPmmU2bNpni4mLz+uuvm169epnRo0d7zuGvsd93331m7dq1pri42Hz66afmvvvuMzabzbz77rvGmMC95qeLO5Cut5KdDvDkk0+azMxM43A4zIgRI8yGDRt83aR2N3nyZJOWlmYcDofp1q2bmTx5stm1a5en/NixY+b22283cXFxJjw83Pzwhz80JSUlPmzx2XvvvfcMcNJjypQpxhhr+vn9999vUlJSTGhoqBk/frwpKiryOkd5ebm57rrrTGRkpImOjjY33HCDqa6u9kE0bXe6uOvq6syECRNMUlKSCQkJMVlZWebmm28+Kan3x7hbixkwixcv9tRpy/d7z5495vLLLzdhYWEmMTHRzJw50zQ1NXVyNN/OmWLft2+fGT16tImPjzehoaGmT58+ZtasWaaystLrPP4Y+4033miysrKMw+EwSUlJZvz48Z5Ex5jAveanizuQrrfNGGM67z6SiIiISOfSmB0REREJaEp2REREJKAp2REREZGApmRHREREApqSHREREQloSnZEREQkoCnZERERkYCmZEdE2mzPnj3YbDbPkvFdwY4dO7j44otxOp1ceOGFrdYZO3Ysd999d6e2S0S6DiU7In5k6tSp2Gw2FixY4HX8tddew2az+ahVvjVnzhwiIiIoKiry2rvo61599VUeeuihTm4ZPPjgg6dMwNpbV0xERboKJTsifsbpdLJw4UKOHj3q66a0m8bGxrN+7+7du7nkkkvIysoiISGh1Trx8fFERUWd9WeIiH9TsiPiZ/Lz80lNTWX+/PmnrNPaHYXf//739OjRw/N66tSpXHXVVTz88MOkpKQQGxvLvHnzcLlczJo1i/j4eDIyMli8ePFJ59+xYwff+c53cDqdDBw4kLVr13qVb9u2jcsvv5zIyEhSUlL493//dw4fPuwpHzt2LNOnT+fuu+8mMTGRiRMnthqH2+1m3rx5ZGRkEBoayoUXXsjy5cs95TabjcLCQubNm4fNZuPBBx9s9Tzf7Mbq0aMHDz/8MDfeeCNRUVFkZmby5z//2VPecpdk6dKlp4xzyZIlxMbGen3O1++wLVmyhLlz5/LJJ59gs9mw2WwsWbKk1fa5XC7uvPNOYmNjSUhI4N5772XKlClcddVVnjrLly/nkksu8dT5/ve/z+7duz3lLTuUDxkyBJvNxtixYz1lzz33HDk5OTidTrKzs3nqqac8ZY2NjUyfPp20tDScTidZWVmn/W6J+CMlOyJ+JigoiIcffpgnn3ySL7/88pzOtXr1ag4cOMC6det47LHHmDNnDt///veJi4tj48aN3Hrrrfz85z8/6XNmzZrFzJkz2bx5M3l5eVxxxRWUl5cDUFFRwbhx4xgyZAibNm1i+fLllJWVce2113qd4/nnn8fhcLB+/XqeeeaZVtv3hz/8gd/97nf89re/5dNPP2XixIn84Ac/YOfOnQCUlJQwYMAAZs6cSUlJCb/4xS/aHPvvfvc7hg0bxubNm7n99tu57bbbKCoqanOcZzJ58mRmzpzJgAEDKCkpoaSkhMmTJ7dad+HChbzwwgssXryY9evXU1VVxWuvveZVp7a2lhkzZrBp0yZWrVqF3W7nhz/8IW63G4APP/wQgJUrV1JSUsKrr74KwAsvvMADDzzAb37zGz7//HMefvhh7r//fp5//nkAnnjiCd544w3++te/UlRUxAsvvOCVFIsEBF/vRCoibTdlyhRz5ZVXGmOMufjii82NN95ojDFm2bJl5uv/Oc+ZM8cMHjzY672PP/64ycrK8jpXVlaWaW5u9hzr16+fufTSSz2vXS6XiYiIMC+99JIxxpji4mIDmAULFnjqNDU1mYyMDLNw4UJjjDEPPfSQmTBhgtdn79+/3wCe3eDHjBljhgwZcsZ409PTzW9+8xuvY8OHDze333675/XgwYPNnDlzTnueMWPGmLvuusvzOisry/zkJz/xvHa73SY5Odk8/fTTbY5z8eLFJiYmxutz2nIdWpOSkmIeffRRz2uXy2UyMzM917o1hw4dMoDZunWrV5s3b97sVa93797mxRdf9Dr20EMPmby8PGOMMXfccYcZN26ccbvdZ2yniL/SnR0RP7Vw4UKef/55Pv/887M+x4ABA7DbT/wzkJKSQm5urud1UFAQCQkJHDx40Ot9eXl5nufBwcEMGzbM045PPvmE9957j8jISM8jOzsbwKvbZejQoadtW1VVFQcOHGDUqFFex0eNGnVOMbcYNGiQ57nNZiM1NfVbxdleKisrKSsrY8SIEZ5jQUFBJ/19du7cyXXXXUevXr2Ijo723H3Zt2/fKc9dW1vL7t27uemmm7yux3/+5396rsXUqVPZsmUL/fr148477+Tdd99t1/hEuoJgXzdARM7O6NGjmThxIrNnz2bq1KleZXa7HWOM17GmpqaTzhESEuL12maztXqspaukLWpqarjiiitYuHDhSWVpaWme5xEREW0+Z0c41zjb+jduL1dccQVZWVk8++yzpKen43a7GThw4GkHd9fU1ADw7LPPMnLkSK+yoKAgAC666CKKi4t55513WLlyJddeey35+fn87W9/67BYRDqb7uyI+LEFCxbw5ptvUlBQ4HU8KSmJ0tJSrx/j9pySvGHDBs9zl8tFYWEhOTk5gPXjuX37dnr06EGfPn28Ht8mwYmOjiY9PZ3169d7HV+/fj39+/dvn0DO4HRxJiUlUV1dTW1trafON//GDoeD5ubm035GTEwMKSkpfPTRR55jzc3NfPzxx57X5eXlFBUV8etf/5rx48eTk5Nz0mw8h8PheW+LlJQU0tPT+eKLL066Fi0DmsH6W0+ePJlnn32Wl19+mb///e8cOXLkTH8eEb+hOzsifiw3N5frr7+eJ554wuv42LFjOXToEI888gj/9m//xvLly3nnnXeIjo5ul89dtGgRffv2JScnh8cff5yjR49y4403AjBt2jSeffZZrrvuOn75y18SHx/Prl27WLp0Kc8995znjkJbzJo1izlz5tC7d28uvPBCFi9ezJYtW3jhhRfaJY4zOV2cI0eOJDw8nF/96lfceeedbNy48aTZVj169KC4uJgtW7aQkZFBVFQUoaGhJ33OHXfcwfz58+nTpw/Z2dk8+eSTHD161DOzKy4ujoSEBP785z+TlpbGvn37uO+++7zOkZycTFhYGMuXLycjIwOn00lMTAxz587lzjvvJCYmhkmTJtHQ0MCmTZs4evQoM2bM4LHHHiMtLY0hQ4Zgt9t55ZVXSE1NPWmmmYg/050dET83b968k7pfcnJyeOqpp1i0aBGDBw/mww8//FYzlc5kwYIFLFiwgMGDB/P+++/zxhtvkJiYCOC5G9Pc3MyECRPIzc3l7rvvJjY21mt8UFvceeedzJgxg5kzZ5Kbm8vy5ct544036Nu3b7vFcjqnizM+Pp6//OUvvP322+Tm5vLSSy+dNPX9mmuuYdKkSVx22WUkJSXx0ksvtfo59957L9dddx0//elPycvLIzIykokTJ+J0OgGry2zp0qUUFhYycOBA7rnnHh599FGvcwQHB/PEE0/wpz/9ifT0dK688koAfvazn/Hcc8+xePFicnNzGTNmDEuWLPHc2YmKiuKRRx5h2LBhDB8+nD179vD2229/62sl0pXZzDc7nUVEznN79uyhZ8+ebN68udNWQP46t9tNTk4O1157rU9WfhYJNOrGEhHxsb179/Luu+8yZswYGhoa+OMf/0hxcTE//vGPfd00kYCg+5QiIj5mt9tZsmQJw4cPZ9SoUWzdupWVK1d6BkOLyLlRN5aIiIgENN3ZERERkYCmZEdEREQCmpIdERERCWhKdkRERCSgKdkRERGRgKZkR0RERAKakh0REREJaEp2REREJKAp2REREZGA9v8Bl+xctOYJ2EEAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHHCAYAAABZbpmkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAACncUlEQVR4nOzdd3iUZdb48e/0THpv9A4BBESFCFYQVHR1QV1dC+vLq65iRVFZO64N1/5aVtcVXfXnu9Z9bSCCHQQEC02kBwjpyUwyk+nP7497ZpIhbRISUjif65ork+d55pl7EMnJfZ/7HJ2maRpCCCGEED2UvrMHIIQQQgjRkSTYEUIIIUSPJsGOEEIIIXo0CXaEEEII0aNJsCOEEEKIHk2CHSGEEEL0aBLsCCGEEKJHk2BHCCGEED2aBDtCCCGE6NEk2BFCCCFEjybBjhAiKjt27OCqq65i4MCBxMTEkJiYyKRJk3jqqaeora0FoH///uh0Oq677roGr//yyy/R6XS88847Dc5t2rSJSy65hF69emGxWMjNzeXiiy9m06ZNEdfpdLqoHl9++WWzn8Vut/PAAw9wzDHHkJSUhMVioV+/fvzhD3/g448/btOfT2FhIffeey8//fRTm14vhOg4xs4egBCi6/v44485//zzsVgsXHbZZYwaNQqPx8O3337L/Pnz2bRpEy+++GL4+pdeeokFCxaQm5vb4r3fe+89LrroIlJTU5kzZw4DBgxg9+7dvPzyy7zzzju89dZb/P73vwfgX//6V8RrX3vtNZYtW9bg+IgRI5p8v+3btzN9+nT27NnD73//ey677DLi4+PZu3cvn3zyCWeddRavvfYal156aWv+iCgsLOS+++6jf//+jB07tlWvFUJ0ME0IIZqxc+dOLT4+Xhs+fLhWWFjY4Py2bdu0J598UtM0TevXr582cuRIzWg0atddd13EdV988YUGaG+//Xb42Pbt27XY2Fht+PDhWklJScT1paWl2vDhw7W4uDhtx44djY5t7ty5Wmv+GfN6vdqoUaO0uLg47dtvv230mqVLl2qffPJJ1PcMWbt2rQZor7zySqtfK4ToWLKMJYRo1qJFi6ipqeHll18mJyenwfnBgwdzww03hL/v378/l112GS+99BKFhYXN3vvRRx/F6XTy4osvkpGREXEuPT2dv//97zgcDhYtWtQun+Xtt99m48aN3HXXXUyaNKnRa6ZNm8YZZ5wR/r6iooJbbrmF0aNHEx8fT2JiImeccQY///xz+Jovv/ySY489FoDLL788vJy2ePHi8DWrV6/m9NNPJykpidjYWE466SS+++67iPeurq7mxhtvpH///lgsFjIzMznttNNYv359u3x+IY5UEuwIIZr14YcfMnDgQI4//vioX3PHHXfg8/l4+OGHW7x3//79OeGEExo9f+KJJ9K/f/8259E09n4Al1xySdSv2blzJx988AFnnXUWjz/+OPPnz2fDhg2cdNJJ4WBuxIgRLFy4EIArr7ySf/3rX/zrX//ixBNPBGDFihWceOKJ2O127rnnHh588EGqqqo49dRTWbNmTfi9/vznP/P8888za9YsnnvuOW655RasVitbtmxpl88vxBGrs6eWhBBdl81m0wDtnHPOier6fv36aTNmzNA0TdMuv/xyLSYmJrz0dfAyVlVVVVT3/t3vfqcBmt1ub3CutctY48aN05KTkxscr6mp0UpLS8MPm80WPudyuTS/3x9x/a5duzSLxaItXLgwfKypZaxAIKANGTJEmz59uhYIBMLHnU6nNmDAAO20004LH0tKStLmzp0b9ecRQkRHZnaEEE2y2+0AJCQktPq1d955Z7OzO9XV1VHdO3Q+NJZDYbfbiY+Pb3D8jjvuICMjI/z44x//GD5nsVjQ69U/lX6/n/LycuLj4xk2bFhUy0s//fQT27Zt449//CPl5eWUlZVRVlaGw+FgypQpfP311wQCAQCSk5NZvXp1i8t/QojWkd1YQogmJSYmAnWBSWsMHDiQSy+9lBdffJHbb7+9wflQENPSvaMNikJqamqoqakJf28wGML5QAkJCZSXlzd4zTXXXMNZZ50FNFziCgQCPPXUUzz33HPs2rULv98fPpeWltbieLZt2wbA7Nmzm7zGZrORkpLCokWLmD17Nn369GH8+PGceeaZXHbZZQwcOLDF9xFCNE1mdoQQTUpMTCQ3N5eNGze26fWh3J1HHnmkwbmkpCRycnL45Zdfmr3HL7/8Qq9evcKBV0v+9re/kZOTE36EEocBhg8fTlVVFfv37494zdChQ5k6dSpTp04lJiYm4tyDDz7IvHnzOPHEE3n99ddZunQpy5YtY+TIkeEZmeaErnn00UdZtmxZo4/QbNMFF1zAzp07eeaZZ8jNzeXRRx9l5MiRfPrpp1F9diFE42RmRwjRrLPOOosXX3yRVatWkZ+f36rXDho0iEsuuYS///3vTJgwodF7v/TSS3z77bdMnjy5wflvvvmG3bt3c9VVV0X9npdddlnEvaxWa8T7vfXWW7zxxhvceuutUd3vnXfe4ZRTTuHll1+OOF5VVUV6enr4e51O1+jrBw0aBKjAcerUqS2+X05ODtdccw3XXHMNJSUlHH300TzwwAMRO8SEEK0jMztCiGbdeuutxMXF8d///d8UFxc3OL9jxw6eeuqpJl9/55134vV6G90+Pn/+fKxWK1dddVWD5aWKigr+/Oc/Exsby/z586Me78CBA8OzNFOnTo3YYn7BBReQl5fH/fffz/fff9/o6zVNi/jeYDA0OPb22283mB2Ki4sDVBBU3/jx4xk0aBB/+9vfIpbXQkpLSwGVD2Sz2SLOZWZmkpubi9vtbuYTCyFaIjM7QohmDRo0iDfffJM//OEPjBgxIqKC8sqVK3n77bf505/+1OzrL7nkEl599dUG54YMGcKrr77KxRdfzOjRoxtUUC4rK+P//b//F54dOVQmk4n333+f6dOnM3nyZGbOnMkJJ5xAXFwc+/fv5//+7/8oKChgxowZ4decddZZLFy4kMsvv5zjjz+eDRs28MYbbzTIoxk0aBDJycm88MILJCQkEBcXx4QJExgwYAD/+Mc/OOOMMxg5ciSXX345vXr1Yv/+/XzxxRckJiby4YcfUl1dTe/evTnvvPMYM2YM8fHxfP7556xdu5bHHnusXT6/EEeszt4OJoToHn777Tftiiuu0Pr376+ZzWYtISFBmzRpkvbMM89oLpdL07TIref1bdu2TTMYDA0qKIf88ssv2kUXXaTl5ORoJpNJy87O1i666CJtw4YNzY6ptVvPQ6qqqrSFCxdq48aN0+Lj4zWz2az16dNHO++887QPP/ww4lqXy6XdfPPNWk5Ojma1WrVJkyZpq1at0k466STtpJNOirj2P//5j5aXl6cZjcYG29B//PFHbebMmVpaWppmsVi0fv36aRdccIG2fPlyTdM0ze12a/Pnz9fGjBmjJSQkaHFxcdqYMWO05557rtWfTwgRSadpB83PCiGEEEL0IJKzI4QQQogeTYIdIYQQQvRoEuwIIYQQokfr1GDH7/dz1113MWDAAKxWK4MGDeL++++P2OapaRp33303OTk5WK1W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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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qW3yPkIIIYRoWFRUS1itVk488URWrFgR2uf3+1mxYgXjxo1rx5IJIYQQoiOIihoigNmzZzN16lTGjBnDySefzJIlS6iqqmLatGntXTQhhBBCtLOoCUSXX345RUVFzJ8/n/z8fEaPHs0HH3xQp6O1EEIIIaJP1MxDdCxacx4iIYQQQrSO5nx/R0UfIiGEEEKIxkggEkIIIUTUk0AkhBBCiKgngUgIIYQQUU8CkRBCCCGingQiIYQQQkQ9CURCCCGEiHoSiIQQQggR9SQQCSGEECLqRc3SHcciOJm33W5v55IIIYQQIlLB7+1IFuWQQBSBiooKAHr16tXOJRFCCCFEc1VUVJCcnNzoObKWWQT8fj+HDh0iMTERg8HQYte12+306tWL/fv3R9UaadF63yD3Ho33Hq33DdF779F639Dx7l0pRUVFBTk5ORiNjfcSkhqiCBiNRnr27Nlq109KSuoQfzhtLVrvG+Teo/Heo/W+IXrvPVrvGzrWvTdVMxQknaqFEEIIEfUkEAkhhBAi6kkgakc2m4377rsPm83W3kVpU9F63yD3Ho33Hq33DdF779F639C57106VQshhBAi6kkNkRBCCCGingQiIYQQQkQ9CURCCCGEiHoSiIQQQggR9SQQtZOnnnqKvn37EhMTw9ixY/nyyy/bu0gt7v7778dgMIQ9Bg8eHDrudDqZMWMG6enpJCQkcOmll1JQUNCOJT46a9as4cILLyQnJweDwcCbb74Zdlwpxfz58+nevTuxsbFMmjSJ7du3h51TUlLCVVddRVJSEikpKVx//fVUVla24V0cnabu/dprr63zN3DuueeGndMZ733hwoWcdNJJJCYmkpmZyUUXXcS2bdvCzonk73vfvn2cf/75xMXFkZmZyZw5c/B6vW15K80Wyb1PmDChzud+0003hZ3T2e79mWeeYeTIkaEJB8eNG8f7778fOt5VP29o+t67yuctgagd/POf/2T27Nncd999bNy4kVGjRjF58mQKCwvbu2gtbtiwYeTl5YUen376aejYb37zG95++23+/e9/s3r1ag4dOsQll1zSjqU9OlVVVYwaNYqnnnqq3uOLFy/mySef5Nlnn2XdunXEx8czefJknE5n6JyrrrqKTZs2sXz5ct555x3WrFnDjTfe2Fa3cNSauneAc889N+xv4NVXXw073hnvffXq1cyYMYMvvviC5cuX4/F4OOecc6iqqgqd09Tft8/n4/zzz8ftdvP555/zwgsvsHTpUubPn98etxSxSO4d4IYbbgj73BcvXhw61hnvvWfPnixatIgNGzbw1VdfcfbZZ/PTn/6UTZs2AV3384am7x26yOetRJs7+eST1YwZM0LPfT6fysnJUQsXLmzHUrW8++67T40aNareY2VlZcpisah///vfoX1btmxRgFq7dm0blbDlAWrZsmWh536/X2VnZ6tHH300tK+srEzZbDb16quvKqWU2rx5swLU+vXrQ+e8//77ymAwqIMHD7ZZ2Y/VkfeulFJTp05VP/3pTxt8TVe598LCQgWo1atXK6Ui+/t+7733lNFoVPn5+aFznnnmGZWUlKRcLlfb3sAxOPLelVLqzDPPVLfddluDr+kq956amqr++te/RtXnHRS8d6W6zuctNURtzO12s2HDBiZNmhTaZzQamTRpEmvXrm3HkrWO7du3k5OTQ79+/bjqqqvYt28fABs2bMDj8YT9HgYPHkzv3r271O9h9+7d5Ofnh91ncnIyY8eODd3n2rVrSUlJYcyYMaFzJk2ahNFoZN26dW1e5pa2atUqMjMzGTRoENOnT6e4uDh0rKvce3l5OQBpaWlAZH/fa9euZcSIEWRlZYXOmTx5Mna7Pey/vDu6I+896OWXX6Zbt24MHz6cuXPnUl1dHTrW2e/d5/Px2muvUVVVxbhx46Lq8z7y3oO6wucti7u2scOHD+Pz+cL+MACysrLYunVrO5WqdYwdO5alS5cyaNAg8vLyWLBgAaeffjo//PAD+fn5WK1WUlJSwl6TlZVFfn5++xS4FQTvpb7PO3gsPz+fzMzMsONms5m0tLRO/7s499xzueSSS8jNzWXnzp3cc889TJkyhbVr12IymbrEvfv9fmbNmsX48eMZPnw4QER/3/n5+fX+XQSPdQb13TvAL37xC/r06UNOTg7fffcdd911F9u2beM///kP0Hnv/fvvv2fcuHE4nU4SEhJYtmwZQ4cO5Ztvvunyn3dD9w5d5/OWQCRazZQpU0LbI0eOZOzYsfTp04d//etfxMbGtmPJRFu54oorQtsjRoxg5MiRHHfccaxatYqJEye2Y8lazowZM/jhhx/C+sdFi4buvXYfsBEjRtC9e3cmTpzIzp07Oe6449q6mC1m0KBBfPPNN5SXl/P6668zdepU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vPACVquVzz77jGeffbbe8j3xxBM89thj/P73v+e7775j8uTJ/OQnP2H79u0A5OXlMWzYMG6//Xby8vK44447Ir73xx57jDFjxvD1119z8803M336dLZt2xbxfTbl8ssv5/bbb2fYsGHk5eWRl5fH5ZdfXuc8v9/PP//5T66++mpycnLqvVbt5lCPx8ODDz7It99+y5tvvsmePXu49tprAejVqxdvvPEGANu2bSMvL48nnngCgIULF/Liiy/y7LPPsmnTJn7zm99w9dVXs3r1agDmzZvH5s2bef/999myZQvPPPMM3bp1i+hehegU2juRCSFaTrBWRymlTjnlFHXdddcppY6+hqhPnz7K5/OF9g0aNEidfvrpoeder1fFx8erV199VSlVUwOxaNGi0Dkej0f17NlTPfLII0oppR588EF1zjnnhL33/v37FaC2bdumlNI1Nscff3yT95uTk6MefvjhsH0nnXSSuvnmm0PPR40a1WDNUFB9NURXX3116Lnf71eZmZnqmWeeifg+m6ohUqr+z+FI+fn5ClB/+MMfwvafcMIJKj4+XsXHx6srrriiwdevX79eAaqiokIppdTHH3+sAFVaWho6x+l0qri4OPX555+Hvfb6669XV155pVJKqQsvvFBNmzat0bIK0ZlJDZEQXdQjjzzCCy+8wJYtW476GsOGDcNorPlnIisrixEjRoSem0wm0tPTKSwsDHvduHHjQttms5kxY8aEyvHtt9/y8ccfk5CQEHoMHjwY0P19gk488cRGy2a32zl06BDjx48P2z9+/PhjuuegkSNHhrYNBgPZ2dnNus/WtmzZMr755hsmT56Mw+EI7d+wYQMXXnghvXv3JjExkTPPPBOAffv2NXitHTt2UF1dzf/93/+FfS4vvvhi6DOZPn06r732GqNHj+bOO+/k888/b90bFKKNmdu7AEKI1nHGGWcwefJk5s6dG2oyCTIajSilwvZ5PJ4617BYLGHPDQZDvfv8fn/E5aqsrOTCCy/kkUceqXOse/fuoe34+PiIr9kajvU+I/0dNyUjI4OUlJQ6zXW9e/cGIDExMTRirKqqismTJzN58mRefvllMjIy2LdvH5MnT260Y3plZSUA7777Lj169Ag7ZrPZAJgyZQp79+7lvffeY/ny5UycOJEZM2bw+9//vtn3JERHJDVEQnRhixYt4u2332bt2rVh+zMyMsjPzw/7wm7JuYO++OKL0LbX62XDhg0MGTIEgBNOOIFNmzbRt29f+vfvH/ZoTghKSkoiJyeHzz77LGz/Z599xtChQ1vmRprQ2H1mZGRQUVFBVVVV6Jwjf8dWqxWfz9foexiNRi677DJeeuklDh061Oi5W7dupbi4mEWLFnH66aczePDgOrVaVqsVIOx9hw4dis1mY9++fXU+k169eoXOy8jIYOrUqbz00kssWbKEv/zlL42WR4jORAKREF3YiBEjuOqqq3jyySfD9k+YMIGioiIWL17Mzp07eeqpp3j//fdb7H2feuopli1bxtatW5kxYwalpaVcd911AMyYMYOSkhKuvPJK1q9fz86dO/nf//7HtGnTmgwHR5ozZw6PPPII//znP9m2bRt3330333zzDbfddluL3UtjGrvPsWPHEhcXxz333MPOnTt55ZVXWLp0adjr+/bty+7du/nmm284fPgwLper3vf53e9+R48ePTj55JP5+9//znfffcfOnTtZtmwZa9euxWQyAbrWyGq18sc//pFdu3bx1ltv1ZlfqU+fPhgMBt555x2KioqorKwkMTGRO+64g9/85je88MIL7Ny5k40bN/LHP/6RF154AYD58+fz3//+lx07drBp0ybeeeedUPgToiuQQCREF/fAAw/UaeoZMmQITz/9NE899RSjRo3iyy+/bNYIrKYsWrSIRYsWMWrUKD799FPeeuut0IikYK2Oz+fjnHPOYcSIEcyaNYuUlJSw/kqRuPXWW5k9eza33347I0aM4IMPPuCtt95iwIABLXYvjWnsPtPS0njppZd47733GDFiBK+++ir3339/2OsvvfRSzj33XM466ywyMjJ49dVX632f9PR0vvzyS375y1/y6KOPcvLJJzNixAjuv/9+Lr/8cp577jlA1+AsXbqUf//73wwdOpRFixbVadLq0aMHCxYs4O677yYrK4uZM2cC8OCDDzJv3jwWLlzIkCFDOPfcc3n33XfJzc0FdM3S3LlzGTlyJGeccQYmk4nXXnutJX+dQrQrgzqykVsIIUSj9uzZQ25uLl9//XXEM00LITo2qSESQgghRNSTQCSEEEKIqCdNZkIIIYSIelJDJIQQQoioJ4FICCGEEFFPApEQQgghop4EIiGEEEJEPQlEQgghhIh6EoiEEEIIEfUkEAkhhBAi6kkgEkIIIUTUk0AkhBBCiKj3/3T+W4QVYpCrAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "sns.lineplot(df, x=\"nr_gates\", y=\"h\", hue=\"method\")\n", "plt.title(\"H-Gates\")\n", @@ -763,7 +469,8 @@ "plt.xlabel(\"Number of input Gates\")\n", "plt.ylabel(\"Circuit Depth\")\n", "plt.show()\n" - ] + ], + "outputs": [] }, { "cell_type": "markdown", @@ -789,8 +496,8 @@ "execution_count": null, "id": "821b792f-5161-437a-ad17-1144a683cb7f", "metadata": {}, - "outputs": [], - "source": [] + "source": [], + "outputs": [] } ], "metadata": { diff --git a/pauliopt/circuits.py b/pauliopt/circuits.py index 7fdcc402..f6c782af 100644 --- a/pauliopt/circuits.py +++ b/pauliopt/circuits.py @@ -16,6 +16,7 @@ "y": lambda qubits, _: Y(*qubits), "z": lambda qubits, _: Z(*qubits), "s": lambda qubits, _: S(*qubits), + "sx": lambda qubits, _: V(*qubits), "sdg": lambda qubits, _: Sdg(*qubits), "t": lambda qubits, _: T(*qubits), "tdg": lambda qubits, _: Tdg(*qubits), @@ -52,16 +53,23 @@ def _get_qubits_qiskit(qubits, qreg): return tuple(qubits_) -class Circuit: +class AbstractCircuit: """Class for representing quantum circuits.""" def __init__(self, n_qubits, _gates=None): self.n_qubits = n_qubits - self._gates = [] if _gates is None else _gates + self._gates: List[Gate] = [] if _gates is None else _gates + self.global_phase = 0.0 for gate in self._gates: self._check_gate(gate) + self.final_permutation = None + + @property + def gates(self): + return self._gates + def add_gate(self, gate): return self.add_gates([gate]) @@ -92,6 +100,36 @@ def _check_gate(self, gate): def __repr__(self) -> str: return f"Circuit({self.n_qubits}, {self._gates})" + def __iadd__(self, other: "Circuit"): + for gate in other._gates: + self.add_gate(gate) + return self + + def __add__(self, other: "Circuit"): + if self.n_qubits != other.n_qubits: + print(self.n_qubits, other.n_qubits) + raise Exception("Can only concatenate circuits with same number of qubits.") + return Circuit(self.n_qubits, self._gates + other._gates) + + def inverse(self): + inverted = Circuit(self.n_qubits) + inv_gates = list(reversed([gate.inverse() for gate in self._gates])) + if any([inv_gate is None for inv_gate in inv_gates]): + print(inv_gates) + inverted.add_gates(inv_gates) + return inverted + + def apply_permutation(self, permutation: list[int]): + for gate in self._gates: + gate.apply_permutation(permutation) + + def copy(self) -> "Circuit": + new_gates = [] + for gate in self._gates: + new_gates.append(gate.copy()) + + return Circuit(self.n_qubits, _gates=new_gates) + def _to_svg( self, *, @@ -186,6 +224,7 @@ def from_qiskit(qc: "qiskit.QuantumCircuit"): def to_qiskit(self): try: from qiskit import QuantumCircuit + from qiskit.circuit.library import Permutation except ModuleNotFoundError: raise ModuleNotFoundError("You must install the 'qiskit' library.") @@ -194,4 +233,99 @@ def to_qiskit(self): for gate in self._gates: op, qubits = gate.to_qiskit() qc.append(op, qubits) + + if self.final_permutation is not None: + qc.compose(Permutation(self.n_qubits, self.final_permutation), inplace=True) return qc + + +class Circuit(AbstractCircuit): + """General Circuit class.""" + + def h(self, qubit): + qubits = (qubit,) + self.add_gate(H(*qubits)) + + def v(self, qubit): + qubits = (qubit,) + self.add_gate(V(*qubits)) + + def vdg(self, qubit): + qubits = (qubit,) + self.add_gate(Vdg(*qubits)) + + def s(self, qubit): + qubits = (qubit,) + self.add_gate(S(*qubits)) + + def sdg(self, qubit): + qubits = (qubit,) + self.add_gate(Sdg(*qubits)) + + def t(self, qubit): + qubits = (qubit,) + self.add_gate(T(*qubits)) + + def tdg(self, qubit): + qubits = (qubit,) + self.add_gate(Tdg(*qubits)) + + def cx(self, control, target): + qubits = (control, target) + self.add_gate(CX(*qubits)) + + def cy(self, control, target): + qubits = (control, target) + self.add_gate(CY(*qubits)) + + def cz(self, control, target): + qubits = (control, target) + self.add_gate(CZ(*qubits)) + + def x(self, qubit): + qubits = (qubit,) + self.add_gate(X(*qubits)) + + def y(self, qubit): + qubits = (qubit,) + self.add_gate(Y(*qubits)) + + def z(self, qubit): + qubits = (qubit,) + self.add_gate(Z(*qubits)) + + def swap(self, control, target): + qubits = (control, target) + self.add_gate(SWAP(*qubits)) + + def ccx(self, control1, control2, target): + qubits = (control1, control2, target) + self.add_gate(CCX(*qubits)) + + def ccz(self, control1, control2, target): + qubits = (control1, control2, target) + self.add_gate(CCZ(*qubits)) + + def rx(self, param: Angle, qubit): + qubits = (qubit,) + self.add_gate(Rx(param, *qubits)) + + def ry(self, param: Angle, qubit): + qubits = (qubit,) + self.add_gate(Ry(param, *qubits)) + + def rz(self, param: Angle, qubit): + qubits = (qubit,) + self.add_gate(Rz(param, *qubits)) + + def crx(self, param: Angle, control, target): + qubits = (control, target) + self.add_gate(CRx(param, *qubits)) + + def cry(self, param: Angle, control, target): + qubits = (control, target) + self.add_gate(CRy(param, *qubits)) + + def crz(self, param: Angle, control, target): + qubits = (control, target) + self.add_gate(CRz(param, *qubits)) diff --git a/pauliopt/clifford/tableau.py b/pauliopt/clifford/tableau.py index b95ace5e..a3698eb9 100644 --- a/pauliopt/clifford/tableau.py +++ b/pauliopt/clifford/tableau.py @@ -1,5 +1,29 @@ +from typing import List + import numpy as np +from pauliopt.circuits import ( + _get_qubits_qiskit, + _get_phase_qiskit, + QISKIT_CONVERSION, + Circuit, + AbstractCircuit, +) +from pauliopt.gates import ( + CliffordGate, + SingleQubitClifford, + TwoQubitClifford, + Gate, + H, + V, + Vdg, + S, + Sdg, + CX, + CY, + CZ, +) + def mult_paulis(p1, p2, sign1, sign2, n_qubits): """ @@ -46,15 +70,15 @@ class CliffordTableau: The sign of the operator in row i is given by the i-th entry of the sign vector. - The tableau is initialized as the identity matrix with a zero sign vector. + The clifford is initialized as the identity matrix with a zero sign vector. Args: - n_qubits (int): Number of qubits in the tableau. + n_qubits (int): Number of qubits in the clifford. - A more readable representation of the tableau is given by the string: + A more readable representation of the clifford is given by the string: ```python - >>> from pauliopt.clifford.tableau import CliffordTableau + >>> from pauliopt.clifford.clifford import CliffordTableau >>> ct = CliffordTableau(2) >>> print(ct) # Expected Output: @@ -67,9 +91,9 @@ class CliffordTableau: # I/I X/Z | + ``` - To get the raw $2n \times 2n$ matrix representation of the tableau, use: + To get the raw $2n \times 2n$ matrix representation of the clifford, use: ```python - >>> ct.tableau + >>> ct.clifford # Expected Output: # array([[0, 0, 1, 0], # [0, 1, 0, 0], @@ -97,10 +121,10 @@ def __str__(self) -> str: @staticmethod def from_tableau(tableau, signs): """ - Create a CliffordTableau from a tableau and sign vector. + Create a CliffordTableau from a clifford and sign vector. Args: - tableau (np.ndarray): $2n \times 2n$ binary matrix representing the tableau. + tableau (np.ndarray): $2n \times 2n$ binary matrix representing the clifford. signs (np.ndarray): $2n$-dimensional binary vector representing the sign vector. Returns: @@ -139,7 +163,7 @@ def from_qiskit_tableau(qiskit_ct: "qiskit.quantum_info.Clifford"): def string_repr(self, sep=" ", sign_sep="| "): """ - Get a string representation of the tableau. + Get a string representation of the clifford. Args: sep (str): Separator between the pauli operators @@ -197,7 +221,7 @@ def _xor_row(self, i, j): def prepend_h(self, qubit): """ - Prepend a Hadamard gate to the tableau. + Prepend a Hadamard gate to the clifford. Args: qubit (int): Qubit the hadamard gate is applied to. @@ -208,7 +232,7 @@ def prepend_h(self, qubit): def append_h(self, qubit): """ - Append a Hadamard gate to the tableau. + Append a Hadamard gate to the clifford. Args: qubit (int): Qubit the hadamard gate is applied to. @@ -220,7 +244,7 @@ def append_h(self, qubit): def prepend_s(self, qubit): """ - Prepend a S gate to the tableau. + Prepend a S gate to the clifford. Args: qubit (int): Qubit the S gate is applied to. @@ -229,7 +253,7 @@ def prepend_s(self, qubit): def append_s(self, qubit): """ - Append a S gate to the tableau. + Append a S gate to the clifford. Args: qubit (int): Qubit the S gate is applied to. @@ -241,7 +265,7 @@ def append_s(self, qubit): def prepend_cnot(self, control, target): """ - Prepend a CNOT gate to the tableau. + Prepend a CNOT gate to the clifford. Args: control (int): Control qubit. @@ -253,7 +277,7 @@ def prepend_cnot(self, control, target): def append_cnot(self, control, target): """ - Append a CNOT gate to the tableau. + Append a CNOT gate to the clifford. Args: control (int): Control qubit. @@ -276,7 +300,7 @@ def append_cnot(self, control, target): def insert_pauli_row(self, pauli, p_sign, row): """ - Insert a Pauli row into the tableau. + Insert a Pauli row into the clifford. Args: pauli (np.array): Pauli to be inserted. @@ -289,13 +313,13 @@ def insert_pauli_row(self, pauli, p_sign, row): def inverse(self): """ - Invert the tableau. + Invert the clifford. - Note: this is will create a deep copy of the tableau. + Note: this is will create a deep copy of the clifford. Returns: - CliffordTableau: Inverted tableau. + CliffordTableau: Inverted clifford. """ n_qubits = self.n_qubits @@ -319,9 +343,9 @@ def inverse(self): def apply(self, other: "CliffordTableau"): """ - Apply a CliffordTableau to the current tableau. + Apply a CliffordTableau to the current clifford. - Note: this is will create a deep copy of the tableau. + Note: this is will create a deep copy of the clifford. Args: other (CliffordTableau): CliffordTableau to apply. @@ -370,3 +394,122 @@ def apply(self, other: "CliffordTableau"): phase = np.mod(phase + p, 2) return CliffordTableau.from_tableau(new_tableau, phase) + + def prepend_gate(self, gate: CliffordGate) -> None: + for h_s_cx_gate in reversed(gate.get_h_s_cx_decomposition()): + if h_s_cx_gate.name == "H": + assert isinstance(h_s_cx_gate, SingleQubitClifford) + self.prepend_h(h_s_cx_gate.qubit) + elif h_s_cx_gate.name == "S": + assert isinstance(h_s_cx_gate, SingleQubitClifford) + self.prepend_s(h_s_cx_gate.qubit) + elif h_s_cx_gate.name == "CX": + assert isinstance(h_s_cx_gate, TwoQubitClifford) + self.prepend_cnot(h_s_cx_gate.control, h_s_cx_gate.target) + else: + raise TypeError(f"Invalid H, S, CX decomposition of {gate.name}") + + def append_gate(self, gate: CliffordGate) -> None: + for h_s_cx_gate in gate.get_h_s_cx_decomposition(): + if h_s_cx_gate.name == "H": + assert isinstance(h_s_cx_gate, SingleQubitClifford) + self.append_h(h_s_cx_gate.qubit) + elif h_s_cx_gate.name == "S": + assert isinstance(h_s_cx_gate, SingleQubitClifford) + self.append_s(h_s_cx_gate.qubit) + elif h_s_cx_gate.name == "CX": + assert isinstance(h_s_cx_gate, TwoQubitClifford) + self.append_cnot(h_s_cx_gate.control, h_s_cx_gate.target) + else: + raise TypeError(f"Invalid H, S, CX decomposition of {gate.name}") + + +class CliffordRegion(AbstractCircuit): + """Circuit, that specifically consists only out of clifford gates.""" + + def __init__(self, n_qubits, _gates: List[Gate] = None) -> None: + super().__init__(n_qubits, _gates=_gates) + + @property + def gates(self): + return self._gates + + def _check_gate(self, gate): + n_qubits = self.n_qubits + if not isinstance(gate, CliffordGate): + raise TypeError( + f"{gate} is not a valid gate. All gates must be clifford gates." + ) + + if len(set(gate.qubits)) != len(gate.qubits): + raise ValueError(f"{gate.qubits} are not unique.") + + if any(not (0 <= qubit < n_qubits) for qubit in gate.qubits): + msg = f"{gate} acts out of range for {n_qubits} qubit circuit." + raise ValueError(msg) + + @staticmethod + def from_qiskit(qc: "qiskit.QuantumCircuit"): + circ = CliffordRegion(qc.num_qubits) + + for inst in qc: + qubits = _get_qubits_qiskit(inst.qubits, qc.qregs[0]) + phase = _get_phase_qiskit(inst.operation.params) + circ.add_gate(QISKIT_CONVERSION[inst.operation.name](qubits, phase)) + + return circ + + def to_tableau(self, append: bool = True) -> CliffordTableau: + + ct = CliffordTableau(self.n_qubits) + + for gate in self._gates: + assert isinstance(gate, CliffordGate) + if append: + ct.append_gate(gate) + else: + ct.prepend_gate(gate) + return ct + + def __iadd__(self, other: "Circuit"): + for gate in other._gates: + self.add_gate(gate) + return self + + def __add__(self, other: "Circuit"): + if self.n_qubits != other.n_qubits: + print(self.n_qubits, other.n_qubits) + raise Exception("Can only concatenate circuits with same number of qubits.") + return CliffordRegion(self.n_qubits, self._gates + other._gates) + + def h(self, qubit): + qubits = (qubit,) + self.add_gate(H(*qubits)) + + def v(self, qubit): + qubits = (qubit,) + self.add_gate(V(*qubits)) + + def vdg(self, qubit): + qubits = (qubit,) + self.add_gate(Vdg(*qubits)) + + def s(self, qubit): + qubits = (qubit,) + self.add_gate(S(*qubits)) + + def sdg(self, qubit): + qubits = (qubit,) + self.add_gate(Sdg(*qubits)) + + def cx(self, control, target): + qubits = (control, target) + self.add_gate(CX(*qubits)) + + def cy(self, control, target): + qubits = (control, target) + self.add_gate(CY(*qubits)) + + def cz(self, control, target): + qubits = (control, target) + self.add_gate(CZ(*qubits)) diff --git a/pauliopt/clifford/tableau_synthesis.py b/pauliopt/clifford/tableau_synthesis.py index 5021105c..e336d7be 100644 --- a/pauliopt/clifford/tableau_synthesis.py +++ b/pauliopt/clifford/tableau_synthesis.py @@ -4,16 +4,17 @@ from pauliopt.circuits import Circuit from pauliopt.clifford.tableau import CliffordTableau from pauliopt.gates import CX, H, S +from pauliopt.utils import is_cutting from pauliopt.topologies import Topology def heurisitc_fkt(row, G, remaining: CliffordTableau): """ - The heuristic function for picking the pivot in the tableau synthesis algorithm. + The heuristic function for picking the pivot in the clifford synthesis algorithm. :param row: The row to consider :param G: The graph of the topology - :param remaining: The remaining tableau + :param remaining: The remaining clifford """ row_x = [ nx.shortest_path_length(G, source=row, target=col) @@ -32,13 +33,13 @@ def heurisitc_fkt(row, G, remaining: CliffordTableau): def pick_pivot(G, remaining: "CliffordTableau", possible_swaps, include_swaps): """ - Pick the pivot to eliminate the next column in the tableau synthesis algorithm. + Pick the pivot to eliminate the next column in the clifford synthesis algorithm. We currently use the heuristic function h to pick the pivot, i.e choose the row with the smallest `heurisitc_fkt` value. :param G: The graph of the topology - :param remaining: The remaining tableau + :param remaining: The remaining clifford :param possible_swaps: The columns that can be swapped :param include_swaps: Whether to include the columns that can be swapped """ @@ -103,7 +104,7 @@ def compute_steiner_tree( Compute the steiner tree of the sub_graph with the given nodes. This function is a wrapper around the networkx steiner tree function. - It will additionally swap the columns of the remaining tableau to further reduce + It will additionally swap the columns of the remaining clifford to further reduce the amount of CNOTs if include_swaps is True. Include_swaps requires lookup, swappable_nodes, permutation and n_qubits to be set. @@ -164,16 +165,6 @@ def compute_steiner_tree( return list(reversed(list(traversal))) -def is_cutting(vertex, g): - """ - Check if the given vertex is a cutting vertex in the given graph. - - :param vertex: The vertex to check - :param g: The graph to check - """ - return vertex in nx.articulation_points(g) - - def sanitize_z(row, row_z, remaining, apply): """ Sanitization process for the stabilizer part. @@ -183,9 +174,9 @@ def sanitize_z(row, row_z, remaining, apply): - If the z_out is X (=1), then apply H - :param row: The row of the tableau - :param row_z: The row of the tableau for the stabilizer part - :param remaining: The remaining tableau + :param row: The row of the clifford + :param row_z: The row of the clifford for the stabilizer part + :param remaining: The remaining clifford :param apply: The function to apply a gate """ for column in row_z: @@ -208,9 +199,9 @@ def sanitize_field_x(row, row_x, remaining, apply): - If the x_out is Y (=3), then apply S - If the x_out is X (=2), then apply H - :param row: The row of the tableau - :param row_x: The row of the tableau for the destabilizer part - :param remaining: The remaining tableau + :param row: The row of the clifford + :param row_x: The row of the clifford for the destabilizer part + :param remaining: The remaining clifford :param apply: The function to apply a gate """ for column in row_x: @@ -238,12 +229,12 @@ def remove_interactions( Include swaps requires swappable_nodes, permutation and include_swaps to be set. - :param pivot: The pivot of the tableau - :param row: The specific row of the tableau + :param pivot: The pivot of the clifford + :param row: The specific row of the clifford :param sub_graph: The graph of the topology - :param remaining: The remaining tableau + :param remaining: The remaining clifford :param apply: The function to apply a gate - :param basis: The basis of the tableau (x for destabilizer or z for stabilizer) + :param basis: The basis of the clifford (x for destabilizer or z for stabilizer) :param swappable_nodes: The nodes that can be swapped :param permutation: The permutation of the topology :param include_swaps: Whether to include swaps in the steiner tree @@ -287,11 +278,11 @@ def steiner_reduce_column( include_swaps=False, ): """ - Steiner reduce a column of the tableau. + Steiner reduce a column of the clifford. - :param pivot: The pivot of the tableau + :param pivot: The pivot of the clifford :param sub_graph: The graph of the topology - :param remaining: The remaining tableau + :param remaining: The remaining clifford :param apply: The function to apply a gate :param swappable_nodes: The nodes that can be swapped :param permutation: The permutation of the topology @@ -332,7 +323,7 @@ def steiner_reduce_column( ) # ensure that the pivots are in ZX basis - # (this is provided by the construction of a tableau) + # (this is provided by the construction of a clifford) assert remaining.x_out(pivot, pivot) == 1 assert remaining.z_out(pivot, pivot) == 2 diff --git a/pauliopt/gates.py b/pauliopt/gates.py index c007d1f0..6938c85d 100644 --- a/pauliopt/gates.py +++ b/pauliopt/gates.py @@ -1,11 +1,14 @@ from abc import ABC, abstractmethod from itertools import combinations from math import ceil +from typing import List, Union +from pauliopt.pauli_strings import Pauli from pauliopt.phase import X as XHead from pauliopt.phase import Z as ZHead from pauliopt.phase import pi from pauliopt.phase.phase_circuits import PhaseGadget +from pauliopt.utils import Angle class Gate(ABC): @@ -13,6 +16,7 @@ class Gate(ABC): def __init__(self, *qubits): self.qubits = qubits + self.n_qubits = len(qubits) self.name = self.__class__.__name__ if len(qubits) != self.n_qubits: name, n_qubits = self.name, self.n_qubits @@ -112,9 +116,22 @@ def gadgets(self): def to_qiskit(self): pass + @abstractmethod + def inverse(self): + pass + + def apply_permutation(self, permutation: list) -> None: + register = list(range(len(permutation))) + self.qubits = tuple( + [permutation[register.index(qubit)] for qubit in self.qubits] + ) -class PhaseGate(Gate): - def __init__(self, phase, *qubits): + def copy(self): + return self.__class__(*self.qubits) + + +class PhaseGate(Gate, ABC): + def __init__(self, phase: Angle, *qubits): super().__init__(*qubits) self.phase = phase @@ -122,8 +139,135 @@ def __repr__(self) -> str: args = map(repr, self.qubits) return f"{self.name}({self.phase}, {', '.join(args)})" + def get_phase_as_float(self): + return self.phase if not isinstance(self.phase, Angle) else float(self.phase) + + def get_phase_as_angle(self): + return self.phase if isinstance(self.phase, Angle) else Angle(self.phase) + + def inverse(self): + return self.__class__(-self.phase, *self.qubits) + + def copy(self): + return self.__class__(self.phase, self.qubits) + + +PROPAGATION_H = { + "X": (Pauli.Z, 1), + "Y": (Pauli.Y, -1), + "Z": (Pauli.X, 1), + "I": (Pauli.I, 1), +} + +PROPAGATION_S = { + "X": (Pauli.Y, -1), + "Y": (Pauli.X, 1), + "Z": (Pauli.Z, 1), + "I": (Pauli.I, 1), +} + +PROPAGATION_CX = { + "XX": (Pauli.X, Pauli.I, 1), + "XY": (Pauli.Y, Pauli.Z, 1), + "XZ": (Pauli.Y, Pauli.Y, -1), + "XI": (Pauli.X, Pauli.X, 1), + "YX": (Pauli.Y, Pauli.I, 1), + "YY": (Pauli.X, Pauli.Z, -1), + "YZ": (Pauli.X, Pauli.Y, 1), + "YI": (Pauli.Y, Pauli.X, 1), + "ZX": (Pauli.Z, Pauli.X, 1), + "ZY": (Pauli.I, Pauli.Y, 1), + "ZZ": (Pauli.I, Pauli.Z, 1), + "ZI": (Pauli.Z, Pauli.I, 1), + "IX": (Pauli.I, Pauli.X, 1), + "IY": (Pauli.Z, Pauli.Y, 1), + "IZ": (Pauli.Z, Pauli.Z, 1), + "II": (Pauli.I, Pauli.I, 1), +} + + +class CliffordGate(Gate, ABC): + def __init__(self, *qubits): + super().__init__(*qubits) + + @abstractmethod + def get_h_s_cx_decomposition(self) -> List[Union["H", "S", "CX"]]: + """ + Every clifford must be decomposable into a list of H, S and CX gates. + Returns: + + """ + pass + + def propagate_pauli(self, gadget: "pauliopt.pauli.pauli_gadget.PauliGadget"): + """ + Propagate a pauli gate through a gadget using the H, S, CX decomposition rules. + + One can define for H, S and CX propagation rules, which are defined in the dictionaries above. + Args: + gadget: + + Returns: + + """ + h_s_cx_decomposition = self.get_h_s_cx_decomposition() + for gate in reversed(h_s_cx_decomposition): + if gate.name == "H": + assert isinstance(gate, SingleQubitClifford) + p_string = gadget.paulis[gate.qubit].value + new_p, phase_change = PROPAGATION_H[p_string] + gadget.paulis[gate.qubit] = new_p + if phase_change == -1: + gadget.angle *= phase_change + elif gate.name == "S": + assert isinstance(gate, SingleQubitClifford) + p_string = gadget.paulis[gate.qubit].value + new_p, phase_change = PROPAGATION_S[p_string] + gadget.paulis[gate.qubit] = new_p + if phase_change == -1: + gadget.angle *= phase_change + elif gate.name == "CX": + assert isinstance(gate, TwoQubitClifford) + p_string = ( + gadget.paulis[gate.control].value + gadget.paulis[gate.target].value + ) + p_c, p_t, phase_change = PROPAGATION_CX[p_string] + gadget.paulis[gate.control] = p_c + gadget.paulis[gate.target] = p_t + if phase_change == -1: + gadget.angle *= phase_change + + return gadget + + +class SingleQubitClifford(CliffordGate, ABC): + + def __init__(self, qubit: int): + super().__init__((qubit)) + + @property + def qubit(self): + return self.qubits[0] + + +class TwoQubitClifford(CliffordGate, ABC): + def __init__(self, control, target): + qubits = (control, target) + super().__init__(*qubits) + + @property + def control(self): + return self.qubits[0] + + @property + def target(self): + return self.qubits[1] + + def copy(self): + return self.__class__(self.control, self.target) -class H(Gate): + +class H(SingleQubitClifford): n_qubits = 1 width = 40 @@ -150,8 +294,14 @@ def to_qiskit(self): return HGate(), self.qubits + def inverse(self): + return H(*self.qubits) + + def get_h_s_cx_decomposition(self) -> List[Union["H", "S", "CX"]]: + return [H(*self.qubits)] + -class X(Gate): +class X(SingleQubitClifford): n_qubits = 1 draw_as_zx = True @@ -167,8 +317,14 @@ def to_qiskit(self): return XGate(), self.qubits + def inverse(self): + return X(*self.qubits) -class Z(Gate): + def get_h_s_cx_decomposition(self): + return [H(*self.qubits), S(*self.qubits), S(*self.qubits), H(*self.qubits)] + + +class Z(SingleQubitClifford): n_qubits = 1 draw_as_zx = True @@ -184,8 +340,14 @@ def to_qiskit(self): return ZGate(), self.qubits + def inverse(self): + return Z(*self.qubits) + + def get_h_s_cx_decomposition(self) -> List[Union["H", "S", "CX"]]: + return [S(*self.qubits), S(*self.qubits)] -class Y(Gate): + +class Y(SingleQubitClifford): n_qubits = 1 draw_as_zx = True @@ -202,8 +364,18 @@ def to_qiskit(self): return YGate(), self.qubits + def inverse(self): + return Y(*self.qubits) + + def get_h_s_cx_decomposition(self) -> List[Union["H", "S", "CX"]]: + return ( + Sdg(*self.qubits).get_h_s_cx_decomposition() + + X(*self.qubits).get_h_s_cx_decomposition() + + S(*self.qubits).get_h_s_cx_decomposition() + ) + -class S(Gate): +class S(SingleQubitClifford): n_qubits = 1 draw_as_zx = True @@ -219,8 +391,14 @@ def to_qiskit(self): return SGate(), self.qubits + def inverse(self): + return Sdg(*self.qubits) + + def get_h_s_cx_decomposition(self) -> List[Union["H", "S", "CX"]]: + return [S(*self.qubits)] + -class Sdg(Gate): +class Sdg(SingleQubitClifford): n_qubits = 1 draw_as_zx = True @@ -236,6 +414,62 @@ def to_qiskit(self): return SdgGate(), self.qubits + def inverse(self): + return S(*self.qubits) + + def get_h_s_cx_decomposition(self) -> List[Union["H", "S", "CX"]]: + return [S(*self.qubits), S(*self.qubits), S(*self.qubits)] + + +class V(SingleQubitClifford): + n_qubits = 1 + draw_as_zx = True + + @property + def decomp(self): + return [XHead(pi / 2) @ {self.qubits[0]}] + + def to_qiskit(self): + try: + from qiskit.circuit.library import SXGate + except ImportError: + raise ImportError("Please install qiskit to use this feature.") + + return SXGate(), self.qubits + + def inverse(self): + return Vdg(*self.qubits) + + def get_h_s_cx_decomposition(self) -> List[Union["H", "S", "CX"]]: + return [H(*self.qubits), S(*self.qubits), H(*self.qubits)] + + +class Vdg(SingleQubitClifford): + n_qubits = 1 + draw_as_zx = True + + @property + def decomp(self): + return [XHead(-pi / 2) @ {self.qubits[0]}] + + def to_qiskit(self): + try: + from qiskit.circuit.library import SXdgGate + except ImportError: + raise ImportError("Please install qiskit to use this feature.") + + return SXdgGate(), self.qubits + + def inverse(self): + return V(*self.qubits) + + def get_h_s_cx_decomposition(self) -> List[Union["H", "S", "CX"]]: + return ( + [H(*self.qubits)] + + Sdg(*self.qubits).get_h_s_cx_decomposition() + + [H(*self.qubits)] + ) + class T(Gate): n_qubits = 1 @@ -253,6 +487,9 @@ def to_qiskit(self): return TGate(), self.qubits + def inverse(self): + return Tdg(*self.qubits) + class Tdg(Gate): n_qubits = 1 @@ -270,8 +507,11 @@ def to_qiskit(self): return TdgGate(), self.qubits + def inverse(self): + return T(*self.qubits) + -class SWAP(Gate): +class SWAP(CliffordGate): n_qubits = 2 draw_as_zx = True @@ -288,8 +528,15 @@ def to_qiskit(self): return SwapGate(), self.qubits + def inverse(self): + return SWAP(*self.qubits) + + def get_h_s_cx_decomposition(self) -> List[Union["H", "S", "CX"]]: + q0, q1 = self.qubits + return [CX(q0, q1), CX(q1, q0), CX(q0, q1)] + -class CX(Gate): +class CX(TwoQubitClifford): n_qubits = 2 draw_as_zx = True width = 40 @@ -313,6 +560,10 @@ def draw(self, builder, base, row_width, params): builder.circle((x, y_ctrl), r, zcolor) builder.circle((x, y_trgt), r, xcolor) + def get_h_s_cx_decomposition(self) -> List[Union["H", "S", "CX"]]: + q0, q1 = self.qubits + return [CX(q0, q1)] + def to_qiskit(self): try: from qiskit.circuit.library import CXGate @@ -321,8 +572,11 @@ def to_qiskit(self): return CXGate(), self.qubits + def inverse(self): + return CX(*self.qubits) + -class CY(Gate): +class CY(TwoQubitClifford): n_qubits = 2 draw_as_zx = True @@ -339,8 +593,15 @@ def to_qiskit(self): return CYGate(), self.qubits + def inverse(self): + return CY(*self.qubits) + + def get_h_s_cx_decomposition(self) -> List[Union["H", "S", "CX"]]: + q0, q1 = self.qubits + return Sdg(q1).get_h_s_cx_decomposition() + [CX(q0, q1)] + [S(q1)] -class CZ(Gate): + +class CZ(TwoQubitClifford): n_qubits = 2 draw_as_zx = True @@ -373,6 +634,13 @@ def to_qiskit(self): return CZGate(), self.qubits + def inverse(self): + return CZ(*self.qubits) + + def get_h_s_cx_decomposition(self) -> List[Union["H", "S", "CX"]]: + q0, q1 = self.qubits + return [H(q1), CX(q0, q1), H(q1)] + class CCX(Gate): n_qubits = 3 @@ -391,6 +659,9 @@ def to_qiskit(self): return CCXGate(), self.qubits + def inverse(self): + return CCX(*self.qubits) + class CCZ(Gate): n_qubits = 3 @@ -413,6 +684,9 @@ def to_qiskit(self): return CCZGate(), self.qubits + def inverse(self): + return CCZ(*self.qubits) + class Rx(PhaseGate): n_qubits = 1 @@ -421,15 +695,14 @@ class Rx(PhaseGate): @property def decomp(self): (q,) = self.qubits - return [XHead(self.phase) @ {q}] + return [XHead(self.get_phase_as_angle()) @ {q}] def to_qiskit(self): try: from qiskit.circuit.library import RXGate except ImportError: raise ImportError("Please install qiskit to use this feature.") - - return RXGate(self.phase), self.qubits + return RXGate(self.get_phase_as_float()), self.qubits class Ry(PhaseGate): @@ -439,7 +712,11 @@ class Ry(PhaseGate): @property def decomp(self): (q,) = self.qubits - return [XHead(pi / 2) @ {q}, ZHead(self.phase) @ {q}, XHead(-pi / 2) @ {q}] + return [ + XHead(pi / 2) @ {q}, + ZHead(self.get_phase_as_angle()) @ {q}, + XHead(-pi / 2) @ {q}, + ] def to_qiskit(self): try: @@ -447,7 +724,7 @@ def to_qiskit(self): except ImportError: raise ImportError("Please install qiskit to use this feature.") - return RYGate(self.phase), self.qubits + return RYGate(self.get_phase_as_float()), self.qubits class Rz(PhaseGate): @@ -457,15 +734,14 @@ class Rz(PhaseGate): @property def decomp(self): (q,) = self.qubits - return [ZHead(self.phase) @ {q}] + return [ZHead(self.get_phase_as_angle()) @ {q}] def to_qiskit(self): try: from qiskit.circuit.library import RZGate except ImportError: raise ImportError("Please install qiskit to use this feature.") - - return RZGate(self.phase), self.qubits + return RZGate(self.get_phase_as_float()), self.qubits class CRx(PhaseGate): @@ -483,8 +759,7 @@ def to_qiskit(self): from qiskit.circuit.library import CRXGate except ImportError: raise ImportError("Please install qiskit to use this feature.") - - return CRXGate(self.phase), self.qubits + return CRXGate(self.get_phase_as_float()), self.qubits class CRy(PhaseGate): @@ -503,7 +778,7 @@ def to_qiskit(self): except ImportError: raise ImportError("Please install qiskit to use this feature.") - return CRYGate(self.phase), self.qubits + return CRYGate(self.get_phase_as_float()), self.qubits class CRz(PhaseGate): @@ -522,7 +797,7 @@ def to_qiskit(self): except ImportError: raise ImportError("Please install qiskit to use this feature.") - return CRZGate(self.phase), self.qubits + return CRZGate(self.get_phase_as_float()), self.qubits CNOT = CX diff --git a/pauliopt/pauli/anneal.py b/pauliopt/pauli/anneal.py deleted file mode 100644 index 86f9e308..00000000 --- a/pauliopt/pauli/anneal.py +++ /dev/null @@ -1,61 +0,0 @@ -import numpy as np - -from pauliopt.pauli.clifford_gates import ( - CliffordGate, - CliffordType, - generate_random_clifford, -) -from pauliopt.pauli.clifford_region import CliffordRegion -from pauliopt.pauli.pauli_polynomial import PauliPolynomial -from pauliopt.phase.optimized_circuits import _validate_temp_schedule -from pauliopt.topologies import Topology - - -def pick_random_gate(num_qubits, gate_set=None): - if gate_set is None: - gate_set = [CliffordType.CX, CliffordType.CY, CliffordType.CZ] - - gate = np.random.choice(gate_set) - - return generate_random_clifford(gate, num_qubits) - - -def compute_effect( - pp: PauliPolynomial, gate: CliffordGate, topology: Topology, leg_cache=None -): - pp_ = pp.copy() - pp_.propagate(gate) - - return pp_.two_qubit_count(topology, leg_cache=leg_cache) - pp.two_qubit_count( - topology, leg_cache=leg_cache - ) - - -def anneal( - pp: PauliPolynomial, topology, schedule=("geometric", 1.0, 0.1), nr_iterations=100 -): - leg_cache = {} - clifford_region = CliffordRegion(pp.num_qubits) - - schedule = _validate_temp_schedule(schedule) - random_nrs = np.random.uniform(0.0, 1.0, size=(nr_iterations,)) - num_qubits = pp.num_qubits - for it in range(nr_iterations): - t = schedule(it, nr_iterations) - gate = pick_random_gate(num_qubits) - effect = 2 + compute_effect(pp, gate, topology, leg_cache=leg_cache) - accept_step = effect < 0 or random_nrs[it] < np.exp(-np.log(2) * effect / t) - if accept_step: - clifford_region.add_gate(gate) # TODO optimize clifford regions - pp.propagate(gate) - try: - from qiskit import QuantumCircuit - - except: - raise Exception("Please install qiskit to export the circuit") - - qc = QuantumCircuit(pp.num_qubits) - qc.compose(clifford_region.to_qiskit(), inplace=True) # TODO route on architecture - qc.compose(pp.to_qiskit(topology), inplace=True) - qc.compose(clifford_region.to_qiskit().inverse(), inplace=True) - return qc diff --git a/pauliopt/pauli/clifford_gates.py b/pauliopt/pauli/clifford_gates.py deleted file mode 100644 index e077b6d7..00000000 --- a/pauliopt/pauli/clifford_gates.py +++ /dev/null @@ -1,213 +0,0 @@ -from abc import ABC, abstractmethod -from enum import Enum - -from pauliopt.pauli.pauli_gadget import PauliGadget -from pauliopt.pauli.utils import X, Y, Z, I -import numpy as np - - -class CliffordType(Enum): - CX = "cx" - CY = "cy" - CZ = "cz" - H = "h" - S = "s" - V = "v" - - -class CliffordGate(ABC): - def __init__(self, c_type): - self.c_type = c_type - - @abstractmethod - def propagate_pauli(self, gadget: PauliGadget): ... - - -class SingleQubitGate(CliffordGate, ABC): - rules = None - - def __init__(self, type, qubit): - super().__init__(type) - self.qubit = qubit - - def propagate_pauli(self, gadget: PauliGadget): - if self.rules is None: - raise Exception(f"{self} has no rules defined for propagation!") - p_string = gadget.paulis[self.qubit].value - new_p, phase_change = self.rules[p_string] - gadget.paulis[self.qubit] = new_p - gadget.angle *= phase_change - return gadget - - -class ControlGate(CliffordGate, ABC): - rules = None - - def __init__(self, type, control, target): - super().__init__(type) - self.control = control - self.target = target - - def propagate_pauli(self, gadget: PauliGadget): - if self.rules is None: - raise Exception(f"{self} has no rules defined for propagation!") - pauli_size = len(gadget) - if self.control >= pauli_size or self.target >= pauli_size: - raise Exception( - f"Control: {self.control} or Target {self.target} out of bounds: {pauli_size}" - ) - p_string = gadget.paulis[self.control].value + gadget.paulis[self.target].value - p_c, p_t, phase_change = self.rules[p_string] - gadget.paulis[self.control] = p_c - gadget.paulis[self.target] = p_t - gadget.angle *= phase_change - return gadget - - -class CX(ControlGate): - rules = { - "XX": (X, I, 1), - "XY": (Y, Z, 1), - "XZ": (Y, Y, -1), - "XI": (X, X, 1), - "YX": (Y, I, 1), - "YY": (X, Z, -1), - "YZ": (X, Y, 1), - "YI": (Y, X, 1), - "ZX": (Z, X, 1), - "ZY": (I, Y, 1), - "ZZ": (I, Z, 1), - "ZI": (Z, I, 1), - "IX": (I, X, 1), - "IY": (Z, Y, 1), - "IZ": (Z, Z, 1), - "II": (I, I, 1), - } - - def __init__(self, control, target): - super().__init__(CliffordType.CX, control, target) - - -class CZ(ControlGate): - rules = { - "XX": (Y, Y, 1), - "XY": (Y, X, -1), - "XZ": (X, I, 1), - "XI": (X, Z, 1), - "YX": (X, Y, -1), - "YY": (X, X, 1), - "YZ": (Y, I, 1), - "YI": (Y, Z, 1), - "ZX": (I, X, 1), - "ZY": (I, Y, 1), - "ZZ": (Z, Z, 1), - "ZI": (Z, I, 1), - "IX": (Z, X, 1), - "IY": (Z, Y, 1), - "IZ": (I, Z, 1), - "II": (I, I, 1), - } - - def __init__(self, control, target): - super().__init__(CliffordType.CZ, control, target) - - -class CY(ControlGate): - rules = { - "XX": (Y, Z, -1), - "XY": (X, I, 1), - "XZ": (Y, X, 1), - "XI": (X, Y, 1), - "YX": (X, Z, 1), - "YY": (Y, I, 1), - "YZ": (X, X, -1), - "YI": (Y, Y, 1), - "ZX": (I, X, 1), - "ZY": (Z, Y, 1), - "ZZ": (I, Z, 1), - "ZI": (Z, I, 1), - "IX": (Z, X, 1), - "IY": (I, Y, 1), - "IZ": (Z, Z, 1), - "II": (I, I, 1), - } - - def __init__(self, control, target): - super().__init__(CliffordType.CY, control, target) - - -class H(SingleQubitGate): - rules = {"X": (Z, 1), "Y": (Y, -1), "Z": (X, 1), "I": (I, 1)} - - def __init__(self, qubit): - super().__init__(CliffordType.H, qubit) - - -class S(SingleQubitGate): - rules = {"X": (Y, -1), "Y": (X, 1), "Z": (Z, 1), "I": (I, 1)} - - def __init__(self, qubit): - super().__init__(CliffordType.S, qubit) - - -class V(SingleQubitGate): - rules = {"X": (X, 1), "Y": (Z, -1), "Z": (Y, 1), "I": (I, 1)} - - def __init__(self, qubit): - super().__init__(CliffordType.V, qubit) - - -# For the gates X, Y, Z there won't be a change of Pauli matrices -# Refused to implement "higher order gates" like NCX, SWAP, DCX, ... but with this structure this can easily be done - - -def generate_random_clifford(c_type: CliffordType, n_qubits: int): - qubit = np.random.choice(list(range(n_qubits))) - if c_type == CliffordType.CX: - control = np.random.choice([i for i in range(n_qubits) if i != qubit]) - return CX(control, qubit) - elif c_type == CliffordType.CY: - control = np.random.choice([i for i in range(n_qubits) if i != qubit]) - return CY(control, qubit) - elif c_type == CliffordType.CZ: - control = np.random.choice([i for i in range(n_qubits) if i != qubit]) - return CZ(control, qubit) - elif c_type == CliffordType.H: - return H(qubit) - elif c_type == CliffordType.S: - return S(qubit) - elif c_type == CliffordType.V: - return V(qubit) - else: - raise TypeError(f"Unknown Clifford Type: {c_type}") - - -def clifford_to_qiskit(clifford: CliffordGate): - try: - from qiskit import QuantumCircuit - except: - raise Exception("Please install qiskit to export Clifford Gates") - - if isinstance(clifford, ControlGate): - qc = QuantumCircuit(max(clifford.control, clifford.target) + 1) - if clifford.c_type == CliffordType.CX: - qc.cx(clifford.control, clifford.target) - elif clifford.c_type == CliffordType.CY: - qc.cy(clifford.control, clifford.target) - elif clifford.c_type == CliffordType.CZ: - qc.cz(clifford.control, clifford.target) - else: - raise TypeError(f"Undefined Control gate {clifford.c_type}") - elif isinstance(clifford, SingleQubitGate): - qc = QuantumCircuit(clifford.qubit + 1) - if clifford.c_type == CliffordType.H: - qc.h(clifford.qubit) - elif clifford.c_type == CliffordType.S: - qc.s(clifford.qubit) - elif clifford.c_type == CliffordType.V: - qc.sx(clifford.qubit) - else: - raise TypeError(f"Undefined Single qubit gate: {clifford.c_type}") - else: - raise TypeError(f"Gate must be either single qubit or control") - return qc diff --git a/pauliopt/pauli/clifford_region.py b/pauliopt/pauli/clifford_region.py deleted file mode 100644 index 77ce0753..00000000 --- a/pauliopt/pauli/clifford_region.py +++ /dev/null @@ -1,34 +0,0 @@ -from pauliopt.pauli.clifford_gates import * - - -class CliffordRegion: - def __init__(self, num_qubits, gates=None): - if gates is None: - gates = [] - self.gates: [CliffordGate] = gates - self.num_qubits = num_qubits - - def add_gate(self, gate: CliffordGate): - if isinstance(gate, SingleQubitGate) and gate.qubit >= self.num_qubits: - raise Exception( - f"Gate with {gate.qubit} is out of bounds for Clifford Region with Qubits: {self.num_qubits}" - ) - if ( - isinstance(gate, ControlGate) - and gate.control >= self.num_qubits - and gate.target >= self.num_qubits - ): - raise Exception( - f"Control Gate with {gate.control}, {gate.target} is out of bounds for Clifford Region with Qubits: {self.num_qubits}" - ) - self.gates.append(gate) - - def to_qiskit(self): - try: - from qiskit import QuantumCircuit - except: - raise Exception("Please install qiskit to export Clifford Regions") - qc = QuantumCircuit(self.num_qubits) - for gate in self.gates: - qc.compose(clifford_to_qiskit(gate), inplace=True) - return qc diff --git a/pauliopt/pauli/pauli_gadget.py b/pauliopt/pauli/pauli_gadget.py index 78b9079e..aec2be1c 100644 --- a/pauliopt/pauli/pauli_gadget.py +++ b/pauliopt/pauli/pauli_gadget.py @@ -4,7 +4,9 @@ import networkx as nx import numpy as np -from pauliopt.pauli.utils import Pauli, X, Y, Z, I +from pauliopt.circuits import Circuit +from pauliopt.gates import H, V, Rz, CX, Vdg +from pauliopt.pauli_strings import Pauli, X, Y, Z, I from pauliopt.topologies import Topology from pauliopt.utils import AngleExpr @@ -22,7 +24,7 @@ def decompose_cnot_ladder_z(ctrl: int, trg: int, arch: Topology): return reversed(cnot_ladder) -def find_minimal_cx_assignment(column: np.array, arch: Topology): +def find_minimal_cx_assignment(column: np.array, arch: Topology, q0=None): if not np.all(np.isin(column, [0, 1])): raise Exception(f"Expected binary array as column, got: {column}") @@ -40,8 +42,10 @@ def find_minimal_cx_assignment(column: np.array, arch: Topology): for fst, snd in mst_branches: incident[fst].add((fst, snd)) incident[snd].add((snd, fst)) - - q0 = np.argmax(column) # Assume that 0 is always the first qubit aka first non zero + if q0 is None: + q0 = np.argmax( + column + ) # Assume that 0 is always the first qubit aka first non zero visited = set() queue = deque([q0]) cnot_ladder = [] @@ -64,6 +68,9 @@ def __init__(self, angle: AngleExpr): def __matmul__(self, paulis: List[Pauli]): return PauliGadget(self._angle, paulis) + def __str__(self): + return f"PPhase({self._angle})" + class PauliGadget: def __init__(self, angle: AngleExpr, paulis: List[Pauli]): @@ -74,83 +81,159 @@ def __len__(self): return len(self.paulis) def __repr__(self): - return f"({self.angle}) @ {{ {', '.join([pauli.value for pauli in self.paulis])} }}" + return self.to_string() + + def __getitem__(self, item): + return self.paulis[item] + + @property + def num_qubits(self): + return len(self.paulis) + + def to_string(self, pad_length=0): + pad = " " * (pad_length - len(str(self.angle))) + return f"PPhase({self.angle}) @ {pad} [ {', '.join([pauli.value for pauli in self.paulis])} ]" + + def num_legs(self): + return sum([1 for pauli in self.paulis if pauli != Pauli.I]) def copy(self): return PauliGadget(self.angle, self.paulis.copy()) + def decompose(self, q0): + cliffords = [] + column = np.asarray(self.paulis) + for pauli_idx in range(len(column)): + if column[pauli_idx] == I: + pass + elif column[pauli_idx] == X: + cliffords.append(H(pauli_idx)) + elif column[pauli_idx] == Y: + cliffords.append(V(pauli_idx)) + elif column[pauli_idx] == Z: # Z + pass + else: + raise Exception(f"unknown column type: {column[pauli_idx]}") + for q in range(self.num_qubits): + if q == q0: + continue + if self[q] != I: + cliffords.append(CX(q, q0)) + return cliffords, q0 + + def swap_rows(self, row1, row2): + self.paulis[row1], self.paulis[row2] = self.paulis[row2], self.paulis[row1] + def two_qubit_count(self, topology, leg_cache=None): if leg_cache is None: leg_cache = {} - column = np.asarray(self.paulis) - col_binary = np.where(column == Pauli.I, 0, 1) + col_binary = [1 if self[q] != I else 0 for q in range(self.num_qubits)] col_id = "".join([str(int(el)) for el in col_binary]) if col_id in leg_cache.keys(): return leg_cache[col_id] else: - cnot_amount = 2 * len(find_minimal_cx_assignment(col_binary, topology)[0]) + cnot_amount = 2 * len( + find_minimal_cx_assignment(np.asarray(col_binary), topology)[0] + ) leg_cache[col_id] = cnot_amount return cnot_amount - def to_qiskit(self, topology=None): - if isinstance(self.angle, float): - angle = self.angle - elif isinstance(self.angle, AngleExpr): - angle = self.angle.to_qiskit - else: - raise TypeError( - f"Angle must either be float or AngleExpr, but got {type(self.angle)}" + def mutual_legs(self, other: "PauliGadget"): + if len(self.paulis) != len(other.paulis): + raise Exception( + f"Paulis must be of equal length to have mutual legs. But are {len(self.paulis)}, " + f"{len(other.paulis)}" + ) + + match_count = 0 + for p_1, p_2 in zip(self.paulis, other.paulis): + leg_present_1 = p_1 != Pauli.I + leg_present_2 = p_2 != Pauli.I + if leg_present_2 and leg_present_1: + match_count += 1 + elif leg_present_1 != leg_present_2: + match_count -= 1 + else: + match_count -= 1 + return match_count + + def commutes(self, other: "PauliGadget"): + if len(self.paulis) != len(other.paulis): + raise Exception( + f"Paulis must be of equal length to commute. But are {len(self.paulis)}, " + f"{len(other.paulis)}" ) - num_qubits = len(self.paulis) + + mismatchcount = 0 + for p_1, p_2 in zip(self.paulis, other.paulis): + if p_1 != p_2 and p_1 != Pauli.I and p_2 != Pauli.I: + mismatchcount += 1 + return mismatchcount % 2 == 0 + + def to_circuit(self, topology=None, time=1): + num_qubits = self.num_qubits if topology is None: topology = Topology.complete(num_qubits) - try: - from qiskit import QuantumCircuit - except: - raise Exception("Please install qiskit to export Clifford Regions") - circ = QuantumCircuit(num_qubits) + + circ = Circuit(num_qubits) column = np.asarray(self.paulis) column_binary = np.where(column == I, 0, 1) if np.all(column_binary == 0): - circ.global_phase += angle + circ.global_phase += self.angle return circ - cnot_ladder, q0 = find_minimal_cx_assignment(column_binary, topology) for pauli_idx in range(len(column)): if column[pauli_idx] == I: pass elif column[pauli_idx] == X: - circ.h(pauli_idx) # Had + circ.add_gate(H(pauli_idx)) # Had elif column[pauli_idx] == Y: - circ.rx(0.5 * np.pi, pauli_idx) # V = Rx(0.5) + circ.add_gate(V(pauli_idx)) elif column[pauli_idx] == Z: # Z pass else: + print(column) raise Exception(f"unknown column type: {column[pauli_idx]}") if len(cnot_ladder) > 0: for pauli_idx, target in reversed(cnot_ladder): - circ.cx(pauli_idx, target) + circ.add_gate(CX(pauli_idx, target)) - circ.rz(angle, q0) + circ.add_gate(Rz(self.angle * time, q0)) for pauli_idx, target in cnot_ladder: - circ.cx(pauli_idx, target) + circ.add_gate(CX(pauli_idx, target)) else: target = np.argmax(column_binary) - circ.rz(angle, target) + circ.add_gate(Rz(self.angle * time, target)) for pauli_idx in range(len(column)): - if column[pauli_idx] == Pauli.I: + if column[pauli_idx] == I: pass - elif column[pauli_idx] == Pauli.X: - circ.h(pauli_idx) # Had - elif column[pauli_idx] == Pauli.Y: - circ.rx(-0.5 * np.pi, pauli_idx) # Vdg = Rx(-0.5) - elif column[pauli_idx] == Pauli.Z: + elif column[pauli_idx] == X: + circ.add_gate(H(pauli_idx)) # Had + elif column[pauli_idx] == Y: + circ.add_gate(Vdg(pauli_idx)) + elif column[pauli_idx] == Z: pass else: raise Exception(f"unknown column type: {column[pauli_idx]}") return circ + + def to_qiskit(self, time=1, topology=None): + return self.to_circuit(topology, time).to_qiskit() + + def permute(self, permutation: dict): + for k, v in permutation.items(): + self.paulis[k], self.paulis[v] = self.paulis[v], self.paulis[k] + + def assign_time(self, time): + if isinstance(self.angle, float): + self.angle = self.angle * time + else: + self.angle = self.angle.to_qiskit * time + + def set_angle(self, angle): + self.angle = float(angle) diff --git a/pauliopt/pauli/pauli_polynomial.py b/pauliopt/pauli/pauli_polynomial.py index 89f6f696..8080e4e0 100644 --- a/pauliopt/pauli/pauli_polynomial.py +++ b/pauliopt/pauli/pauli_polynomial.py @@ -1,41 +1,150 @@ -from pauliopt.pauli.clifford_gates import CliffordGate -from pauliopt.pauli.pauli_gadget import PauliGadget +import math +from typing import List + +import numpy as np +from pauliopt.circuits import Circuit +from pauliopt.gates import CliffordGate +from pauliopt.pauli.pauli_gadget import PauliGadget from pauliopt.topologies import Topology -import math -from pauliopt.pauli.utils import X, Y, Z, I from pauliopt.utils import SVGBuilder +from pauliopt.pauli_strings import X, Y, Z, I + +LATEX_HEADER = """\documentclass[preview]{standalone} + +\\usepackage{tikz} +\\usetikzlibrary{zx-calculus} +\\usetikzlibrary{quantikz} +\\usepackage{graphicx} + +\\tikzset{ +diagonal fill/.style 2 args={fill=#2, path picture={ +\\fill[#1, sharp corners] (path picture bounding box.south west) -| + (path picture bounding box.north east) -- cycle;}}, +reversed diagonal fill/.style 2 args={fill=#2, path picture={ +\\fill[#1, sharp corners] (path picture bounding box.north west) |- + (path picture bounding box.south east) -- cycle;}} +} + +\\tikzset{ +diagonal fill/.style 2 args={fill=#2, path picture={ +\\fill[#1, sharp corners] (path picture bounding box.south west) -| + (path picture bounding box.north east) -- cycle;}} +} + +\\tikzset{ +pauliY/.style={ +zxAllNodes, +zxSpiders, +inner sep=0mm, +minimum size=2mm, +shape=rectangle, +%fill=colorZxX +diagonal fill={colorZxX}{colorZxZ} +} +} + +\\tikzset{ +pauliX/.style={ +zxAllNodes, +zxSpiders, +inner sep=0mm, +minimum size=2mm, +shape=rectangle, +fill=colorZxX +} +} + +\\tikzset{ +pauliZ/.style={ +zxAllNodes, +zxSpiders, +inner sep=0mm, +minimum size=2mm, +shape=rectangle, +fill=colorZxZ +} +} + +\\tikzset{ +pauliPhase/.style={ +zxAllNodes, +zxSpiders, +inner sep=0.5mm, +minimum size=2mm, +shape=rectangle, +fill=white +} +} +""" class PauliPolynomial: - def __init__(self, num_qubits): - self.num_qubits = num_qubits - self.pauli_gadgets = [] + def __init__(self, num_qubits: int): + self.num_qubits: int = num_qubits + self.pauli_gadgets: List[PauliGadget] = [] + self.global_phase: float = 0.0 def __irshift__(self, gadget: PauliGadget): if not len(gadget) == self.num_qubits: raise Exception( - f"Pauli Polynomial has {self.num_qubits}, but Pauli gadget has: {len(gadget)}" + f"Pauli Polynomial has {self.num_qubits} qubits, but Pauli gadget has: " + f"{len(gadget)} qubits" ) self.pauli_gadgets.append(gadget) return self - def __rshift__(self, pauli_polynomial): + def __rshift__(self, pauli_polynomial: "PauliPolynomial"): for gadget in pauli_polynomial.pauli_gadgets: self.pauli_gadgets.append(gadget) return self def __repr__(self): - return "\n".join(map(repr, self.pauli_gadgets)) + if len(self.pauli_gadgets) > 0: + pad_length = max([len(str(gadget.angle)) for gadget in self.pauli_gadgets]) + else: + pad_length = 0 + return "\n".join( + [self[i].to_string(pad_length=pad_length) for i in range(self.num_gadgets)] + ) def __len__(self): return len(self.pauli_gadgets) + def __getitem__(self, index): + if isinstance(index, tuple): + index = list(index) + pp_ = PauliPolynomial(self.num_qubits) + pp_.pauli_gadgets = [self[i] for i in index] + return pp_ + elif isinstance(index, list): + pp_ = PauliPolynomial(self.num_qubits) + pp_.pauli_gadgets = [self[i] for i in index] + return pp_ + else: + return self.pauli_gadgets[index] + @property def num_gadgets(self): return len(self.pauli_gadgets) - def to_qiskit(self, topology=None): + def num_legs(self): + legs = 0 + for gadget in self.pauli_gadgets: + legs += gadget.num_legs() + return legs + + def assign_time(self, time: float): + for gadget in self.pauli_gadgets: + assert isinstance(gadget, PauliGadget) + gadget.assign_time(time) + + def set_random_angles(self, allowed_angles: list): + for gadget in self.pauli_gadgets: + angle = np.random.choice(allowed_angles) + gadget.set_angle(angle) + + def to_qiskit(self, topology: Topology = None, time: float = 1): num_qubits = self.num_qubits if topology is None: topology = Topology.complete(num_qubits) @@ -46,16 +155,39 @@ def to_qiskit(self, topology=None): qc = QuantumCircuit(num_qubits) for gadget in self.pauli_gadgets: - qc.compose(gadget.to_qiskit(topology), inplace=True) + qc.compose(gadget.to_qiskit(topology=topology, time=time), inplace=True) + qc.global_phase += self.global_phase + return qc + + def to_circuit(self, topology=None): + num_qubits = self.num_qubits + if topology is None: + topology = Topology.complete(num_qubits) + qc = Circuit(num_qubits) + for gadget in self.pauli_gadgets: + qc += gadget.to_circuit(topology) return qc - def propagate(self, gate: CliffordGate): + def propagate(self, gate: CliffordGate, sub_columns=None): + if sub_columns is None: + sub_columns = list(range(self.num_gadgets)) + pp_ = PauliPolynomial(self.num_qubits) - for gadget in self.pauli_gadgets: - pp_ >>= gate.propagate_pauli(gadget) + for idx, gadget in enumerate(self.pauli_gadgets): + if idx in sub_columns: + pp_ >>= gate.propagate_pauli(gadget) + else: + pp_ >>= gadget return pp_ + def propagate_inplace(self, gate: CliffordGate, sub_columns=None): + if sub_columns is None: + sub_columns = list(range(self.num_gadgets)) + + for col in sub_columns: + gate.propagate_pauli(self[col]) + def copy(self): pp_ = PauliPolynomial(self.num_qubits) for gadget in self.pauli_gadgets: @@ -70,6 +202,16 @@ def two_qubit_count(self, topology, leg_cache=None): count += gadget.two_qubit_count(topology, leg_cache=leg_cache) return count + def commutes(self, col1, col2): + gadget1 = self.pauli_gadgets[col1] + gadget2 = self.pauli_gadgets[col2] + return gadget1.commutes(gadget2) + + def mutual_legs(self, col1: int, col2: int): + gadget1 = self.pauli_gadgets[col1] + gadget2 = self.pauli_gadgets[col2] + return gadget1.mutual_legs(gadget2) + def to_svg( self, hscale: float = 1.0, @@ -80,8 +222,8 @@ def to_svg( vscale *= scale hscale *= scale - x_color = "#FF8888" - z_color = "#CCFFCC" + x_color = "#CCFFCC" + z_color = "#FF8888" y_color = "ycolor" num_qubits = self.num_qubits @@ -108,10 +250,8 @@ def to_svg( num_gadgets * (square_width + margin_x + margin_angle_x + text_width) + margin_x ) - height = ( - (num_qubits) * (square_height + margin_y) - + (square_height + margin_y + margin_angle_y) - + margin_y + height = (num_qubits) * (square_height + margin_y) + ( + square_height + margin_y + margin_angle_y ) builder = SVGBuilder(width, height) @@ -125,10 +265,7 @@ def to_svg( paulis = gadget.paulis y = margin_y text_coords = (square_width + margin_x + margin_angle_x + x, y) - text_lower_mid = ( - text_coords[0] + square_width, - text_coords[1] + square_height, - ) + text_left_lower_corder = (text_coords[0], text_coords[1] + square_height) for qubit in range(num_qubits): if qubit == 0: y += square_height + margin_y + margin_angle_y @@ -143,7 +280,7 @@ def to_svg( ) prev_x[qubit] = x + square_width builder.line_bend( - text_lower_mid, center_coords, degree=qubit * bend_degree + text_left_lower_corder, center_coords, degree=qubit * bend_degree ) if paulis[qubit] == X: builder.square((x, y), square_width, square_height, x_color) @@ -156,7 +293,6 @@ def to_svg( text_coords, text_width, square_height, str(gadget.angle) ) x += square_width + margin_x + text_width + margin_angle_x - y = margin_y for qubit in range(num_qubits): if qubit == 0: @@ -184,3 +320,71 @@ def _repr_svg_(self): See https://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html """ return self.to_svg(svg_code_only=True) + + def to_latex(self, file_name=None): + out_str = LATEX_HEADER + out_str += "\\begin{document}\n" + out_str += "\\begin{ZX}\n" + + angle_line = "\zxNone{} \t\t&" + + angle_pad_max = max( + [len(str(gadget.angle.repr_latex)) for gadget in self.pauli_gadgets] + ) + lines = {q: "\\zxNone{} \\rar \t&" for q in range(self.num_qubits)} + for gadget in self.pauli_gadgets: + assert isinstance(gadget, PauliGadget) + pad_ = "".join([" " for _ in range(self.num_qubits + 26)]) + pad_angle = "".join( + [" " for _ in range(angle_pad_max - len(str(gadget.angle.repr_latex)))] + ) + angle_line += ( + f" \\zxNone{{}} {pad_}&" + f" |[pauliPhase]| {gadget.angle.repr_latex} {pad_angle}&" + f" \\zxNone{{}} &" + ) + paulis = gadget.paulis + for q in range(self.num_qubits): + us = "".join(["u" for _ in range(q)]) + + pad_angle = "".join([" " for _ in range(angle_pad_max)]) + if paulis[q] != I: + pad_ = "".join([" " for _ in range(self.num_qubits - q)]) + lines[q] += ( + f" |[pauli{paulis[q].value}]| " + f"\\ar[ruu{us}, bend right] \\rar {pad_}&" + f" \\zxNone{{}} \\rar {pad_angle} &" + f" \\zxNone{{}} \\rar &" + ) + else: + pad_ = "".join([" " for _ in range(self.num_qubits + 22)]) + lines[q] += ( + f" \\zxNone{{}} \\rar {pad_}& " + f"\\zxNone{{}} \\rar {pad_angle} & " + f"\\zxNone{{}} \\rar &" + ) + out_str += angle_line + "\\\\ \n" + out_str += "\\\\ \n" + for q in range(self.num_qubits): + out_str += lines[q] + "\\\\ \n" + out_str += "\\end{ZX} \n" + out_str += "\\end{document}\n" + if file_name is not None: + with open(f"{file_name}.tex", "w") as f: + f.write(out_str) + return out_str + + def swap_gadgets(self, col1, col2): + self.pauli_gadgets[col1], self.pauli_gadgets[col2] = ( + self.pauli_gadgets[col2], + self.pauli_gadgets[col1], + ) + + def swap_rows(self, row1, row2): + for l in range(self.num_gadgets): + self.pauli_gadgets[l].swap_rows(row1, row2) + + def permute(self, permutation: dict): + for gadget in self.pauli_gadgets: + assert isinstance(gadget, PauliGadget) + gadget.permute(permutation) diff --git a/tests/tableau/__init__.py b/pauliopt/pauli/simplification/__init__.py similarity index 100% rename from tests/tableau/__init__.py rename to pauliopt/pauli/simplification/__init__.py diff --git a/pauliopt/pauli/simplification/simple_simplify.py b/pauliopt/pauli/simplification/simple_simplify.py new file mode 100644 index 00000000..65e4ceca --- /dev/null +++ b/pauliopt/pauli/simplification/simple_simplify.py @@ -0,0 +1,51 @@ +from pauliopt.pauli.pauli_polynomial import PauliPolynomial +import numpy as np + + +def remove_collapsed_pauli_gadgets(remaining_poly): + return list(filter(lambda x: x.angle != 2 * np.pi and x.angle != 0, remaining_poly)) + + +def find_matching_parity_right(idx, remaining_poly): + gadget = remaining_poly[idx] + for idx_right, gadget_right in enumerate(remaining_poly[idx + 1 :]): + if all([p_1 == p_2 for p_1, p_2 in zip(gadget.paulis, gadget_right.paulis)]): + return idx + idx_right + 1 + return None + + +def is_commuting_region(idx, idx_right, remaining_poly, allow_acs=False): + if allow_acs: + return True + for k in range(idx, idx_right): + if not remaining_poly[idx].commutes(remaining_poly[k]): + return False + return True + + +def propagate_phase_gadgets(remaining_poly, allow_acs=False): + converged = True + for idx, gadget in enumerate(remaining_poly): + idx_right = find_matching_parity_right(idx, remaining_poly) + if idx_right is None: + continue + if not is_commuting_region(idx, idx_right, remaining_poly, allow_acs=allow_acs): + continue + + remaining_poly[idx_right].angle = remaining_poly[idx_right].angle + gadget.angle + remaining_poly[idx].angle = 0.0 + converged = False + return converged + + +def simplify_pauli_polynomial(pp: PauliPolynomial, allow_acs=False): + remaining_poly = [gadget.copy() for gadget in pp.pauli_gadgets] + converged = False + while not converged: + remaining_poly = remove_collapsed_pauli_gadgets(remaining_poly) + converged = propagate_phase_gadgets(remaining_poly, allow_acs=allow_acs) + + pp_ = PauliPolynomial(pp.num_qubits) + for gadget in remaining_poly: + pp_ >>= gadget + return pp_ diff --git a/pauliopt/pauli/synthesis/__init__.py b/pauliopt/pauli/synthesis/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pauliopt/pauli/synthesis/annealing.py b/pauliopt/pauli/synthesis/annealing.py new file mode 100644 index 00000000..654c0b82 --- /dev/null +++ b/pauliopt/pauli/synthesis/annealing.py @@ -0,0 +1,129 @@ +from typing import Tuple, List + +import numpy as np + +from pauliopt.circuits import Circuit +from pauliopt.clifford.tableau import CliffordTableau +from pauliopt.clifford.tableau_synthesis import synthesize_tableau +from pauliopt.gates import CZ, CY, CX, CliffordGate + +from pauliopt.pauli.pauli_polynomial import PauliPolynomial +from pauliopt.phase.optimized_circuits import _validate_temp_schedule +from pauliopt.topologies import Topology + + +def pick_random_control_and_target(num_qubits: int) -> Tuple[int, int]: + """ + Given the number of qubits pick a random, but distinct control and target qubit. + :param num_qubits: + :return: + """ + control = np.random.choice([q for q in range(num_qubits)]) + target = np.random.choice([q for q in range(num_qubits) if q != control]) + return control, target + + +def compute_effect( + pp: PauliPolynomial, gate: CliffordGate, topology: Topology, leg_cache: dict = None +) -> int: + """ + Compute the effect on the PauliPolynomial as: #CX_prev - #CX_new + :param pp: + :param gate: + :param topology: + :param leg_cache: + :return: + """ + pp_ = pp.copy() + pp_ = pp_.propagate(gate) + return pp_.two_qubit_count(topology, leg_cache=leg_cache) - pp.two_qubit_count( + topology, leg_cache=leg_cache + ) + + +def get_best_gate( + pp: PauliPolynomial, + control: int, + target: int, + gate_set: List[CliffordGate], + topology: Topology, + leg_cache: dict = None, +): + """ + Get the gate with the best effect from the gate set. + :param pp: + :param control: + :param target: + :param gate_set: + :param topology: + :param leg_cache: + :return: + """ + gate_scores = [] + for gate in gate_set: + gate = gate(control, target) + effect = compute_effect(pp, gate, topology, leg_cache=leg_cache) + gate_scores.append((gate, effect)) + return min(gate_scores, key=lambda x: x[1]) + + +def count_legs(pp: PauliPolynomial, gate: CliffordGate) -> int: + """ + Count the legs on the pauli-polynomial. + :param pp: + :param gate: + :return: + """ + pp_ = pp.copy() + pp_.propagate(gate) + return pp_.num_legs() - pp.num_legs() + + +def annealing_synthesis( + pp: PauliPolynomial, + topology: Topology, + schedule: tuple = ("geometric", 1.0, 0.1), + nr_iterations: int = 100, + gate_set: List[CliffordGate] = None, +) -> Circuit: + """ + Simple annealing based synthesis of a pauli-polynomial. + + See: TODO reference + + :param pp: + :param topology: + :param schedule: + :param nr_iterations: + :param gate_set: + :return: + """ + if gate_set is None: + gate_set = [CX, CY, CZ] + + leg_cache = {} + clifford_tableau = CliffordTableau(n_qubits=pp.num_qubits) + + schedule = _validate_temp_schedule(schedule) + random_nrs = np.random.uniform(0.0, 1.0, size=(nr_iterations,)) + for it in range(nr_iterations): + t = schedule(it, nr_iterations) + ctrl, trg = pick_random_control_and_target(pp.num_qubits) + gate, effect = get_best_gate( + pp, ctrl, trg, gate_set, topology, leg_cache=leg_cache + ) + accept_step = effect < 0 or random_nrs[it] < np.exp(-np.log(2) * effect / t) + if accept_step: + clifford_tableau.append_gate(gate) + pp.propagate_inplace(gate) + + clifford_circ, _ = synthesize_tableau( + clifford_tableau, topology, include_swaps=False + ) + pp_circuit = pp.to_circuit(topology) + + qc = Circuit(pp.num_qubits) + qc += clifford_circ + qc += pp_circuit + qc += clifford_circ.inverse() + return qc diff --git a/pauliopt/pauli/synthesis/steiner_gray_synthesis.py b/pauliopt/pauli/synthesis/steiner_gray_synthesis.py new file mode 100644 index 00000000..97e4860c --- /dev/null +++ b/pauliopt/pauli/synthesis/steiner_gray_synthesis.py @@ -0,0 +1,536 @@ +from typing import List + +import networkx as nx + +from pauliopt.circuits import Circuit +from pauliopt.gates import CX, H, V, Vdg, Sdg +from pauliopt.pauli.pauli_polynomial import PauliPolynomial +from pauliopt.pauli_strings import I, X, Y, Z, Pauli +from pauliopt.topologies import Topology +from pauliopt.utils import is_cutting +from pauliopt.clifford.tableau import CliffordRegion +from pauliopt.clifford.tableau_synthesis import synthesize_tableau + + +def pick_row(pp: PauliPolynomial, columns_to_use, qubits_to_use): + qubit_scores = [] + weight_i = 10 + for q in qubits_to_use: + i_score = len([col for col in columns_to_use if pp.pauli_gadgets[col][q] == I]) + x_score = len([col for col in columns_to_use if pp.pauli_gadgets[col][q] == X]) + y_score = len([col for col in columns_to_use if pp.pauli_gadgets[col][q] == Y]) + z_score = len([col for col in columns_to_use if pp.pauli_gadgets[col][q] == Z]) + score = ( + weight_i * i_score + + max([x_score, y_score, z_score]) + - min([x_score, y_score, z_score]) + ) + qubit_scores.append((q, score)) + return max(qubit_scores, key=lambda x: x[1])[0] + + +def update_gadget_single_column( + pp: PauliPolynomial, qc: Circuit, q: int, p: Pauli, columns_to_use +): + if p == X: + gate = H(q) + pp.propagate(gate, columns_to_use) + qc.h(q) + elif p == Y: + gate = V(q) + pp.propagate(gate, columns_to_use) + qc.v(q) + elif p == Z: + pass # Nothing to do here + else: + raise ValueError("Invalid Pauli") + + +def find_common_paulis(q, pp: PauliPolynomial, columns_to_use): + common_paulis = [] + for col in columns_to_use: + if pp[col][q] != I: + common_paulis.append(pp[col][q]) + common_paulis = list(set(common_paulis)) + if len(common_paulis) == 1: + return common_paulis[0] + return None + + +def update_single_qubits(pp: PauliPolynomial, c: Circuit, qubits: list, columns_to_use): + change = False + for q in qubits: + p = find_common_paulis(q, pp, columns_to_use) + if p is not None: + update_gadget_single_column(pp, c, q, p, columns_to_use) + change = True + return change + + +def is_compatible(pp: PauliPolynomial, q1, q2, columns_to_use): + return find_compatible_pair(pp, q1, q2, columns_to_use) is not None + + +def find_compatible_pair(pp: PauliPolynomial, q1, q2, columns_to_use): + for p1 in [X, Y, Z]: + for p2 in [X, Y, Z]: + found_pair = True + for l in columns_to_use: + p_gdt = pp[l][q1] + p_gdt2 = pp[l][q2] + a_valid = p_gdt in [I, p1] + b_valid = p_gdt2 in [I, p2] + if a_valid != b_valid: + found_pair = False + break + if found_pair: + return p1, p2 + + return None + + +def pick_best_pair(pp, G: nx.Graph, columns_to_use, qubits): + for q_1, q_2 in G.edges: + if q_1 in qubits and q_2 in qubits: + pairs = find_compatible_pair(pp, q_1, q_2, columns_to_use) + if pairs is not None: + return pairs, (q_1, q_2) + return None + + +def filter_identity_qubits(pp: PauliPolynomial, qubits, columns_to_use): + non_identity_qubits = [] + for q in qubits: + if pp[columns_to_use[0]][q] != I: + non_identity_qubits.append(q) + return non_identity_qubits + + +def update_pair_qubits( + pp: PauliPolynomial, c: Circuit, topology, qubits, columns_to_use +): + non_visited_qubits = [q for q in qubits] + non_visited_qubits = filter_identity_qubits(pp, non_visited_qubits, columns_to_use) + qubit_pairs = pick_best_pair( + pp, + topology.to_nx.subgraph(non_visited_qubits), + columns_to_use, + non_visited_qubits, + ) + (p1, p2), (q_1, q_2) = qubit_pairs + non_visited_qubits.remove(q_1) + non_visited_qubits.remove(q_2) + update_gadget_single_column(pp, c, q_1, p1, columns_to_use) + update_gadget_single_column(pp, c, q_2, p2, columns_to_use) + + pp.propagate(CX(q_1, q_2), columns_to_use) + c.cx(q_1, q_2) + + +def partition_pauli_polynomial(pp: PauliPolynomial, row: int, columns_to_use: list): + col_i = [] + col_x = [] + col_y = [] + col_z = [] + for col in columns_to_use: + if pp.pauli_gadgets[col][row] == X: + col_x.append(col) + elif pp.pauli_gadgets[col][row] == Y: + col_y.append(col) + elif pp.pauli_gadgets[col][row] == Z: + col_z.append(col) + elif pp.pauli_gadgets[col][row] == I: + col_i.append(col) + else: + raise ValueError("Invalid Pauli in Partition") + return col_i, col_x, col_y, col_z + + +def max_partition_pauli_polynomial(pp: PauliPolynomial, row: int, columns_to_use: list): + cols = [[X], [Y], [Z]] + cols_i = [] + for col in columns_to_use: + if pp.pauli_gadgets[col][row] == X: + cols[0].append(col) + elif pp.pauli_gadgets[col][row] == Y: + cols[1].append(col) + elif pp.pauli_gadgets[col][row] == Z: + cols[2].append(col) + elif pp.pauli_gadgets[col][row] == I: + cols_i.append(col) + else: + raise ValueError("Invalid Pauli in Weighted") + + cols.sort(key=lambda x: len(x)) + + return cols_i, cols[-1][1:], cols[-1][0], cols[0][1:] + cols[1][1:] + + +def identity_partition_pauli_polynomial( + pp: PauliPolynomial, row: int, columns_to_use: list +): + col_i = [] + cols = [] + for col in columns_to_use: + if pp.pauli_gadgets[col][row] == I: + col_i.append(col) + elif pp.pauli_gadgets[col][row] == X: + cols.append(col) + elif pp.pauli_gadgets[col][row] == Y: + cols.append(col) + elif pp.pauli_gadgets[col][row] == Z: + cols.append(col) + else: + raise ValueError("Invalid Pauli") + return col_i, cols + + +def bipartition_pauli_polynomial(pp: PauliPolynomial, row: int, columns_to_use: list): + col_i, col_x, col_y, col_z = partition_pauli_polynomial(pp, row, columns_to_use) + cols = [] + if not col_x: + return col_i, X, Z, col_y, Z, col_z + if not col_y: + return col_i, X, Y, col_x, Z, col_z + + if len(col_x) != 0 and len(col_y) != 0: + cols.append((X, Y, col_x + col_y, Z, col_z, len(col_x) + len(col_y))) + if len(col_x) != 0 and len(col_z) != 0: + cols.append((X, Z, col_x + col_z, Y, col_y, len(col_x) + len(col_z))) + if len(col_y) != 0 and len(col_z): + cols.append((Y, Z, col_y + col_z, X, col_x, len(col_y) + len(col_z))) + + if cols: + type_two_1, type_two_2, cols_2, type_col1, col1, _ = max( + cols, key=lambda x: x[-1] + ) + else: + raise Exception("Invalid State") + return col_i, type_two_1, type_two_2, cols_2, type_col1, col1 + + +def zy_partition_pauli_polynomial(pp: PauliPolynomial, row: int, columns_to_use: list): + col_i, col_x, col_y, col_z = partition_pauli_polynomial(pp, row, columns_to_use) + return col_i, col_z + col_y, col_x + + +def propagate_circuit( + pp: PauliPolynomial, circuit: CliffordRegion, sub_columns: List[int] = None +): + if sub_columns is None: + sub_columns = list(range(pp.num_gadgets)) + for gate in reversed(circuit.gates): + pp.propagate(gate, sub_columns) + + +def pauli_polynomial_steiner_gray_clifford(pp: PauliPolynomial, topo: Topology): + perm_gadgets = [] + permutation = {k: k for k in range(pp.num_qubits)} + G = topo.to_nx + + def identity_recurse(columns_to_use, qubits_to_use): + """Determines row and row_next for recursion, removes all identity operators on both row and row_next""" + qc_out = Circuit(pp.num_qubits) + qc_prop = CliffordRegion(pp.num_qubits) + # always check to remove columns here, this should prevent some of the strange reintroduction of rotations + qc_out += check_columns(columns_to_use) + if not columns_to_use or not qubits_to_use: + return qc_out, qc_prop + G_sub = G.subgraph(qubits_to_use) + + non_cutting = [q for q in qubits_to_use if not is_cutting(q, G_sub)] + + row = pick_row(pp, columns_to_use, non_cutting) + row_neighbors = list(G_sub.neighbors(row)) + assert row_neighbors + + col_i, col_rest_1 = identity_partition_pauli_polynomial(pp, row, columns_to_use) + + remaining_qubits = [q for q in qubits_to_use if q != row] + qc_i, qc_prop_i = identity_recurse(col_i, remaining_qubits) + qc_out += qc_i + propagate_circuit(pp, qc_prop_i, col_rest_1) + # prepend propagated gates + qc_prop = qc_prop_i + qc_prop + + row_next = pick_row(pp, col_rest_1, row_neighbors) + # identity is empty on `row`, identify region with largest pauli + _, col_max, pauli_max, col_rest_2 = max_partition_pauli_polynomial( + pp, row, col_rest_1 + ) + + # find column identities on `row_next` in `col_max` + col_i_swap, col_rest_swap = identity_partition_pauli_polynomial( + pp, row_next, col_max + ) + col_rest_3 = col_rest_swap + col_rest_2 + + # this swap maximizes identity region that is recursed into identity_recurse + # we also know that this swap removes rotations from a non-cutting vertex + qc_swap, qc_prop_swap = swap_row(col_i_swap, row, row_next, pauli_max) + # Add swapping gates to output and propagate gates + # propagating qc_prop_swap jumbles paulis on `row` + qc_out += qc_swap + propagate_circuit(pp, qc_prop_swap, col_rest_3) + + qc_prop = qc_prop_swap + qc_prop + + # find new identities on `row` in `col_rest` and + col_i, col_rest_4 = identity_partition_pauli_polynomial(pp, row, col_rest_3) + # immediately recurse removing `row` + qc_i_re, qc_prop_i_re = identity_recurse(col_i_swap + col_i, remaining_qubits) + qc_out += qc_i_re + + propagate_circuit(pp, qc_prop_i_re, col_rest_4) + qc_prop = qc_prop_i_re + qc_prop + + # now if row and row_next have no identities, we p_recurse + col_i_row, col_rest_5 = identity_partition_pauli_polynomial(pp, row, col_rest_4) + + col_i_row_next, col_rest_6 = identity_partition_pauli_polynomial( + pp, row_next, col_rest_5 + ) + + # identity is empty on `row`, identify region with largest pauli + _, col_max, pauli_max, col_rest_7 = max_partition_pauli_polynomial( + pp, row, col_rest_6 + ) + col_rest_8 = col_i_row + col_i_row_next + col_rest_7 + # basically only called for perfect conditions, otherwise getting rid of I's makes more sense + + qc_p, qc_prop_p = p_recurse(col_max, qubits_to_use, row, row_next, pauli_max) + qc_out += qc_p + propagate_circuit(pp, qc_prop_p, col_rest_8) + qc_prop = qc_prop_p + qc_prop + # otherwise we continue removing identities + + qc_last, qc_prop_last = identity_recurse(col_rest_8, qubits_to_use) + qc_out += qc_last + qc_prop = qc_prop_last + qc_prop + + return qc_out, qc_prop + + def p_recurse(columns_to_use, qubits_to_use, row, row_next, rec_type): + """Always receives columns where `row` and `row_next` do not contain identities because functions here can reintroduce entanglement if identities exist""" + assert rec_type in [X, Y, Z] + # no check columns because all entries are non_identity + qc_out = Circuit(pp.num_qubits) + qc_prop = CliffordRegion(pp.num_qubits) + + if not columns_to_use or not qubits_to_use: + return qc_out, qc_prop + + if rec_type == X: + qc_out.h(row) + pp.propagate(H(row), columns_to_use) + elif rec_type == Y: + qc_out.v(row) + pp.propagate(Vdg(row), columns_to_use) + + col_i_row, _ = identity_partition_pauli_polynomial(pp, row, columns_to_use) + col_i, col_x, col_y, col_z = partition_pauli_polynomial( + pp, row_next, columns_to_use + ) + + # should never receive identity + assert not col_i_row + assert not col_i + + if not col_x and not col_y: + qc_one, qc_prop_one = simplify_one_pauli( + col_z, qubits_to_use, row, row_next, Z + ) + qc_out += qc_one + qc_prop = qc_prop_one + qc_prop + elif not col_x and not col_z: + qc_one, qc_prop_one = simplify_one_pauli( + col_y, qubits_to_use, row, row_next, Y + ) + qc_out += qc_one + qc_prop = qc_prop_one + qc_prop + elif not col_y and not col_z: + qc_one, qc_prop_one = simplify_one_pauli( + col_x, qubits_to_use, row, row_next, X + ) + qc_out += qc_one + qc_prop = qc_prop_one + qc_prop + elif not col_x: + qc_two, qc_prop_two = simplify_two_pauli( + col_y + col_z, qubits_to_use, row, row_next, Y, Z + ) + qc_out += qc_two + qc_prop = qc_prop_two + qc_prop + elif not col_y: + qc_two, qc_prop_two = simplify_two_pauli( + col_x + col_z, qubits_to_use, row, row_next, X, Z + ) + qc_out += qc_two + qc_prop = qc_prop_two + qc_prop + elif not col_z: + qc_two, qc_prop_two = simplify_two_pauli( + col_x + col_y, qubits_to_use, row, row_next, X, Y + ) + qc_out += qc_two + qc_prop = qc_prop_two + qc_prop + else: + qc_two, qc_prop_two = simplify_two_pauli( + col_y + col_z, qubits_to_use, row, row_next, Y, Z + ) + qc_out += qc_two + propagate_circuit(pp, qc_prop_two, col_x) + qc_prop = qc_prop_two + qc_prop + # this may introduce identity to the circuit, so identity recurse here + + qc_i, qc_prop_i = identity_recurse(col_x, qubits_to_use) + qc_out += qc_i + qc_prop = qc_prop_i + qc_prop + + if rec_type == X: + qc_prop.add_gate(H(row)) + elif rec_type == Y: + qc_prop.add_gate(Vdg(row)) + + return qc_out, qc_prop + + def simplify_two_pauli( + columns_to_use, qubits_to_use, row, row_next, rec_type_1, rec_type_2 + ): + qc_out = Circuit(pp.num_qubits) + qc_prop = CliffordRegion(pp.num_qubits) + if not columns_to_use or not qubits_to_use: + return qc_out, qc_prop + + if rec_type_1 == X and rec_type_2 == Y: + qc_out.h(row_next) + pp.propagate(H(row_next), columns_to_use) + elif rec_type_1 == X and rec_type_2 == Z: + qc_out.s(row_next) + pp.propagate(Sdg(row_next), columns_to_use) + + qc_out.cx(row, row_next) + pp.propagate(CX(row, row_next), columns_to_use) + + columns_to_use = [col for col in columns_to_use if pp[col][row_next] in [Z, Y]] + + remaining_qubits = [q for q in qubits_to_use if q != row] + # identity_recurse here because `next_row`` can contain identity + qc_iden, qc_prop_iden = identity_recurse(columns_to_use, remaining_qubits) + qc_out += qc_iden + + qc_prop = qc_prop_iden + qc_prop + qc_prop.add_gate(CX(row, row_next)) + + if rec_type_1 == X and rec_type_2 == Y: + qc_prop.add_gate(H(row_next)) + elif rec_type_1 == X and rec_type_2 == Z: + qc_prop.add_gate(Sdg(row_next)) + return qc_out, qc_prop + + def simplify_one_pauli(columns_to_use, qubits_to_use, row, row_next, rec_type): + qc_out = Circuit(pp.num_qubits) + qc_prop = CliffordRegion(pp.num_qubits) + if not columns_to_use or not qubits_to_use: + return qc_out, qc_prop + + if rec_type == X: + qc_out.h(row_next) + pp.propagate(H(row_next), columns_to_use) + elif rec_type == Y: + qc_out.v(row_next) + pp.propagate(Vdg(row_next), columns_to_use) + + qc_out.cx(row, row_next) + pp.propagate(CX(row, row_next), columns_to_use) + + columns_to_use = [col for col in columns_to_use if pp[col][row_next] in [Z]] + + remaining_qubits = [q for q in qubits_to_use if q != row] + + qc_iden, qc_prop_iden = identity_recurse(columns_to_use, remaining_qubits) + qc_out += qc_iden + qc_prop = qc_prop_iden + qc_prop + + qc_prop.add_gate(CX(row, row_next)) + + if rec_type == X: + qc_prop.add_gate(H(row_next)) + elif rec_type == Y: + qc_prop.add_gate(Vdg(row_next)) + + return qc_out, qc_prop + + def swap_row(columns_to_use, row, row_next, pauli_type): + """ + Converts `row,row_next` to `ZI` and converts it to `IZ`. Swaps `row` and `row_next` + based on pauli_type, returns added gates for swapping and gates for propagation + """ + qc_out = Circuit(pp.num_qubits) + qc_prop = CliffordRegion(pp.num_qubits) + if not columns_to_use: + return qc_out, qc_prop + if pauli_type == X: + qc_out.h(row) + pp.propagate(H(row), columns_to_use) + elif pauli_type == Y: + qc_out.v(row) + pp.propagate(Vdg(row), columns_to_use) + elif pauli_type == Z: + pass + + qc_out.cx(row_next, row) + qc_out.cx(row, row_next) + + pp.propagate(CX(row_next, row), columns_to_use) + pp.propagate(CX(row, row_next), columns_to_use) + + qc_prop.add_gate(CX(row, row_next)) + qc_prop.add_gate(CX(row_next, row)) + + if pauli_type == X: + qc_prop.add_gate(H(row)) + elif pauli_type == Y: + qc_prop.add_gate(Vdg(row)) + elif pauli_type == Z: + pass + + return qc_out, qc_prop + + def check_columns(columns_to_use): + qc = Circuit(pp.num_qubits) + to_remove = [] + for col in columns_to_use: + if pp[col].num_legs() == 1: + row = [q for q in range(pp.num_qubits) if pp[col][q] != I][0] + col_type = pp[col][row] + + if col_type == X: + qc.h(row) + elif col_type == Y: + qc.v(row) + + qc.rz(pp.pauli_gadgets[col].angle, row) + perm_gadgets.append(col) + to_remove.append(col) + + if col_type == X: + qc.h(row) + elif col_type == Y: + qc.vdg(row) + for col in to_remove: + columns_to_use.remove(col) + return qc + + circ_out = Circuit(pp.num_qubits) + columns_to_use = list(range(pp.num_gadgets)) + circ_out += check_columns(columns_to_use) + circ_recurse, circ_prop = identity_recurse( + columns_to_use, list(range(pp.num_qubits)) + ) + circ_prop, permutation = synthesize_tableau( + circ_prop.to_tableau(), topo, include_swaps=False + ) + + circ_out = circ_out + circ_recurse + circ_prop + circ_out.final_permutation = circ_prop.final_permutation + permutation = [permutation[i] for i in range(pp.num_qubits)] + return circ_out, perm_gadgets, permutation diff --git a/pauliopt/pauli/synthesis/synthesis_divide_and_conquer.py b/pauliopt/pauli/synthesis/synthesis_divide_and_conquer.py new file mode 100644 index 00000000..ee3218a2 --- /dev/null +++ b/pauliopt/pauli/synthesis/synthesis_divide_and_conquer.py @@ -0,0 +1,220 @@ +from typing import List, Union, Tuple + +from pauliopt.clifford.tableau import CliffordTableau +from pauliopt.clifford.tableau_synthesis import synthesize_tableau +from pauliopt.circuits import Circuit +from pauliopt.gates import CZ, CY, CX + +from pauliopt.pauli.pauli_gadget import PauliGadget +from pauliopt.pauli.pauli_polynomial import PauliPolynomial +from pauliopt.pauli.synthesis.annealing import get_best_gate +from pauliopt.pauli_strings import X, Y, Z, I +from pauliopt.topologies import Topology +import networkx as nx + +DESIRED_NEIGHBORS = [(X, X), (Y, X), (Z, Z), (Z, Y)] +UNDESIRABLE_NEIGHBORS = [(X, I), (Y, I), (Z, I)] + + +def compute_global_permutation(pp: PauliPolynomial, topology: Topology) -> dict: + """ + Compute a globally optimal permutation. + :param pp: + :param topology: + :return: + """ + matching_graph = nx.Graph() + for e1 in range(pp.num_qubits): + for e2 in range(pp.num_qubits): + if e1 != e2: + matching_graph.add_edge(e1, e2, weight=0) + matching_graph.add_nodes_from(range(pp.num_qubits)) + for gadget in pp.pauli_gadgets: + assert isinstance(gadget, PauliGadget) + for e1 in range(pp.num_qubits): + for e2 in range(pp.num_qubits): + if e1 != e2: + p1 = gadget.paulis[e1] + p2 = gadget.paulis[e2] + if (p1, p2) in DESIRED_NEIGHBORS or (p2, p1) in DESIRED_NEIGHBORS: + matching_graph[e1][e2]["weight"] += topology.dist(e1, e2) + elif (p1, p2) in UNDESIRABLE_NEIGHBORS or ( + p2, + p1, + ) in UNDESIRABLE_NEIGHBORS: + matching_graph[e1][e2]["weight"] -= topology.dist(e1, e2) + return dict(nx.maximal_matching(matching_graph)) + + +def optimize_pauli_polynomial( + clifford_left: CliffordTableau, + pp: PauliPolynomial, + clifford_right: CliffordTableau, + topology: Topology, + gate_set=None, + leg_cache=None, +) -> Tuple[CliffordTableau, PauliPolynomial, CliffordTableau]: + """ + Optimize a region of Clifford - PauliPolynomial - Clifford. + + :param clifford_left: + :param pp: + :param clifford_right: + :param topology: + :param gate_set: + :param leg_cache: + :return: + """ + if gate_set is None: + gate_set = [CX, CY, CZ] + + for c in range(pp.num_qubits): + for t in range(pp.num_qubits): + if c != t: + gate, effect = get_best_gate( + pp, c, t, gate_set, topology, leg_cache=leg_cache + ) + dist = topology.dist(c, t) + if effect + 2 * dist <= 0: + pp.propagate_inplace(gate) + clifford_left.append_gate(gate) + clifford_right.prepend_gate(gate) + + return clifford_left, pp, clifford_right + + +def compare( + pp: PauliPolynomial, prev_gadget: int, current_gadget: int, next_gadget: int +) -> bool: + """ + Compare the previous and next gadget to the current gadget. + :param pp: + :param prev_gadget: + :param current_gadget: + :param next_gadget: + :return: + """ + return pp.commutes(current_gadget, next_gadget) and ( + pp.mutual_legs(prev_gadget, current_gadget) + < pp.mutual_legs(prev_gadget, next_gadget) + ) + + +def sort_pauli_polynomial(pp: PauliPolynomial) -> PauliPolynomial: + """ + Insertion sort for the Pauli Polynomial. + :param pp: + :return: + """ + col_idx = 1 + while col_idx < pp.num_gadgets - 1: + prev_col_idx = col_idx - 1 + col_idx_ = col_idx + new_col_idx = col_idx + while new_col_idx < pp.num_gadgets and compare( + pp, prev_col_idx, col_idx_, new_col_idx + ): + pp.swap_gadgets(col_idx_, new_col_idx) + prev_col_idx = col_idx_ + col_idx_ = new_col_idx + new_col_idx = col_idx_ + 1 + col_idx += 1 + return pp + + +def split_pauli_polynomial( + pp: PauliPolynomial, +) -> Tuple[PauliPolynomial, PauliPolynomial]: + """ + Split the Pauli Polynomial into two regions. + :param pp: + :return: + """ + pp_left = PauliPolynomial(pp.num_qubits) + pp_right = PauliPolynomial(pp.num_qubits) + + for gadget in pp.pauli_gadgets[: pp.num_gadgets // 2]: + pp_left >>= gadget + + for gadget in pp.pauli_gadgets[pp.num_gadgets // 2 :]: + pp_right >>= gadget + + return pp_left, pp_right + + +def recursion_synth_divide_and_conquer( + c_l: CliffordTableau, + pp: PauliPolynomial, + c_r: CliffordTableau, + topology: Topology, + leg_cache=None, +) -> List[Union[CliffordTableau, PauliPolynomial]]: + """ + Recursive definition of the algorithm. + + 1. optimize the PP + 2. IF the number of gadgets are smaller than two return + 2. ELSE split the PP and optimize the two subregions by testing every combination + 3. Recurse on both subregions + 4. Combine and continue + :param c_l: + :param pp: + :param c_r: + :param topology: + :param leg_cache: + :return: + """ + c_l, pp, c_r = optimize_pauli_polynomial( + c_l, pp, c_r, topology, leg_cache=leg_cache + ) + if pp.num_gadgets <= 2: + return [c_l, pp, c_r] + + c_center = CliffordTableau(pp.num_qubits) + pp = sort_pauli_polynomial(pp) + pp_left, pp_right = split_pauli_polynomial(pp) + regions_left = recursion_synth_divide_and_conquer( + c_l, pp_left, c_center, topology, leg_cache=leg_cache + ) + regions_right = recursion_synth_divide_and_conquer( + c_center, pp_right, c_r, topology, leg_cache=leg_cache + ) + + return regions_left[:-1] + [c_center] + regions_right[1:] + + +def synthesis_divide_and_conquer( + pp: PauliPolynomial, topology: Topology +) -> Tuple[Circuit, List]: + """ + Divide and conquer synthesis. + + Will return a circuit that is synthesized with an additional global placement of qubits. + See: TODO reference + + :param pp: + :param topology: + :return: + """ + permutation = compute_global_permutation(pp, topology) + pp.permute(permutation) + + c_l = CliffordTableau(pp.num_qubits) + c_r = CliffordTableau(pp.num_qubits) + legs_cache = {} + regions = recursion_synth_divide_and_conquer( + c_l, pp, c_r, topology, leg_cache=legs_cache + ) + + circ_out = Circuit(pp.num_qubits) + for region in regions: + if isinstance(region, PauliPolynomial): + circ_out += region.to_circuit(topology=topology) + else: + circ, _ = synthesize_tableau(region, topology, include_swaps=False) + circ_out += circ + + qubit_placement = list(range(pp.num_qubits)) + for i, j in permutation.items(): + qubit_placement[i], qubit_placement[j] = qubit_placement[j], qubit_placement[i] + return circ_out, qubit_placement diff --git a/pauliopt/pauli/utils.py b/pauliopt/pauli/utils.py index 01d990d9..e69de29b 100644 --- a/pauliopt/pauli/utils.py +++ b/pauliopt/pauli/utils.py @@ -1,14 +0,0 @@ -from enum import Enum - - -class Pauli(Enum): - I = "I" - X = "X" - Y = "Y" - Z = "Z" - - -I = Pauli.I -X = Pauli.X -Y = Pauli.Y -Z = Pauli.Z diff --git a/pauliopt/pauli_strings.py b/pauliopt/pauli_strings.py new file mode 100644 index 00000000..04dd2887 --- /dev/null +++ b/pauliopt/pauli_strings.py @@ -0,0 +1,74 @@ +from enum import Enum + +PAULI_DICT = { + ("X", "X"): (1, "I"), + ("X", "Y"): (1j, "Z"), + ("X", "Z"): (-1j, "Y"), + ("X", "I"): (1, "X"), + ("Y", "X"): (-1j, "Z"), + ("Y", "Y"): (1, "I"), + ("Y", "Z"): (1j, "X"), + ("Y", "I"): (1, "Y"), + ("Z", "X"): (1j, "Y"), + ("Z", "Y"): (-1j, "X"), + ("Z", "Z"): (1, "I"), + ("Z", "I"): (1, "Z"), + ("I", "X"): (1, "X"), + ("I", "Y"): (1, "Y"), + ("I", "Z"): (1, "Z"), + ("I", "I"): (1, "I"), +} + + +class Pauli(Enum): + I = "I" + X = "X" + Y = "Y" + Z = "Z" + + def __add__(self, other): + if isinstance(other, Pauli): + summands = [(1, self), (1, other)] + return SummedPauliOp(summands, 1) + elif isinstance(other, SummedPauliOp): + if other.n_qubits != 1: + raise ValueError("SummedPauliOp must have n_qubits=1") + summands = [(1, self)] + other.summands + return SummedPauliOp(summands, 1) + else: + raise ValueError("Cannot add Pauli to {}".format(type(other))) + + def __matmul__(self, other): + if isinstance(other, Pauli): + sign, res = PAULI_DICT[(self.value, other.value)] + res = Pauli(res) + return SummedPauliOp([(sign, res)], 1) + elif isinstance(other, SummedPauliOp): + if other.n_qubits != 1: + raise ValueError("SummedPauliOp must have n_qubits=1") + summands = [] + for sign, pauli in other.summands: + new_sign, res = PAULI_DICT[(self.value, pauli.value)] + res = Pauli(res) + summands.append((sign * new_sign, res)) + return SummedPauliOp(summands, 1) + elif isinstance(other, float): + return SummedPauliOp([(other, self)], 1) + else: + raise ValueError("Cannot add Pauli to {}".format(type(other))) + + def __xor__(self, other): + if isinstance(other, Pauli): + return SummedPauliOp([(1, [self, other])], 2) + + +class SummedPauliOp: + def __init__(self, summands, n_qubits): + self.summands = summands + self.n_qubits = n_qubits + + +I = Pauli.I +X = Pauli.X +Y = Pauli.Y +Z = Pauli.Z diff --git a/pauliopt/utils.py b/pauliopt/utils.py index 5b34acf2..ad63619f 100644 --- a/pauliopt/utils.py +++ b/pauliopt/utils.py @@ -25,6 +25,17 @@ Union, ) import numpy as np +import networkx as nx + + +def is_cutting(vertex, g): + """ + Check if the given vertex is a cutting vertex in the given graph. + + :param vertex: The vertex to check + :param g: The graph to check + """ + return vertex in nx.articulation_points(g) def calculate_orthogonal_point(a, b, d, left): @@ -44,7 +55,7 @@ def calculate_orthogonal_point(a, b, d, left): return int(orthogonal_point[0]), int(orthogonal_point[1]) -AngleInitT = Union[int, Fraction, str, Decimal] +AngleInitT = Union[int, Fraction, str, Decimal, float] class AngleExpr(ABC): @@ -787,7 +798,7 @@ def rect( x, y = centre tag = ( f'' ) self._tags.append(tag) @@ -805,7 +816,7 @@ def text( if not isinstance(font_size, int) or font_size <= 0: raise TypeError("Font size must be positive integer.") x, y = pos - attrs = f'x="{x}" y="{y+font_size//4}" font-size="{font_size}"' + attrs = f'x="{x}" y="{y + font_size // 4}" font-size="{font_size}"' attrs += f' text-anchor="middle"' if center else "" tag = f"{text}" self._tags.append(tag) @@ -937,7 +948,6 @@ def temp_schedule(it: int, num_iters: int) -> float: Names of the standard temperature schedules. """ - StandardTempSchedule = Tuple[ StandardTempScheduleName, Union[int, float], Union[int, float] ] @@ -945,7 +955,6 @@ def temp_schedule(it: int, num_iters: int) -> float: Type for standard temperature schedules. """ - StandardTempSchedules: Final[ Mapping[StandardTempScheduleName, TempScheduleProvider] ] = { diff --git a/requirements-dev.in b/requirements-dev.in new file mode 100644 index 00000000..90b9e2ea --- /dev/null +++ b/requirements-dev.in @@ -0,0 +1,9 @@ +-r requirements.in +pytket~=1.11 +pytket-qiskit~=0.34 +qiskit~=0.39 +galois~=0.3 +parameterized +notebook +black +pip-tools \ No newline at end of file diff --git a/requirements-dev.txt b/requirements-dev.txt index ab47008d..51ee265e 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,9 +1,144 @@ -networkx==2.6.2 -numpy>=1.21.0 -pytket==1.11.0 -pytket-qiskit==0.34.0 -qiskit==0.39.0 -galois==0.3.7 +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate requirements-dev.in +# +anyio==4.4.0 +appnope==0.1.4 +argon2-cffi==23.1.0 +argon2-cffi-bindings==21.2.0 +arrow==1.3.0 +asttokens==2.4.1 +async-lru==2.0.4 +attrs==24.2.0 +babel==2.16.0 +beautifulsoup4==4.12.3 +black==24.8.0 +bleach==6.1.0 +build==1.2.1 +certifi==2024.7.4 +cffi==1.17.0 +charset-normalizer==3.3.2 +click==8.1.7 +comm==0.2.2 +cryptography==43.0.0 +debugpy==1.8.5 +decorator==5.1.1 +defusedxml==0.7.1 +dill==0.3.8 +exceptiongroup==1.2.2 +executing==2.0.1 +fastjsonschema==2.20.0 +fqdn==1.5.1 +galois==0.4.1 +graphviz==0.20.3 +h11==0.14.0 +httpcore==1.0.5 +httpx==0.27.0 +ibm-cloud-sdk-core==3.20.6 +ibm-platform-services==0.55.3 +idna==3.7 +ipykernel==6.29.5 +ipython==8.26.0 +isoduration==20.11.0 +jedi==0.19.1 +jinja2==3.1.4 +json5==0.9.25 +jsonpointer==3.0.0 +jsonschema[format-nongpl]==4.23.0 +jsonschema-specifications==2023.12.1 +jupyter-client==8.6.2 +jupyter-core==5.7.2 +jupyter-events==0.10.0 +jupyter-lsp==2.2.5 +jupyter-server==2.14.2 +jupyter-server-terminals==0.5.3 +jupyterlab==4.2.4 +jupyterlab-pygments==0.3.0 +jupyterlab-server==2.27.3 +lark==1.1.9 +llvmlite==0.43.0 +markupsafe==2.1.5 +matplotlib-inline==0.1.7 +mistune==3.0.2 +mpmath==1.3.0 +mypy-extensions==1.0.0 +nbclient==0.10.0 +nbconvert==7.16.4 +nbformat==5.10.4 +nest-asyncio==1.6.0 +networkx==3.3 +notebook==7.2.1 +notebook-shim==0.2.4 +numba==0.60.0 +numpy==1.26.4 +overrides==7.7.0 +packaging==24.1 +pandocfilters==1.5.1 parameterized==0.9.0 -notebook==7.0.7 -black==24.3.0 +parso==0.8.4 +pathspec==0.12.1 +pbr==6.0.0 +pexpect==4.9.0 +pip-tools==7.4.1 +platformdirs==4.2.2 +ply==3.11 +prometheus-client==0.20.0 +prompt-toolkit==3.0.47 +psutil==6.0.0 +ptyprocess==0.7.0 +pure-eval==0.2.3 +pycparser==2.22 +pygments==2.18.0 +pyjwt==2.9.0 +pyproject-hooks==1.1.0 +pyspnego==0.11.1 +python-dateutil==2.9.0.post0 +python-json-logger==2.0.7 +pytket==1.31.1 +pytket-qiskit==0.48.0 +pyyaml==6.0.2 +pyzmq==26.1.0 +qiskit==0.45.3 +qiskit-aer==0.13.3 +qiskit-algorithms==0.2.2 +qiskit-ibm-provider==0.8.0 +qiskit-ibm-runtime==0.17.0 +qiskit-terra==0.45.3 +qwasm==1.0.1 +referencing==0.35.1 +requests==2.32.3 +requests-ntlm==1.3.0 +rfc3339-validator==0.1.4 +rfc3986-validator==0.1.1 +rpds-py==0.20.0 +rustworkx==0.15.1 +scipy==1.14.0 +send2trash==1.8.3 +six==1.16.0 +sniffio==1.3.1 +soupsieve==2.5 +stack-data==0.6.3 +stevedore==5.2.0 +symengine==0.11.0 +sympy==1.13.1 +terminado==0.18.1 +tinycss2==1.3.0 +tomli==2.0.1 +tornado==6.4.1 +traitlets==5.14.3 +types-python-dateutil==2.9.0.20240316 +typing-extensions==4.12.2 +uri-template==1.3.0 +urllib3==2.2.2 +wcwidth==0.2.13 +webcolors==24.8.0 +webencodings==0.5.1 +websocket-client==1.8.0 +websockets==12.0 +wheel==0.44.0 + +# The following packages are considered to be unsafe in a requirements file: +pip==24.2 +setuptools==72.1.0 diff --git a/requirements.in b/requirements.in new file mode 100644 index 00000000..c1fc4929 --- /dev/null +++ b/requirements.in @@ -0,0 +1,2 @@ +networkx +numpy \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..2bf7bc53 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate requirements.in +# +networkx==3.3 +numpy==2.0.1 diff --git a/test.py b/test.py deleted file mode 100644 index 82c77018..00000000 --- a/test.py +++ /dev/null @@ -1,28 +0,0 @@ -from math import pi - -from qiskit import QuantumCircuit -from qiskit.circuit import CircuitInstruction -from qiskit.circuit.random import random_circuit - - -def get_qubits(qubits, qreg): - qubits_ = [] - for qubit in qubits: - qubits_.append(qreg.index(qubit)) - - return tuple(qubits_) - - -def main(): - qc = random_circuit(10, 4) - - qreg = qc.qregs[0] - - ci = CircuitInstruction - for op in qc: - for qubit in op.qubits: - print(qubit) - - -if __name__ == "__main__": - main() diff --git a/tests/clifford/__init__.py b/tests/clifford/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/tableau/test_clifford_synthesis.py b/tests/clifford/test_clifford_synthesis.py similarity index 92% rename from tests/tableau/test_clifford_synthesis.py rename to tests/clifford/test_clifford_synthesis.py index 06098bb1..4f19d67a 100644 --- a/tests/tableau/test_clifford_synthesis.py +++ b/tests/clifford/test_clifford_synthesis.py @@ -5,7 +5,7 @@ from pauliopt.clifford.tableau import CliffordTableau from pauliopt.clifford.tableau_synthesis import synthesize_tableau -from tests.tableau.utils import tableau_from_circuit +from tests.clifford.utils import tableau_from_circuit from tests.utils import verify_equality, random_hscx_circuit from pauliopt.topologies import Topology @@ -34,6 +34,6 @@ def test_clifford_synthesis(self, _, n_qubits, n_gates, topo, include_swaps): qc = qc.to_qiskit() self.assertTrue( - verify_equality(circuit, qc), + verify_equality(circuit.to_qiskit(), qc), "The Synthesized circuit does not equal to original", ) diff --git a/tests/tableau/test_tableau_operations.py b/tests/clifford/test_tableau_operations.py similarity index 70% rename from tests/tableau/test_tableau_operations.py rename to tests/clifford/test_tableau_operations.py index 93c23d66..7302c2bc 100644 --- a/tests/tableau/test_tableau_operations.py +++ b/tests/clifford/test_tableau_operations.py @@ -5,11 +5,12 @@ from parameterized import parameterized from qiskit import QuantumCircuit, transpile +from pauliopt.circuits import Circuit from pauliopt.clifford.tableau import CliffordTableau from pauliopt.clifford.tableau_synthesis import synthesize_tableau from pauliopt.topologies import Topology -from tests.tableau.utils import tableau_from_circuit_prepend, tableau_from_circuit -from tests.utils import verify_equality, random_hscx_circuit +from tests.clifford.utils import tableau_from_circuit_prepend, tableau_from_circuit +from tests.utils import verify_equality, random_hscx_circuit, random_clifford_circuit class TestTableauOperations(unittest.TestCase): @@ -26,11 +27,12 @@ def test_inverse(self, n_qubits): self.assertTrue( np.allclose(ct.tableau, ct_.tableau), - "The twice inverted tableau did not match", + "The twice inverted clifford did not match", ) self.assertTrue( - np.allclose(ct.signs, ct_.signs), "The twice inverted tableau did not match" + np.allclose(ct.signs, ct_.signs), + "The twice inverted clifford did not match", ) @parameterized.expand([(5,), (10,), (15,)]) @@ -44,11 +46,12 @@ def test_tableau_construction(self, n_qubits): self.assertTrue( np.allclose(ct.tableau, ct_.tableau), - "The twice inverted tableau did not match", + "The twice inverted clifford did not match", ) self.assertTrue( - np.allclose(ct.signs, ct_.signs), "The twice inverted tableau did not match" + np.allclose(ct.signs, ct_.signs), + "The twice inverted clifford did not match", ) @parameterized.expand([(5,), (10,), (15,)]) @@ -58,30 +61,32 @@ def test_tableau_apply(self, n_qubits): ct = CliffordTableau(n_qubits) ct = tableau_from_circuit(ct, circuit) - circuit_ = transpile(circuit.inverse(), basis_gates=["h", "s", "cx"]) - + circuit_ = transpile( + circuit.to_qiskit().inverse(), basis_gates=["h", "s", "cx"] + ) + circuit_ = Circuit.from_qiskit(circuit_) ct_ = CliffordTableau(n_qubits) ct_ = tableau_from_circuit(ct_, circuit_) ct = ct.apply(ct_) self.assertTrue( np.allclose(ct.tableau, np.eye(2 * n_qubits)), - "The inverted tableau did not match the identity", + "The inverted clifford did not match the identity", ) @parameterized.expand([(5,), (6,)]) def test_tableau_construction_prepend(self, n_qubits): topo = Topology.complete(n_qubits) - circuit = random_hscx_circuit(nr_qubits=n_qubits, nr_gates=1000) - + circuit = random_clifford_circuit(nr_qubits=n_qubits, nr_gates=1000) ct = CliffordTableau(n_qubits) - ct = tableau_from_circuit_prepend(ct, circuit) + for gate in circuit.gates: + ct.prepend_gate(gate) qc, perm = synthesize_tableau(ct, topo, include_swaps=False) qc = qc.to_qiskit() self.assertTrue( - verify_equality(circuit.reverse_ops(), qc), + verify_equality(circuit.to_qiskit().reverse_ops(), qc), "The Synthesized circuit does not equal " "to the original with reversed ops", ) @@ -98,5 +103,5 @@ def test_string_representation(self): self.assertEqual( str(ct), f.read(), - "The string representation of the tableau is incorrect", + "The string representation of the clifford is incorrect", ) diff --git a/tests/tableau/utils.py b/tests/clifford/utils.py similarity index 53% rename from tests/tableau/utils.py rename to tests/clifford/utils.py index 0ca7eab3..7ac02870 100644 --- a/tests/tableau/utils.py +++ b/tests/clifford/utils.py @@ -1,20 +1,12 @@ from qiskit import QuantumCircuit +from pauliopt.circuits import Circuit +from pauliopt.clifford.tableau import CliffordTableau -def tableau_from_circuit(tableau, circ: QuantumCircuit): - qreg = circ.qregs[0] - for op in circ: - if op.operation.name == "h": - tableau.append_h(qreg.index(op.qubits[0])) - elif op.operation.name == "s": - tableau.append_s(qreg.index(op.qubits[0])) - elif op.operation.name == "cx": - tableau.append_cnot(qreg.index(op.qubits[0]), qreg.index(op.qubits[1])) - else: - raise TypeError( - f"Unrecongnized Gate type: {op.operation.name} for Clifford Tableaus" - ) +def tableau_from_circuit(tableau: CliffordTableau, circ: Circuit): + for gate in circ.gates: + tableau.append_gate(gate) return tableau diff --git a/tests/pauli/__init__.py b/tests/pauli/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/pauli/simplification/__init__.py b/tests/pauli/simplification/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/pauli/simplification/test_pauli_simplification.py b/tests/pauli/simplification/test_pauli_simplification.py new file mode 100644 index 00000000..90c1af75 --- /dev/null +++ b/tests/pauli/simplification/test_pauli_simplification.py @@ -0,0 +1,19 @@ +import unittest + +from pauliopt.pauli.simplification.simple_simplify import simplify_pauli_polynomial +from tests.pauli.utils import generate_random_pauli_polynomial, verify_equality + + +class TestPauliSimplification(unittest.TestCase): + + def test_simplification_process(self): + for num_qubits in [4, 6]: + for phase_gadget in [100, 200, 300, 400]: + pp = generate_random_pauli_polynomial(num_qubits, phase_gadget) + + pp_ = simplify_pauli_polynomial(pp) + print() + self.assertTrue( + verify_equality(pp_.to_qiskit(), pp.to_qiskit()), + "Resulting circuits where not equal", + ) diff --git a/tests/pauli/synthesis/__init__.py b/tests/pauli/synthesis/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/pauli/synthesis/test_annealing.py b/tests/pauli/synthesis/test_annealing.py new file mode 100644 index 00000000..1fdc55a3 --- /dev/null +++ b/tests/pauli/synthesis/test_annealing.py @@ -0,0 +1,23 @@ +import unittest + +from pauliopt.pauli.synthesis.annealing import annealing_synthesis +from pauliopt.topologies import Topology +from tests.pauli.utils import generate_random_pauli_polynomial, verify_equality + + +class TestPauliSynthesis(unittest.TestCase): + def test_pauli_annealing(self): + for num_gadgets in [100]: + for topo in [ + Topology.line(4), + Topology.line(6), + Topology.cycle(4), + Topology.grid(2, 4), + ]: + pp = generate_random_pauli_polynomial(topo.num_qubits, num_gadgets) + pp_ = pp.copy() + qc_out = annealing_synthesis(pp, topo).to_qiskit() + + self.assertTrue( + verify_equality(qc_out, pp_.to_qiskit()), "Circuits did not match" + ) diff --git a/tests/pauli/synthesis/test_steiner_gray_clifford.py b/tests/pauli/synthesis/test_steiner_gray_clifford.py new file mode 100644 index 00000000..d7c1c00b --- /dev/null +++ b/tests/pauli/synthesis/test_steiner_gray_clifford.py @@ -0,0 +1,34 @@ +import unittest + +from pauliopt.pauli.synthesis.annealing import annealing_synthesis +from pauliopt.pauli.synthesis.steiner_gray_synthesis import ( + pauli_polynomial_steiner_gray_clifford, +) +from pauliopt.topologies import Topology +from tests.pauli.utils import ( + generate_random_pauli_polynomial, + verify_equality, + apply_permutation, +) + + +class TestPauliSteinerGraySynthesis(unittest.TestCase): + def test_steiner_gray_clifford(self): + for num_gadgets in [100, 200]: + for topo in [ + Topology.complete(4), + Topology.line(4), + Topology.line(6), + Topology.cycle(4), + Topology.grid(2, 4), + ]: + pp = generate_random_pauli_polynomial(topo.num_qubits, num_gadgets) + pp_ = pp.copy() + circ_out, gadget_perm, perm = pauli_polynomial_steiner_gray_clifford( + pp, topo + ) + + pp_.pauli_gadgets = [pp_[i].copy() for i in gadget_perm] + circ_out = apply_permutation(circ_out.to_qiskit(), perm) + + self.assertTrue(verify_equality(circ_out, pp_.to_qiskit())) diff --git a/tests/pauli/synthesis/test_synthesis_divide_and_conquer.py b/tests/pauli/synthesis/test_synthesis_divide_and_conquer.py new file mode 100644 index 00000000..5213ef2b --- /dev/null +++ b/tests/pauli/synthesis/test_synthesis_divide_and_conquer.py @@ -0,0 +1,33 @@ +import unittest + +from pauliopt.pauli.synthesis.synthesis_divide_and_conquer import ( + synthesis_divide_and_conquer, +) +from pauliopt.topologies import Topology +from tests.pauli.utils import ( + generate_random_pauli_polynomial, + verify_equality, + apply_permutation, +) + + +class TestPauliSynthesis(unittest.TestCase): + def test_pauli_annealing(self): + for num_gadgets in [100, 200]: + for topo in [ + Topology.complete(4), + Topology.line(6), + Topology.cycle(4), + Topology.grid(2, 4), + ]: + pp = generate_random_pauli_polynomial(topo.num_qubits, num_gadgets) + pp_ = pp.copy() + + qc_out, permutation = synthesis_divide_and_conquer(pp, topo) + + qc_out = qc_out.to_qiskit() + qc_out = apply_permutation(qc_out, permutation) + + self.assertTrue( + verify_equality(qc_out, pp_.to_qiskit()), "Circuits did not match" + ) diff --git a/tests/pauli/test_pauli_propagation.py b/tests/pauli/test_pauli_propagation.py new file mode 100644 index 00000000..c7b46c5b --- /dev/null +++ b/tests/pauli/test_pauli_propagation.py @@ -0,0 +1,56 @@ +import unittest + +from qiskit import QuantumCircuit +from tests.pauli.utils import ( + generate_all_combination_pauli_polynomial, + pauli_poly_to_tket, + verify_equality, + check_matching_architecture, + get_two_qubit_count, + generate_random_depth_1_clifford, +) +from pauliopt.circuits import CX, CY, CZ, H, S, V, Circuit +from pauliopt.gates import Vdg, Sdg, Y, X, Z, SWAP +from pauliopt.topologies import Topology + + +class TestPauliPropagation(unittest.TestCase): + def test_circuit_construction(self): + for num_qubits in [2, 3, 4]: + for topo_creation in [Topology.line, Topology.complete]: + pp = generate_all_combination_pauli_polynomial(n_qubits=num_qubits) + + topology = topo_creation(pp.num_qubits) + tket_pp = pauli_poly_to_tket(pp) + our_synth = pp.to_qiskit(topology) + self.assertTrue( + verify_equality(tket_pp, our_synth), + "The resulting Quantum Circuits were not equivalent", + ) + self.assertTrue( + check_matching_architecture(our_synth, topology.to_nx), + "The Pauli Polynomial did not match the architecture", + ) + self.assertEqual( + get_two_qubit_count(our_synth), + pp.two_qubit_count(topology), + "Two qubit count needs to be equivalent to to two qubit count of the circuit", + ) + + def test_gate_propagation(self): + for num_qubits in [2, 3, 4]: + pp = generate_all_combination_pauli_polynomial(n_qubits=num_qubits) + inital_qc = pp.to_qiskit() + for gate_class in [H, S, CX, V, Vdg, Sdg, X, Y, Z, CY, CZ, SWAP]: + gate = generate_random_depth_1_clifford(gate_class, num_qubits) + gate_circ = Circuit(num_qubits) + gate_circ.add_gate(gate) + pp_ = pp.copy().propagate(gate) + qc = QuantumCircuit(num_qubits) + qc.compose(gate_circ.to_qiskit().inverse(), inplace=True) + qc.compose(pp_.to_qiskit(), inplace=True) + qc.compose(gate_circ.to_qiskit(), inplace=True) + self.assertTrue( + verify_equality(inital_qc, qc), + "The resulting Quantum Circuits were not equivalent", + ) diff --git a/tests/pauli/test_pauli_representation.py b/tests/pauli/test_pauli_representation.py new file mode 100644 index 00000000..d2c162ea --- /dev/null +++ b/tests/pauli/test_pauli_representation.py @@ -0,0 +1,156 @@ +import unittest + +from pauliopt.pauli.pauli_gadget import PPhase +from pauliopt.pauli.pauli_polynomial import PauliPolynomial +from pauliopt.pauli_strings import I, X, Z, Y +from pauliopt.topologies import Topology +from pauliopt.utils import Angle, pi +import os + +_PAULI_REPR = "PPhase(π/2) @ [ I, X, Y, Z ]\nPPhase(π/4) @ [ X, X, Y, X ]" + +SVG_CODE_PAULI = '\n\n\n\n\n\n\n\n\n\n\n\nπ\n\n\n\n\n\n\n\n\n\nπ/2\n\n\n\n\n\n\n\n\n\nπ/256\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nπ/8\n\n\n\n\n\n\n\n\n\nπ/4\n\n\n\n\n\n\n\n\n\nπ/2\n\n\n\n\n\n' + +LATEX_CODE_PAULI = """\documentclass[preview]{standalone} + +\\usepackage{tikz} +\\usetikzlibrary{zx-calculus} +\\usetikzlibrary{quantikz} +\\usepackage{graphicx} + +\\tikzset{ +diagonal fill/.style 2 args={fill=#2, path picture={ +\\fill[#1, sharp corners] (path picture bounding box.south west) -| + (path picture bounding box.north east) -- cycle;}}, +reversed diagonal fill/.style 2 args={fill=#2, path picture={ +\\fill[#1, sharp corners] (path picture bounding box.north west) |- + (path picture bounding box.south east) -- cycle;}} +} + +\\tikzset{ +diagonal fill/.style 2 args={fill=#2, path picture={ +\\fill[#1, sharp corners] (path picture bounding box.south west) -| + (path picture bounding box.north east) -- cycle;}} +} + +\\tikzset{ +pauliY/.style={ +zxAllNodes, +zxSpiders, +inner sep=0mm, +minimum size=2mm, +shape=rectangle, +%fill=colorZxX +diagonal fill={colorZxX}{colorZxZ} +} +} + +\\tikzset{ +pauliX/.style={ +zxAllNodes, +zxSpiders, +inner sep=0mm, +minimum size=2mm, +shape=rectangle, +fill=colorZxX +} +} + +\\tikzset{ +pauliZ/.style={ +zxAllNodes, +zxSpiders, +inner sep=0mm, +minimum size=2mm, +shape=rectangle, +fill=colorZxZ +} +} + +\\tikzset{ +pauliPhase/.style={ +zxAllNodes, +zxSpiders, +inner sep=0.5mm, +minimum size=2mm, +shape=rectangle, +fill=white +} +} +\\begin{document} +\\begin{ZX} +\\zxNone{} & \\zxNone{} & |[pauliPhase]| \\pi & \\zxNone{} & \\zxNone{} & |[pauliPhase]| \\pi & \\zxNone{} & \\zxNone{} & |[pauliPhase]| \\frac{\\pi}{2} & \\zxNone{} &\\\\ +\\\\ +\\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar &\\\\ +\\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar &\\\\ +\\zxNone{} \\rar & |[pauliX]| \\ar[ruuuu, bend right] \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & |[pauliX]| \\ar[ruuuu, bend right] \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & |[pauliX]| \\ar[ruuuu, bend right] \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar &\\\\ +\\zxNone{} \\rar & |[pauliZ]| \\ar[ruuuuu, bend right] \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & |[pauliZ]| \\ar[ruuuuu, bend right] \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & |[pauliZ]| \\ar[ruuuuu, bend right] \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar &\\\\ +\\zxNone{} \\rar & |[pauliY]| \\ar[ruuuuuu, bend right] \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & |[pauliY]| \\ar[ruuuuuu, bend right] \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar & |[pauliY]| \\ar[ruuuuuu, bend right] \\rar & \\zxNone{} \\rar & \\zxNone{} \\rar &\\\\ +\\end{ZX} +\\end{document} +""" + + +class TestPauliConversion(unittest.TestCase): + + def test_circuit_construction(self): + pp = PauliPolynomial(4) + + pp >>= PPhase(Angle(pi / 2)) @ [I, X, Y, Z] + + self.assertEqual(pp.num_qubits, 4) + self.assertEqual(len(pp), 1) + + pp >>= PPhase(Angle(pi / 4)) @ [X, X, Y, X] + print(pp) + self.assertEqual(pp.__repr__(), _PAULI_REPR) + self.assertEqual(len(pp), 2) + + pp_ = PauliPolynomial(num_qubits=4) + pp_ >> pp + + self.assertEqual( + pp.__repr__(), + pp_.__repr__(), + "Right shift resulted in different pauli Polynomials.", + ) + + def test_circuit_visualisation_svg(self): + pp = PauliPolynomial(5) + + pp >>= PPhase(Angle(pi)) @ [I, I, X, Z, Y] + pp >>= PPhase(Angle(pi / 2)) @ [X, X, I, I, Y] + pp >>= PPhase(Angle(pi / 256)) @ [X, I, I, Z, Y] + pp >>= PPhase(Angle(pi / 8)) @ [X, X, X, Z, Y] + pp >>= PPhase(Angle(pi / 4)) @ [X, Z, I, I, Y] + pp >>= PPhase(Angle(pi / 2)) @ [X, I, I, Y, Y] + + self.assertEqual(pp.to_svg(svg_code_only=True), SVG_CODE_PAULI) + + def test_circuit_visualization_latex(self): + pp = PauliPolynomial(5) + + pp >>= PPhase(Angle(pi)) @ [I, I, X, Z, Y] + pp >>= PPhase(Angle(pi)) @ [I, I, X, Z, Y] + pp >>= PPhase(Angle(pi / 2)) @ [I, I, X, Z, Y] + + self.assertEqual(pp.to_latex(), LATEX_CODE_PAULI) + + pp.to_latex(file_name="test") + self.assertTrue(os.path.isfile("./test.tex")) + with open("./test.tex", "r") as f: + content = f.read() + self.assertEqual(LATEX_CODE_PAULI, content) + os.remove("./test.tex") + + def test_two_qubit_count(self): + pp = PauliPolynomial(5) + + pp >>= PPhase(Angle(pi)) @ [I, I, X, Z, Y] + pp >>= PPhase(Angle(pi)) @ [I, I, X, Z, Y] + pp >>= PPhase(Angle(pi / 2)) @ [I, I, X, Z, Y] + + self.assertEqual( + pp.two_qubit_count(Topology.complete(pp.num_qubits)), + pp.to_qiskit().count_ops()["cx"], + ) diff --git a/tests/pauli/utils.py b/tests/pauli/utils.py new file mode 100644 index 00000000..47ad4a6c --- /dev/null +++ b/tests/pauli/utils.py @@ -0,0 +1,188 @@ +import itertools + +import networkx as nx +import numpy as np +import pytket +from pytket._tket.circuit import PauliExpBox +from pytket._tket.pauli import I as TketI +from pytket._tket.pauli import X as TketX +from pytket._tket.pauli import Y as TketY +from pytket._tket.pauli import Z as TketZ +from pytket._tket.transform import Transform +from pytket.extensions.qiskit.qiskit_convert import tk_to_qiskit +from qiskit import QuantumCircuit + +from pauliopt.pauli.pauli_gadget import PPhase +from pauliopt.pauli.pauli_polynomial import PauliPolynomial +from pauliopt.pauli_strings import X, Y, Z, I + +PAULI_TO_TKET = {X: TketX, Y: TketY, Z: TketZ, I: TketI} + + +def apply_permutation(qc: QuantumCircuit, permutation: list) -> QuantumCircuit: + """ + Apply a permutation to a qiskit quantum circuit. + :param qc: + :param permutation: + :return: + """ + register = qc.qregs[0] + qc_out = QuantumCircuit(register) + for instruction in qc: + op_qubits = [ + register[permutation[register.index(q)]] for q in instruction.qubits + ] + qc_out.append(instruction.operation, op_qubits) + return qc_out + + +def tket_to_qiskit(circuit: pytket.Circuit) -> QuantumCircuit: + """ + Convert a tket circuit to qiskit circuit. + :param circuit: + :return: + """ + return tk_to_qiskit(circuit) + + +def create_random_phase_gadget(num_qubits, min_legs, max_legs, allowed_angels): + """ + Generate a random phase gadget. + :param num_qubits: + :param min_legs: + :param max_legs: + :param allowed_angels: + :return: + """ + angle = np.random.choice(allowed_angels) + nr_legs = np.random.randint(min_legs, max_legs) + legs = np.random.choice([i for i in range(num_qubits)], size=nr_legs, replace=False) + phase_gadget = [I for _ in range(num_qubits)] + for leg in legs: + phase_gadget[leg] = np.random.choice([X, Y, Z]) + return PPhase(angle) @ phase_gadget + + +def generate_random_pauli_polynomial( + num_qubits: int, num_gadgets: int, min_legs=None, max_legs=None, allowed_angels=None +): + """ + Generate a random pauli polynomial. + :param num_qubits: + :param num_gadgets: + :param min_legs: + :param max_legs: + :param allowed_angels: + :return: + """ + if min_legs is None: + min_legs = 1 + if max_legs is None: + max_legs = num_qubits + if allowed_angels is None: + allowed_angels = [2 * np.pi, np.pi, 0.5 * np.pi, 0.25 * np.pi, 0.125 * np.pi] + + pp = PauliPolynomial(num_qubits) + for _ in range(num_gadgets): + pp >>= create_random_phase_gadget( + num_qubits, min_legs, max_legs, allowed_angels + ) + + return pp + + +def pauli_poly_to_tket(pp: PauliPolynomial): + """ + Convert a PauliPolynomial to a tket boxes. + :param pp: + :return: + """ + circuit = pytket.Circuit(pp.num_qubits) + for gadget in pp.pauli_gadgets: + circuit.add_pauliexpbox( + PauliExpBox( + [PAULI_TO_TKET[p] for p in gadget.paulis], + gadget.angle / np.pi, + ), + list(range(pp.num_qubits)), + ) + Transform.DecomposeBoxes().apply(circuit) + return tket_to_qiskit(circuit) + + +def verify_equality(qc_in: QuantumCircuit, qc_out: QuantumCircuit) -> bool: + """ + Verify the equality up to a global phase + :param qc_in: + :param qc_out: + :return: + """ + try: + from qiskit.quantum_info import Operator + except: + raise Exception("Please install qiskit to compare to quantum circuits") + return Operator.from_circuit(qc_in).equiv(Operator.from_circuit(qc_out)) + + +def check_matching_architecture(qc: QuantumCircuit, G: nx.Graph): + """ + Check if a circuit matches the architecture graph. + + :param qc: + :param G: + :return: + """ + for gate in qc: + if gate.operation.num_qubits == 2: + ctrl, target = gate.qubits + ctrl, target = ( + ctrl._index, + target._index, + ) # TODO refactor this to a non deprecated way + if not G.has_edge(ctrl, target): + return False + return True + + +def generate_all_combination_pauli_polynomial(n_qubits=2): + """ + Generate a PauliPolynomial consisting of all possible pauli strings. + + :param n_qubits: + :return: + """ + allowed_angels = [2 * np.pi, np.pi, np.pi / 2, np.pi / 4, np.pi / 8] + pp = PauliPolynomial(n_qubits) + for comb in itertools.product([X, Y, Z, I], repeat=n_qubits): + pp >>= PPhase(np.random.choice(allowed_angels)) @ list(comb) + return pp + + +def get_two_qubit_count(circ: QuantumCircuit): + """ + Get the number of two qubit gates in circuit. + :param circ: + :return: + """ + ops = circ.count_ops() + two_qubit_count = 0 + two_qubit_ops = ["cx", "cy", "cz"] + for op_key in two_qubit_ops: + if op_key in ops.keys(): + two_qubit_count += ops[op_key] + + return two_qubit_count + + +def generate_random_depth_1_clifford(gate_class, num_qubits): + """ + Generates a random depth 1 clifford. given it's gate class and the number of qubits it might act on. + + :param gate_class: + :param num_qubits: + :return: + """ + base_names = [cls.__name__ for cls in gate_class.__bases__] + size = 1 if "SingleQubitClifford" in base_names else 2 + qubits = tuple(np.random.choice(list(range(num_qubits)), size=size, replace=False)) + return gate_class(*qubits) diff --git a/tests/test_circuits.py b/tests/test_circuits.py index 10247e6e..e6f0462e 100644 --- a/tests/test_circuits.py +++ b/tests/test_circuits.py @@ -1,6 +1,6 @@ import os import unittest - +import random from parameterized import parameterized from pauliopt.circuits import Circuit @@ -27,7 +27,7 @@ CRz, ) from pauliopt.utils import pi -from tests.utils import verify_equality, random_circuit +from tests.utils import verify_equality, random_circuit, apply_permutation GATES_TO_TEST = [ H(0), @@ -73,16 +73,8 @@ def test_circuit_construction(self, nr_qubits): verify_equality(qc, qc_), "The converted circuit does not equal to original" ) - @parameterized.expand( - [ - ( - gate.name, - gate, - ) - for gate in GATES_TO_TEST - ] - ) - def test_circuit_representation_cli(self, name, gate): + @parameterized.expand(GATES_TO_TEST) + def test_circuit_representation_cli(self, gate): circ = Circuit(3).add_gate(gate) with open(f"{os.getcwd()}/tests/data/circ_reps/{gate.name}_cli.txt", "r") as f: @@ -98,3 +90,21 @@ def test_circuit_representation_cli(self, name, gate): circ._to_svg(svg_code_only=True), f"The SVG representation of {gate.name} " f"is incorrect or changed!", ) + + @parameterized.expand([(3,), (4,), (5,)]) + def test_circuit_inversion(self, nr_qubits): + qc = random_circuit(nr_qubits=nr_qubits, nr_gates=1000) + + circ = Circuit.from_qiskit(qc) + + self.assertTrue(verify_equality(qc.inverse(), circ.inverse().to_qiskit())) + + @parameterized.expand([(3,), (4,), (5,)]) + def test_apply_permutation(self, nr_qubits): + permutation = random.sample(list(range(nr_qubits)), nr_qubits) + qc = random_circuit(nr_qubits=nr_qubits, nr_gates=10) + + circ = Circuit.from_qiskit(qc) + circ.apply_permutation(permutation) + qc = apply_permutation(qc, permutation) + self.assertTrue(verify_equality(qc, circ.to_qiskit())) diff --git a/tests/test_pauli_annealing.py b/tests/test_pauli_annealing.py deleted file mode 100644 index 3ae9461f..00000000 --- a/tests/test_pauli_annealing.py +++ /dev/null @@ -1,108 +0,0 @@ -import itertools -import unittest - -import networkx as nx -import numpy as np -import pytket -from pytket._tket.circuit import PauliExpBox -from pytket._tket.pauli import Pauli -from pytket._tket.transform import Transform -from pytket.extensions.qiskit.qiskit_convert import tk_to_qiskit -from qiskit import QuantumCircuit - -from pauliopt.pauli.anneal import anneal -from pauliopt.pauli.pauli_gadget import PPhase -from pauliopt.pauli.pauli_polynomial import PauliPolynomial -from pauliopt.pauli.utils import X, Y, Z, I -from pauliopt.topologies import Topology -from pauliopt.utils import pi - -PAULI_TO_TKET = {X: Pauli.X, Y: Pauli.Y, Z: Pauli.Z, I: Pauli.I} - - -def tket_to_qiskit(circuit: pytket.Circuit) -> QuantumCircuit: - return tk_to_qiskit(circuit) - - -def pauli_poly_to_tket(pp: PauliPolynomial): - circuit = pytket.Circuit(pp.num_qubits) - for gadget in pp.pauli_gadgets: - circuit.add_pauliexpbox( - PauliExpBox( - [PAULI_TO_TKET[p] for p in gadget.paulis], - gadget.angle.to_qiskit / np.pi, - ), - list(range(pp.num_qubits)), - ) - Transform.DecomposeBoxes().apply(circuit) - return tket_to_qiskit(circuit) - - -def verify_equality(qc_in, qc_out): - """ - Verify the equality up to a global phase - :param qc_in: - :param qc_out: - :return: - """ - try: - from qiskit.quantum_info import Statevector - except: - raise Exception("Please install qiskit to compare to quantum circuits") - return Statevector.from_instruction(qc_in).equiv( - Statevector.from_instruction(qc_out) - ) - - -def generate_all_combination_pauli_polynomial(n_qubits=2): - allowed_angels = [2 * pi, pi, pi / 2, pi / 4, pi / 8] - pp = PauliPolynomial(n_qubits) - for comb in itertools.product([X, Y, Z, I], repeat=n_qubits): - pp >>= PPhase(np.random.choice(allowed_angels)) @ list(comb) - return pp - - -def check_matching_architecture(qc: QuantumCircuit, G: nx.Graph): - for gate in qc: - if gate.operation.num_qubits == 2: - ctrl, target = gate.qubits - ctrl, target = ( - ctrl._index, - target._index, - ) # TODO refactor this to a non deprecated way - if not G.has_edge(ctrl, target): - return False - return True - - -def get_two_qubit_count(circ: QuantumCircuit): - ops = circ.count_ops() - two_qubit_count = 0 - two_qubit_ops = ["cx", "cy", "cz"] - for op_key in two_qubit_ops: - if op_key in ops.keys(): - two_qubit_count += ops[op_key] - - return two_qubit_count - - -class TestPauliAnnealing(unittest.TestCase): - def test_simulated_annealing_pauli(self): - """ - Checks in this Unit test: - 1) If one constructs the Pauli Polynomial with our libary the circuits should match the ones of tket - 2) When synthesizing onto a different architecture the circuits should match the ones of tket - 3) Check that our to_qiskit method exports the Pauli Polynomial according to an architecture - """ - for num_qubits in [2, 3]: - for topo_creation in [Topology.line, Topology.complete]: - pp = generate_all_combination_pauli_polynomial(n_qubits=num_qubits) - - topology = topo_creation(pp.num_qubits) - tket_pp = pauli_poly_to_tket(pp) - our_synth = anneal(pp, topology) - - self.assertTrue( - verify_equality(tket_pp, our_synth), - "The annealing version returned a wrong circuit", - ) diff --git a/tests/test_pauli_propagation.py b/tests/test_pauli_propagation.py deleted file mode 100644 index d57bcac2..00000000 --- a/tests/test_pauli_propagation.py +++ /dev/null @@ -1,156 +0,0 @@ -import itertools -import unittest - -import networkx as nx -import numpy as np -import pytket -from pytket._tket.circuit import PauliExpBox -from pytket._tket.transform import Transform -from pytket.extensions.qiskit.qiskit_convert import tk_to_qiskit, qiskit_to_tk -from pytket._tket.pauli import Pauli -from qiskit import QuantumCircuit - -from pauliopt.pauli.clifford_gates import ( - CX, - CY, - CZ, - H, - S, - V, - generate_random_clifford, - CliffordType, - CliffordGate, - ControlGate, - SingleQubitGate, - clifford_to_qiskit, -) -from pauliopt.pauli.pauli_gadget import PPhase -from pauliopt.pauli.pauli_polynomial import PauliPolynomial -from pauliopt.pauli.utils import X, Y, Z, I - -from pauliopt.topologies import Topology -from pauliopt.utils import pi - -PAULI_TO_TKET = {X: Pauli.X, Y: Pauli.Y, Z: Pauli.Z, I: Pauli.I} - - -def tket_to_qiskit(circuit: pytket.Circuit) -> QuantumCircuit: - return tk_to_qiskit(circuit) - - -def pauli_poly_to_tket(pp: PauliPolynomial): - circuit = pytket.Circuit(pp.num_qubits) - for gadget in pp.pauli_gadgets: - circuit.add_pauliexpbox( - PauliExpBox( - [PAULI_TO_TKET[p] for p in gadget.paulis], - gadget.angle.to_qiskit / np.pi, - ), - list(range(pp.num_qubits)), - ) - Transform.DecomposeBoxes().apply(circuit) - return tket_to_qiskit(circuit) - - -def verify_equality(qc_in, qc_out): - """ - Verify the equality up to a global phase - :param qc_in: - :param qc_out: - :return: - """ - try: - from qiskit.quantum_info import Statevector - except: - raise Exception("Please install qiskit to compare to quantum circuits") - return Statevector.from_instruction(qc_in).equiv( - Statevector.from_instruction(qc_out) - ) - - -def generate_all_combination_pauli_polynomial(n_qubits=2): - allowed_angels = [2 * pi, pi, pi / 2, pi / 4, pi / 8] - pp = PauliPolynomial(n_qubits) - for comb in itertools.product([X, Y, Z, I], repeat=n_qubits): - pp >>= PPhase(np.random.choice(allowed_angels)) @ list(comb) - return pp - - -def check_matching_architecture(qc: QuantumCircuit, G: nx.Graph): - for gate in qc: - if gate.operation.num_qubits == 2: - ctrl, target = gate.qubits - ctrl, target = ( - ctrl._index, - target._index, - ) # TODO refactor this to a non deprecated way - if not G.has_edge(ctrl, target): - return False - return True - - -def get_two_qubit_count(circ: QuantumCircuit): - ops = circ.count_ops() - two_qubit_count = 0 - two_qubit_ops = ["cx", "cy", "cz"] - for op_key in two_qubit_ops: - if op_key in ops.keys(): - two_qubit_count += ops[op_key] - - return two_qubit_count - - -class TestPauliConversion(unittest.TestCase): - def test_circuit_construction(self): - """ - Checks in this Unit test: - 1) If one constructs the Pauli Polynomial with our libary the circuits should match the ones of tket - 2) When synthesizing onto a different architecture the circuits should match the ones of tket - 3) Check that our to_qiskit method exports the Pauli Polynomial according to an architecture - """ - for num_qubits in [2, 3, 4]: - for topo_creation in [Topology.line, Topology.complete]: - pp = generate_all_combination_pauli_polynomial(n_qubits=num_qubits) - - topology = topo_creation(pp.num_qubits) - tket_pp = pauli_poly_to_tket(pp) - our_synth = pp.to_qiskit(topology) - self.assertTrue( - verify_equality(tket_pp, our_synth), - "The resulting Quantum Circuits were not equivalent", - ) - self.assertTrue( - check_matching_architecture(our_synth, topology.to_nx), - "The Pauli Polynomial did not match the architecture", - ) - self.assertEqual( - get_two_qubit_count(our_synth), - pp.two_qubit_count(topology), - "Two qubit count needs to be equivalent to to two qubit count of the circuit", - ) - - def test_gate_propagation(self): - """ - Checks if the clifford Propagation rules are sound for 2, 3, 4 qubits - """ - for num_qubits in [2, 3, 4]: - pp = generate_all_combination_pauli_polynomial(n_qubits=num_qubits) - inital_qc = pp.to_qiskit() - for gate_class in [ - CliffordType.CX, - CliffordType.CY, - CliffordType.CZ, - CliffordType.H, - CliffordType.S, - CliffordType.V, - ]: - gate = generate_random_clifford(gate_class, num_qubits) - pp_ = pp.copy().propagate(gate) - qc = QuantumCircuit(num_qubits) - qc.compose(clifford_to_qiskit(gate).inverse(), inplace=True) - qc.compose(pp_.to_qiskit(), inplace=True) - qc.compose(clifford_to_qiskit(gate), inplace=True) - self.assertTrue( - verify_equality(inital_qc, qc), - "The resulting Quantum Circuits were not equivalent", - ) diff --git a/tests/test_pauli_representation.py b/tests/test_pauli_representation.py deleted file mode 100644 index 7d74779f..00000000 --- a/tests/test_pauli_representation.py +++ /dev/null @@ -1,47 +0,0 @@ -import unittest - -from pauliopt.pauli.pauli_gadget import PPhase -from pauliopt.pauli.pauli_polynomial import PauliPolynomial -from pauliopt.pauli.utils import * -from pauliopt.utils import Angle, pi -import os - -_PAULI_REPR = "(π/2) @ { I, X, Y, Z }\n(π/4) @ { X, X, Y, X }" - -SVG_CODE_PAULI = '\n\n\n\n\n\n\n\n\n\n\n\nπ\n\n\n\n\n\n\n\n\n\nπ/2\n\n\n\n\n\n\n\n\n\nπ/256\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nπ/8\n\n\n\n\n\n\n\n\n\nπ/4\n\n\n\n\n\n\n\n\n\nπ/2\n\n\n\n\n\n' - - -class TestPauliConversion(unittest.TestCase): - def test_circuit_construction(self): - pp = PauliPolynomial(4) - - pp >>= PPhase(Angle(pi / 2)) @ [I, X, Y, Z] - - self.assertEqual(pp.num_qubits, 4) - self.assertEqual(len(pp), 1) - - pp >>= PPhase(Angle(pi / 4)) @ [X, X, Y, X] - - self.assertEqual(pp.__repr__(), _PAULI_REPR) - self.assertEqual(len(pp), 2) - - pp_ = PauliPolynomial(num_qubits=4) - pp_ >> pp - - self.assertEqual( - pp.__repr__(), - pp_.__repr__(), - "Right shift resulted in different pauli Polynomials.", - ) - - def test_circuit_visualisation_svg(self): - pp = PauliPolynomial(5) - - pp >>= PPhase(Angle(pi)) @ [I, I, X, Z, Y] - pp >>= PPhase(Angle(pi / 2)) @ [X, X, I, I, Y] - pp >>= PPhase(Angle(pi / 256)) @ [X, I, I, Z, Y] - pp >>= PPhase(Angle(pi / 8)) @ [X, X, X, Z, Y] - pp >>= PPhase(Angle(pi / 4)) @ [X, Z, I, I, Y] - pp >>= PPhase(Angle(pi / 2)) @ [X, I, I, Y, Y] - - self.assertEqual(pp.to_svg(svg_code_only=True), SVG_CODE_PAULI) diff --git a/tests/utils.py b/tests/utils.py index 8d978440..e1eef4ab 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -8,7 +8,6 @@ TGate, TdgGate, SdgGate, - SXdgGate, ZGate, YGate, XGate, @@ -26,6 +25,8 @@ ) from qiskit.quantum_info import Operator +from pauliopt.circuits import Circuit + guadalupe_connectivity = [ [0, 1], [1, 0], @@ -143,37 +144,41 @@ def verify_equality(qc_in, qc_out): return Operator.from_circuit(qc_in).equiv(Operator.from_circuit(qc_out)) -def random_clifford_circuit(nr_gates=20, nr_qubits=4, gate_choice=None): - qc = QuantumCircuit(nr_qubits) +def random_clifford_circuit(nr_gates=20, nr_qubits=4, gate_choice=None) -> Circuit: + qc = Circuit(nr_qubits) if gate_choice is None: - gate_choice = ["CY", "CZ", "CX", "H", "S", "V"] + gate_choice = ["CX", "H", "S", "V", "CY", "CZ", "Sdg", "Vdg", "X", "Y", "Z"] for _ in range(nr_gates): gate_t = np.random.choice(gate_choice) + qubit = np.random.choice([i for i in range(nr_qubits)]) if gate_t == "CX": - control = np.random.choice([i for i in range(nr_qubits)]) - target = np.random.choice([i for i in range(nr_qubits) if i != control]) - qc.cx(control, target) + target = np.random.choice([i for i in range(nr_qubits) if i != qubit]) + qc.cx(qubit, target) elif gate_t == "CY": - control = np.random.choice([i for i in range(nr_qubits)]) - target = np.random.choice([i for i in range(nr_qubits) if i != control]) - qc.cy(control, target) + target = np.random.choice([i for i in range(nr_qubits) if i != qubit]) + qc.cy(qubit, target) elif gate_t == "CZ": - control = np.random.choice([i for i in range(nr_qubits)]) - target = np.random.choice([i for i in range(nr_qubits) if i != control]) - qc.cz(control, target) + target = np.random.choice([i for i in range(nr_qubits) if i != qubit]) + qc.cz(qubit, target) elif gate_t == "H": - qubit = np.random.choice([i for i in range(nr_qubits)]) qc.h(qubit) elif gate_t == "S": - qubit = np.random.choice([i for i in range(nr_qubits)]) qc.s(qubit) elif gate_t == "V": - qubit = np.random.choice([i for i in range(nr_qubits)]) - qc.sx(qubit) - elif gate_t == "CX": - control = np.random.choice([i for i in range(nr_qubits)]) - target = np.random.choice([i for i in range(nr_qubits) if i != control]) - qc.cx(control, target) + qc.v(qubit) + elif gate_t == "Vdg": + qc.vdg(qubit) + elif gate_t == "Sdg": + qc.sdg(qubit) + elif gate_t == "X": + qc.x(qubit) + elif gate_t == "Y": + qc.y(qubit) + elif gate_t == "Z": + qc.z(qubit) + else: + raise Exception(f"Unknown Gate: {gate_t}") + return qc