Skip to content

Commit

Permalink
API and 'Implementation' updates
Browse files Browse the repository at this point in the history
  • Loading branch information
WrathfulSpatula committed Jan 21, 2020
1 parent fd6474f commit 38b70d6
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 38 deletions.
41 changes: 34 additions & 7 deletions docs/api/qinterface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@ These enums can be passed to an allocator to create a ``QInterface`` of that spe
Constructors
------------

.. doxygenfunction:: Qrack::QInterface::QInterface(bitLenInt)

.. doxygenfunction:: Qrack::QInterface::QInterface(bitLenInt, bitCapInt)

.. doxygenfunction:: Qrack::QInterface::QInterface(const QInterface&)
.. doxygenfunction:: Qrack::QInterface::QInterface(bitLenInt, qrack_rand_gen_ptr, bool, bool, bool, real1)

Members
-------
Expand Down Expand Up @@ -73,10 +69,28 @@ State Manipulation Methods

.. doxygenfunction:: Qrack::QInterface::Swap(bitLenInt, bitLenInt, bitLenInt)

.. doxygenfunction:: Qrack::QInterface::ISwap(bitLenInt, bitLenInt)

.. doxygenfunction:: Qrack::QInterface::ISwap(bitLenInt, bitLenInt, bitLenInt)

.. doxygenfunction:: Qrack::QInterface::SqrtSwap(bitLenInt, bitLenInt)

.. doxygenfunction:: Qrack::QInterface::SqrtSwap(bitLenInt, bitLenInt, bitLenInt)

.. doxygenfunction:: Qrack::QInterface::CSwap(const bitLenInt*, const bitLenInt&, const bitLenInt&, const bitLenInt&)

.. doxygenfunction:: Qrack::QInterface::AntiCSwap(const bitLenInt*, const bitLenInt&, const bitLenInt&, const bitLenInt&)

.. doxygenfunction:: Qrack::QInterface::CSqrtSwap(const bitLenInt*, const bitLenInt&, const bitLenInt&, const bitLenInt&)

.. doxygenfunction:: Qrack::QInterface::AntiCSqrtSwap(const bitLenInt*, const bitLenInt&, const bitLenInt&, const bitLenInt&)

.. doxygenfunction:: Qrack::QInterface::Reverse(bitLenInt, bitLenInt)

.. doxygenfunction:: Qrack::QInterface::TrySeparate(bitLenInt, bitLenInt)

.. doxygenfunction:: Qrack::QInterface::MultiShotMeasureMask(const bitCapInt*, const bitLenInt, const unsigned int);

Quantum Gates
-------------

Expand Down Expand Up @@ -106,6 +120,13 @@ Single Gates
.. doxygenfunction:: Qrack::QInterface::IS(bitLenInt)
.. doxygenfunction:: Qrack::QInterface::T(bitLenInt)
.. doxygenfunction:: Qrack::QInterface::IT(bitLenInt)
.. doxygenfunction:: Qrack::QInterface::SqrtX(bitLenInt)
.. doxygenfunction:: Qrack::QInterface::ISqrtX(bitLenInt)
.. doxygenfunction:: Qrack::QInterface::SqrtY(bitLenInt)
.. doxygenfunction:: Qrack::QInterface::ISqrtY(bitLenInt)
.. doxygenfunction:: Qrack::QInterface::SqrtH(bitLenInt)
.. doxygenfunction:: Qrack::QInterface::SqrtXConjT(bitLenInt)
.. doxygenfunction:: Qrack::QInterface::ISqrtXConjT(bitLenInt)

.. doxygenfunction:: Qrack::QInterface::CNOT(bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::AntiCNOT(bitLenInt, bitLenInt)
Expand Down Expand Up @@ -139,9 +160,8 @@ Single Gates
.. doxygenfunction:: Qrack::QInterface::ExpZ(real1, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::ExpZDyad(int, int, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::Exp(bitLenInt *, bitLenInt, bitLenInt, complex *, bool)
.. doxygenfunction:: Qrack::QInterface::Log(bitLenInt *, bitLenInt, bitLenInt, complex *, bool)

.. doxygenfunction:: Qrack::QInterface::UniformlyControlledSingleBit(const bitLenInt*, const bitLenInt&, bitLenInt, const complex*)
.. doxygenfunction:: Qrack::QInterface::UniformlyControlledSingleBit(const bitLenInt *, const bitLenInt&, bitLenInt, const complex *)
.. doxygenfunction:: Qrack::QInterface::UniformlyControlledRY(const bitLenInt*, const bitLenInt&, bitLenInt, const real1*)
.. doxygenfunction:: Qrack::QInterface::UniformlyControlledRZ(const bitLenInt*, const bitLenInt&, bitLenInt, const real1*)

Expand All @@ -163,6 +183,13 @@ Register-wide Gates
.. doxygenfunction:: Qrack::QInterface::IS(bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::T(bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::IT(bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::SqrtX(bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::ISqrtX(bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::SqrtY(bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::ISqrtY(bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::SqrtH(bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::SqrtXConjT(bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::ISqrtXConjT(bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::CNOT(bitLenInt, bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::AntiCNOT(bitLenInt, bitLenInt, bitLenInt)
.. doxygenfunction:: Qrack::QInterface::CCNOT(bitLenInt, bitLenInt, bitLenInt, bitLenInt)
Expand Down
12 changes: 0 additions & 12 deletions docs/api/qunitmulti.rst

This file was deleted.

25 changes: 11 additions & 14 deletions docs/implementation.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Implementation
==============

QInterface
QEngine
--------------------------------

A `Qrack::QInterface` stores a set of permutation basis complex number coefficients and operates on them with bit gates and register-like methods.
A `Qrack::QEngine` stores a set of permutation basis complex number coefficients and operates on them with bit gates and register-like methods.

The state vector indicates the probability and phase of all possible pure bit permutations, numbered from :math:`0` to :math:`2^N-1`, by simple binary counting. All operations except measurement should be "unitary," except measurement. They should be representable as a unitary matrix acting on the state vector. Measurement, and methods that involve measurement, should be the only operations that break unitarity. As a rule-of-thumb, this means an operation that doesn't rely on measurement should be "reversible." That is, if a unitary operation is applied to the state, their must be a unitary operation to map back from the output to the exact input. In practice, this means that most gate and register operations entail simply direct exchange of state vector coefficients in a one-to-one manner. (Sometimes, operations involve both a one-to-one exchange and a measurement, like the `QInterface::SetBit` method, or the logical comparison methods.)

Expand All @@ -14,9 +14,14 @@ To determine how state vector coefficients should be exchanged in register-wise

The act of measurement draws a random double against the probability of a bit or string of bits being in the :math:`1` state. To determine the probability of a bit being in the :math:`1` state, sum the probabilities of all permutation states where the bit is equal to :math:`1`. The probablity of a state is equal to the complex norm of its coefficient in the state vector. When the bit is determined to be :math:`1` by drawing a random number against the bit probability, all permutation coefficients for which the bit would be equal to :math:`0` are set to zero. The original probabilities of all states in which the bit is :math:`1` are added together, and every coefficient in the state vector is then divided by this total to "normalize" the probablity back to :math:`1` (or :math:`100\%`).

In the ideal, acting on the state vector with only unitary matrices would preserve the overall norm of the permutation state vector, such that it would always exactly equal :math:`1`, such that on. In practice, floating point error could "creep up" over many operations. To correct we this, we normalize at least immediately before (and immediately after) measurement operations. Many operations imply only measurements by either :math:`1` or :math:`0` and will therefore not introduce floating point error, but in cases where we multiply by say :math:`1/\sqrt{2}`, we can normalize proactively. In fact, to save computational overhead, since most operations entail iterating over the entire permutation state vector once, we can calculate the norm on the fly on one operation, finish with the overall normalization constant in hand, and apply the normalization constant on the next operation, thereby avoiding having to loop twice in every operation.
In the ideal, acting on the state vector with only unitary matrices would preserve the overall norm of the permutation state vector, such that it would always exactly equal :math:`1`, such that on. In practice, floating point error could "creep up" over many operations. To correct we this, Qrack can optionally normalize its state vector, depending on constructor arguments. Specifically, normalization is enabled in tandem with floating point error mitigation that floors very small probability amplitudes to exactly 0, below the estimated level of typical systematic float error for a gate like "H." In fact, to save computational overhead, since most operations entail iterating over the entire permutation state vector once, we can calculate the norm on the fly on one operation, finish with the overall normalization constant in hand, and apply the normalization constant on the next operation, thereby avoiding having to loop twice in every operation.

`Qrack` has been implemented with ``double`` precision complex numbers. Use of single precision ``float`` could get us basically one additional qubit, twice as many bit permutations, on the same system. However, double precision complex numbers naturally align to the width of SIMD intrinsics. It is up to the developer implementing a quantum emulator, whether precision and alignment with SIMD or else one additional qubit on a system is more important.
`Qrack` has been implemented with ``float`` precision complex numbers by default. Optional use of ``double`` precision costs us basically one additional qubit, entailing twice as many potential bit permutations, on the same system. However, double precision complex numbers naturally align to the width of SIMD intrinsics. It is up to the developer, whether precision and alignment with SIMD or else one additional qubit on a system is more important.

QUnit
--------------------------------

`Qrack::QUnit` is a "fundamentally" optimized layer on top of `Qrack::QEngine` types. `QUnit` optimizations include a broadly developed, practical realization of "Schmidt decomposition," (see [Pednault2017]_,) per-qubit basis transformation with gate commutation, 2-qubit controlled gate buffering and "fusion," optimizing out global phase effects that have no effect on physical "observables," (i.e. the expectation values of Hermitian operators,) a classically efficient SWAP still equivalent to the quantum operation, and many "syngeristic" and incidental points of optimization on top of these general approaches. Publication of an academic report on Qrack and its performance is planned soon, but the `Qrack::QUnit` source code is freely publicly available to inspect.

VM6502Q Opcodes
---------------
Expand All @@ -28,15 +33,7 @@ The quantum mode flag takes the place of the ``unused`` flag bit in the original

When an operation happens that would necessarily collapse all superposition in a register or a flag, the emulator keeps track of this, so it can know when its emulation is genuinely quantum as opposed to when it is simply an emulation of a quantum computer emulating a 6502. When quantum emulation is redundant overhead on classical emulation, the emulator is aware, and it performs only the necessary classical emulation. When an operation happens that could lead to superposition, the emulator switches back over to full quantum emulation, until another operation which is guaranteed to collapse a register's state occurs.

CC65
----

An assembler for the vm6502q project has been implemented by extending the instruction set of the MOS-6502. To implement the assembler, one can duplicate an assembler implementation for the 6502 and add the new instruction symbols and binary values to the table of implemented instructions.

.. _c-syntax-enhancements-ref:

C Syntax Enhancements
~~~~~~~~~~~~~~~~~~~~~
.. target-notes::

New higher level syntax extensions are under development using the CC65 C compiler for the 6502. These syntax extensions will leverage the quantum parallel LoaD Accumulator ("LDA") instruction, quantum paralell ADd with Carry ("ADC") instruction, and quantum parallel SuBtract with Carry ("SBC") instruction, as well as the amplitude amplification capabilities of vm6502q, using the modified behavior of status flags in "quantum mode." More is to follow soon.
.. [Pednault2017] `Pednault, Edwin, et al. "Breaking the 49-qubit barrier in the simulation of quantum circuits." arXiv preprint arXiv:1710.05867 (2017). <https://arxiv.org/abs/1710.05867>`_
8 changes: 3 additions & 5 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,16 @@ Introduction

`Qrack <https://github.com/vm6502q/qrack>`_ is a C++ quantum bit and gate simulator, with the ability to support arbitrary numbers of entangled qubits - up to system limitations. Suitable for embedding in other projects, the :cpp:class:`Qrack::QInterface` contains a full and performant collection of standard quantum gates, as well as variations suitable for register operations and arbitrary rotations.

The developers of Qrack maintain a `fork <https://github.com/vm6502q/ProjectQ>`_ of the `ProjectQ <https://github.com/ProjectQ-Framework/ProjectQ>`_ quantum computer compiler which can use Qrack as the simulator, generally. This stack is also compatible with the `SimulaQron <https://github.com/SoftwareQuTech/SimulaQron>`_ quantum network simulator. (Qrack's developers are not directly affiliated with either of those projects, but we thank them for their contribution to the open source quantum computing community!)
The developers of Qrack maintain a `fork <https://github.com/vm6502q/ProjectQ>`_ of the `ProjectQ <https://github.com/ProjectQ-Framework/ProjectQ>`_ quantum computer compiler which can use Qrack as the simulator, generally. This stack is also compatible with the `SimulaQron <https://github.com/SoftwareQuTech/SimulaQron>`_ quantum network simulator. Further, we maintain a `QrackProvider <https://github.com/vm6502q/qiskit-qrack-provider>`_ for `Qiskit <https://qiskit.org/>`_. Both ProjectQ and Qiskit integrations for Qrack support the `PennyLane <https://pennylane.ai/>`_ stack. (For Qiskit, a `fork <https://github.com/vm6502q/pennylane-qiskit>`_ of the Qiskit plugin provides support for a "QrackDevice".) Qrack's developers are not directly affiliated with any of these projects, but we thank them for their contribution to the open source quantum computing community!

As a demonstration of the :cpp:class:`Qrack::QInterface` implementation, a MOS-6502 microprocessor [MOS-6502]_ virtual machine has been modified with a set of new opcodes (:ref:`mos-6502q-opcodes`) supporting quantum operations. The `vm6502q <https://github.com/vm6502q/vm6502q>`_ virtual machine exposes new integrated quantum opcodes such as Hadamard transforms and an X-indexed LDA, with the X register in superposition, across a page of memory. An assembly example of a Grover's search with a simple oracle function is demonstrated in the `examples <https://github.com/vm6502q/examples>`_ repository.

Finally, a `6502 toolchain <https://github.com/vm6502q/cc65>`_ - based on `CC65 <http://cc65.github.io/doc/>`_ - has been modified and enhanced to support the new opcodes for the assembler. We have discussed potential :ref:`c-syntax-enhancements-ref`. This is performed primarily as sandbox/exploratory work to help clarify what quantum computational software engineering might look like as the hardware reaches commoditization.

Copyright
---------

Copyright (c) Daniel Strano 2017-2019 and the Qrack contributors. All rights reserved.
Copyright (c) Daniel Strano 2017-2020 and the Qrack contributors. All rights reserved.

Daniel Strano would like to specifically note that Benn Bollay is almost entirely responsible for the implementation of QUnit and tooling, including unit tests, in addition to large amounts of work on the documentation and many other various contributions in intensive reviews. Also, thank you to Marek Karcz for supplying an awesome base classical 6502 emulator for proof-of-concept.
Daniel Strano would like to specifically note that Benn Bollay is almost entirely responsible for the original implementation of QUnit and tooling, including unit tests, in addition to large amounts of work on the documentation and many other various contributions in intensive reviews. Also, thank you to Marek Karcz for supplying an awesome base classical 6502 emulator for proof-of-concept.

.. toctree::
:maxdepth: 2
Expand Down

0 comments on commit 38b70d6

Please sign in to comment.