From c74c8fa030772eb97281b2796386e4d0ae6e1a90 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Thu, 2 May 2019 06:15:48 +0200 Subject: [PATCH] Add print circuit method This commit introduces a print method to the Circuit class. The idea is to give a visual representation of the quantum circuit. The motivation for this is as a learning aid to help understand the circuit created. The implementation can probably be made more efficient but I wanted to get some feedback on this feature and if it is worth pursuing/spending time on (or perhaps it could be useful as is and developed further as required). --- CHANGELOG.md | 4 + packages/qiskit-sim/lib/Circuit.js | 90 +++++++++++++++++++ .../qiskit-sim/test/functional/Circuit.js | 72 +++++++++++++++ 3 files changed, 166 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3995358..93cf6c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### 🎉 Added + +- `@qiskit/qiskit-sim`: Add print circuit method + ## [0.8.0] - 2019-04-25 ### 🎉 Added diff --git a/packages/qiskit-sim/lib/Circuit.js b/packages/qiskit-sim/lib/Circuit.js index 6e76af3..879904e 100644 --- a/packages/qiskit-sim/lib/Circuit.js +++ b/packages/qiskit-sim/lib/Circuit.js @@ -180,11 +180,13 @@ class Circuit { id, name: (gate instanceof Gate) ? gate.name : gate.toLowerCase(), connector, + multiQubit: numConnectors > 1, }; } return this; } + createTransform(U, qubits) { const dimension = this.numAmplitudes(); this.initTransform(dimension); @@ -362,6 +364,94 @@ class Circuit { return s; } + print(writable = process.stdout) { + const columnLen = 10; + const spaceLen = 4; + const gateLen = 4; + + const connectionsMap = new Map(); + for (let column = 0; column < this.gates[0].length; column += 1) { + for (let wire = 0; wire < this.nQubits; wire += 1) { + const gate = this.gates[wire][column]; + if (gate && gate.multiQubit) { + const m = connectionsMap.has(column) ? connectionsMap.get(column) : + new Map(); + let entry; + if (m.has(gate.id)) { + entry = m.get(gate.id); + entry.to = wire; + } else { + entry = {from: wire, + fromVisited: false, + to: null, + toVisited: false}; + } + m.set(gate.id, entry); + connectionsMap.set(column, m); + } + } + } + + let columnHeader = ''.padStart(columnLen); + for (let i = 0; i < this.numCols(); i += 1) { + columnHeader += `column ${i}`.padEnd(columnLen, ' '); + columnHeader += ''.padEnd(spaceLen, ' '); + } + writable.write('\n'); + writable.write(columnHeader); + writable.write('\n'); + + for (let wire = 0; wire < this.nQubits; wire += 1) { + writable.write(`wire ${wire} `.padEnd(columnLen, '-')); + let wireOutput = ''; + let connOutput = ''.padStart(columnLen, ' '); + for (let column = 0; column < this.gates[wire].length; column += 1) { + const gate = this.getGateAt(column, wire); + const connections = connectionsMap.get(column); + if (connections) { + if (gate && connections.has(gate.id)) { + const c = connections.get(gate.id); + if (c.from === wire) { + c.fromVisited = true; + } + if (c.to === wire) { + c.toVisited = true; + } + + if (c.fromVisited === true && c.toVisited === true) { + connections.delete(gate.id); + if (connections.size === 0) { + connectionsMap.delete(column); + } + } else { + connOutput += ` |`; + } + } else { + connOutput += ` |`; + } + } + + if (gate) { + if (gate.multiQubit && gate.connector !== 0) { + wireOutput += `[*]`.padEnd(gateLen, '-'); + } else { + wireOutput += `[${gate.name}]`.padEnd(gateLen, '-'); + connOutput += ''.padEnd(gateLen, ' '); + } + } else { + wireOutput += ''.padEnd(gateLen, '-'); + connOutput += ''.padEnd(gateLen, ' '); + } + wireOutput += ''.padEnd(columnLen, '-'); + connOutput += ''.padEnd(columnLen, ' '); + } + writable.write(wireOutput); + writable.write('\n'); + writable.write(connOutput); + writable.write('\n'); + } + } + static createCircuit(qubits) { if (typeof qubits !== 'number') throw new TypeError('The "qubits" argument must be of type number. ' + diff --git a/packages/qiskit-sim/test/functional/Circuit.js b/packages/qiskit-sim/test/functional/Circuit.js index 83c78ff..cc542e5 100644 --- a/packages/qiskit-sim/test/functional/Circuit.js +++ b/packages/qiskit-sim/test/functional/Circuit.js @@ -10,6 +10,7 @@ 'use strict'; const assert = require('assert'); +const { Writable } = require('stream'); const { Circuit, Gate } = require('../..'); @@ -150,3 +151,74 @@ describe('sim:Circuit:createCircuit', () => { }); }); }); + +describe('sim:Circuit:print', () => { + let result = ''; + const writable = new Writable({ + write(chunk, encoding, callback) { + result += chunk.toString(); + callback(); + } + }); + + function stripWhitespace(str) { + return str.replace(/\s+/g, ''); + } + + afterEach( () => { result = ''; } ) + + it('should print circuit with single hadamard gate', () => { + const expected = ` + column 0 + wire 0 ---[h]-----------`; + + Circuit.createCircuit(1).addGate(Gate.h, 0, 0).print(writable); + assert.strictEqual(stripWhitespace(result), stripWhitespace(expected)); + }); + + it('should print circuit with multiple gates', () => { + const expected = ` + column 0 + wire 0 ---[h]----------- + + wire 1 ---[h]-----------`; + + Circuit.createCircuit(2).addGate(Gate.h, 0, 0) + .addGate(Gate.h, 0, 1) + .print(writable); + assert.strictEqual(stripWhitespace(result), stripWhitespace(expected)); + }); + + it('should print circuit with connections', () => { + const expected = ` + column 0 column 1 + wire 0 ---[x]-----------[cx]---------- + | + wire 1 -----------------[*]-----------`; + // Note that the star in this case represents the target qubit + // and the control qubit will be qubit 0. + + Circuit.createCircuit(2).addGate(Gate.x, 0, 0) + .addGate(Gate.cx, 1, [0, 1]) + .print(writable); + assert.strictEqual(stripWhitespace(result), stripWhitespace(expected)); + }); + + it('should print circuit with connections over mutiple wires', () => { + const expected = ` + column 0 column 1 + wire 0 ---[x]-----------[cx]---------- + | + wire 1 ------------------------------- + | + wire 2 -----------------[*]----------- + + wire 3 -------------------------------`; + + Circuit.createCircuit(4).addGate(Gate.x, 0, 0) + .addGate(Gate.cx, 1, [0, 2]) + .print(writable); + assert.strictEqual(stripWhitespace(result), stripWhitespace(expected)); + }); + +});