GithubHelp home page GithubHelp logo

matt-lourens / hierarqcal Goto Github PK

View Code? Open in Web Editor NEW
42.0 42.0 15.0 51.75 MB

Generate hierarchical quantum circuits for Neural Architecture Search.

Home Page: https://matt-lourens.github.io/hierarqcal/

License: BSD 3-Clause "New" or "Revised" License

Python 100.00%
deep-learning machine-learning neural-architecture-search quantum quantum-computing

hierarqcal's People

Contributors

aishsweety avatar amyrouillard avatar asrouillard avatar gopal-dahale avatar khnikhil avatar matt-lourens avatar metalcyanide avatar stephendiadamo avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar

hierarqcal's Issues

Add functionality to visualise hypergraphs (N-ary edges for digraphs)

Summary

Every primitive (Qcycle, Qmask, Qpermute) is a directed graph, with nodes corresponding to qubits and edges to unitaries applied between them. Currently, only 2 qubit primitives get plotted, for example, Qcycle with different stride values:

sc1 = Qinit(8) + Qcycle(stride=1, mapping=u2) # plot_motif(sc1[1])
sc3 = Qinit(8) + Qcycle(stride=3, mapping=u2) # plot_motif(sc3[1])
sc5 = Qinit(8) + Qcycle(stride=5, mapping=u2) # plot_motif(sc5[1])
sc7 = Qinit(8) + Qcycle(stride=7, mapping=u2) # plot_motif(sc7[1])

image
It is however possible to provide a N-qubit unitary to a primitive, these correspond to hypergraphs (3-qubit unitary means the underlying graph has 3-tuple edges ex. primitive.E = [(1,2,3),(5,4,3),...]). These need to be visualised with bands, and should look as follows:

m1 = Qinit(15) + Qcycle(stride=1, step=3, offset=0, mapping=Qunitary(arity=3)) # plot_motif(m1[1])
m2 = Qinit(15) + Qcycle(stride=1, step=3, offset=2, mapping=Qunitary(arity=3))  # plot_motif(m2[1])
m3 = Qinit(15) + Qcycle(stride=3, step=1, offset=0, mapping=Qunitary(arity=3)) # plot_motif(m3[1])

image

The plot motif function in utils.py already receives the primitive with the correct edges produced for N-qubit unitaries (i.e. you receive a graph with nodes and N-tuple edges). For the example above, m1[1].E=[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12), (13, 14, 15)]. The task is to plot this graph, as shown above. The hypergraphs above were produced with https://github.com/pnnl/HyperNetX but I don't want to add it as a dependency to the package (to keep the package lightweight, we only want to visualise graphs not interact with them). This is the reason why networkx isn't a dependency and the digraphs for 2-qubit unitaries are drawn with matplotlib. Use the 2-tuple case as a reference to implement the N-qubit case, the goal is to produce graphs similar to the ones above. We have the node radius and center position information, so we have to draw a path around the nodes (without touching them). I think this is a fun problem that can be solved with a little bit of linear algebra (see the 2-tuple case for how the arrowhead positions are determined).

Add an example with short tutorial

Adding an example with a tutorial on how to use the library. This could be in the form of a .ipynb notebook (or myst file, i.e. more readable as a .md file but executable as a Jupyter notebook). This would definitely help the user to find out what the library can do.

This could be linked in the readme

Quantum Circuit Tutorial: Modular Addition and Subtraction using HierarQcal

Issue: Create a quantum computing tutorial in a Jupyter notebook to demonstrate modular arithmetic (addition and subtraction) using the Python package HierarQcal.

Overview

The goal is to provide a jupyter notebook tutorial that implements modular addition and subtraction within quantum circuits. The idea is that this will showcase some core hierarQal functionality. I have provided a code snippet modular_arithmetic_mvp.py that implements an mvp (minimum viable product) version, but it needs to be expanded and improved for pedagodgy, through refactoring, explanations and visualizations. The code follows the implementation from the Vedral et al. paper which will be a useful reference in understanding the circuit layout. Here's some example input and outputs which you can verify with the code snippet.

Addition:

hierq = Qinit(nq, tensors=tensors) + addition_mod_n # a+b % N
result_tensor = hierq()
get_results(result_tensor, bit_layout)
del result_tensor # just because it can be big
# input
a - 6
b - 3
N - 5
# output (answer is stored in b)
a: ['0', '1', '1']
b: ['0', '0', '1'] + ['0']
c: ['0', '0', '0']
n: ['1', '0', '1']
t: ['0']

$(6+3) \text{Mod} 5 = 4$ which is encoded in b: ['0', '0', '1'] + ['0'] (most significant bit is on the right, so this translates to 100 = 4)

# input
a - 4
b - 3
N - 4
# output (answer is stored in b)
a: ['0', '0', '1']
b: ['1', '1', '0'] + ['0']
c: ['0', '0', '0']
n: ['0', '0', '1']
t: ['0']

$(4+3) \text{Mod} 4 = 3$ which is encoded in b: ['1', '1', '0'] + ['0'] (most significant bit is on the right, so this translates to 011 = 4).

You can change things like the bit order (for display the most significant bit should be on the left, the reason for the above was that it was quickly implemented straight from the Vedral et al. Paper.). You'll see in the code there are uncommented x and r variables, these are for use in modular exponentiation, which is out of the scope for this issue but if you do find the above easy, you're welcome to extend the tutorial to modular exponentiation (let me know, I can then provide some more code that might be useful).

When debugging the code, it is useful to break things into parts, for example in looking what addition_mod_n does first run

hierq = (
    Qinit(nq, tensors=tensors)
    + addition
)
result_tensor = hierq()
get_results(result_tensor, bit_layout)
del result_tensor
plot_circuit(hierq, plot_width=100)

then

hierq = (
    Qinit(nq, tensors=tensors)
    + addition
    + swap_an
)
result_tensor = hierq()
get_results(result_tensor, bit_layout)
del result_tensor
plot_circuit(hierq, plot_width=100)

and so on.

Resources:

  • modular_arithmetic_example.py: The provided code snippet offers a minimal implementation for modular addition and subtraction circuits. Your task will be to expand on this code, providing explanations, visualizations and improvements for pedagogy.

  • Paper: Vedral et al. (1996), "Quantum Networks for Elementary Arithmetic Operations," provides details on modular arithmetic in quantum networks. It serves as the reference for implementing modular addition and subtraction circuits.

Requirements

  • Jupyter Notebook: Create a Jupyter notebook that demonstrates and explains modular addition and subtraction using HierarQcal.

Build simple circuits with strings

Summary

The idea is to allow common simple 1 and 2 qubit circuits to be built with a string passed to Qunitary. This would allow a for an elegant interaction to build complicated circuits from simple building blocks. For example:

Qinit(2)+Qcycle(mapping=Qunitary(f"CRX(x0)^01,CRZ(x1)^10)"))

simple_cycle
Where currently this is achieved as follows:

def anz1(bits, symbols=None, circuit=None):
    # Assume bits are strings and in the correct QASM format
    q0, q1 = QuantumRegister(1, bits[0]), QuantumRegister(1, bits[1])
    circuit.crx(symbols[0], q0, q1)
    circuit.crz(symbols[1], q1, q0)
    return circuit
u = Qunitary(anz1, 2, 2)
hierq = Qinit(5) + Qcycle(mapping=u)

Qunitary can receive any function, and we want to allow it to receive a string that specifies a simple circuit. Emphasis on simple, the reason for this feature is to enable building small circuits quickly without needing to create a function, we don't need to cater for all possible use cases, just the commonly used gates. The string format I have in mind is:

"{gate_string}(parameters)^{bits},{gate_string}(parameters)^{bits},...,{gate_string}(parameters)^{bits}"

Where gate_string is one of: h,x,y,z,cx,cy,cz,rx,ry,rz,crx,cry,crz,s,tof,fred and always in either upper case or lower case. Then each gates {parameters} are specified in brackets (x1,x2,...,xn) separated with commas and n<10 (to avoid dis ambiguity and keep it simple. Then ^ specifies bits (the qubit indices that the gate acts upon). We should only allow up to 0-9 since most of the time only 2 qubit circuits are going to be created. The arity and number of symbols can then be determined by the distinct number of bits used and the total number of parameters specified, this should happen when Qunitary is initialised.

The conversion needs to happen when the Qhierarchy object is called (depending on the backend it executes get_circuit_qiskit for example). We'll need some mapping for the gate strings and the corresponding gate name for the backend used (we can stick with qiskit for now). Then some function needs to be constructed, I envisage something along the lines of:

def get_circuit_from_string(qunitary):
    def circuit_fn(bits, symbols=None, circuit=None):        
        arity=qunitary.arity
        qubits = [QuantumRegister(1, bits[i]) for i in range(arity)]
        s_idx = 0
        for gate_name, sub_bits, n_subsymbols in get_gateinfo_from_string(qunitary.circuit_string, arity, n_symbols):
            gate = getattr(circuit, gate_name)
            gate(*symbols[s_idx:n_subsymbols], *qubits.get(sub_bits))
        return circuit
    return circuit_fn

But that's just a guess, in particular I don't know how to handle the sub_bits.

For this issue, you can pick any framework (qiskit, pennylane, cirq) and implement the functionality for one of them. Feel free to come up with a better design, the above is just an idea for how to allow simple string circuits to Qunitary.

Quantum Chemistry example notebook for the exponentiation of Pauli operators

I don't have any background in quantum chemistry but I have seen these circuits for the exponentiation of tensor products of Pauli operators in a quantum chemistry context:
From this paper
image
and this:
image

These should be easy to implement with HierarQcal because of their symmetric nature. I'm hoping someone who knows more of their application can create a notebook example that illustrates their typical use case through using the package. Pennylane also has templates for these.

UnitaryHack Bounty - Quantum Machine Learning Tutorial: Music Genre Classification using HierarQcal

Issue: Create a quantum machine learning tutorial in a Jupyter notebook using the Python package HierarQcal for classifying music genres.

Overview

This tutorial will guide users on using HierarQcal to create quantum circuit models for classification tasks. The goal is to provide a quantum machine learning template, where a user can obtain baseline model performance for a classification task. While focusing on the GTZAN dataset's country vs. rock genre pair, the tutorial should emphasize a robust pipeline for both classical and quantum aspects of QML.

Resources:

  • Paper: The methods section in the hierarqcal paper serves as a blueprint for constructing a machine learning pipeline. The Architectural Impact section will also help guide model development and provide something to compare against.

  • qml_example.py: A code snippet is provided as an MVP for this tutorial, and should be expanded into a comprehensive, well-explained template.

  • Data: Use the GTZAN dataset to distinguish between country and rock songs as done in the paper. Use the 30 second window data with PCA(8 components) encoded on 8 qubits with AngleEmbedding. If alternative preprocessing yields better results, feel free to implement it.

Key Notes

  • Ensure the tutorial is adaptable to other classification tasks despite the specific example used.
  • Suggested sections (feel free to modify as needed):
    1. Data Loading
    2. Data Cleaning and Preprocessing
    3. Model Creation (with HierarQcal)
    4. Training Pipeline
    5. Evaluation and Visualization
  • Implement cross-validation for a comprehensive model evaluation.
  • Feel free to re-use images/graphs from the paper to include in the tutorial.

Requirements

  • Code Base: Utilize the provided code, and expand or improve upon it as needed. The code includes essential parts for getting a model that works.
  • Explanation: Provide detailed explanations for each code section to clarify the quantum circuit architecture and machine learning pipeline.
  • Visualization: Incorporate plots that illustrate model architecture, training loss curves, and overall performance.

References

Add more information in the readme file

Add information in the readme file at https://github.com/matt-lourens/dynamic-qcnn.

Some stuff is standard and existing information that can be summarized in the Readme, other stuff may need to be created. They include:

Feel free to ping me, @stephendiadamo or Unitary Fund advisors for questions.

Hi

Can I work on this project?

UnitaryHack Bounty - Research and Implement Sorting Networks with HierarQcal

Issue: Research and implement sorting networks using the Python package HierarQcal.

Overview

I recently came across the concept of sorting networks and it seems like hierarQcal might be a good fit to implement (and hopefully generate/discover) these networks. I don't know much of the theory behind these sorting networks, so part of this task will be some research (but not neccesarily too much). The idea is to create a jupyter notebook tutorial containing demonstrations and some analysis of sorting networks implemented with hierarQcal. I've provided an example of bubble sort below, use that as reference for implementing two to three other sorting networks. Ultimately, the underlying reason for the issue is to explore how (or if) HierarQcal could facilitate efficient sorting algorithm discovery, contributing to automatic algorithm generation. Use this perspective during implementation and research of these algorithms.

Outcome

  • A Jupyter notebook tutorial that contains atleast two sorting networks (outside the bubble sort example, altough include it in the notebook).

Example: Bubble Sort

Here's an example of a Bubble Sort implementation using HierarQcal:

from hierarqcal import (
    Qcycle,
    Qmotif,
    Qinit,
    Qmask,
    Qunmask,
    Qpermute,
    Qpivot,
    plot_circuit,
    plot_motif,
    get_tensor_as_f,
    Qunitary,
    Qhierarchy,
)

def comparator(bits, symbols=None, state=None):
    v1, v2 = state[bits[0]], state[bits[1]]
    if v1 > v2:
        state[bits[0]], state[bits[1]] = v2, v1
    return state

h_comparator = Qunitary(comparator, n_symbols=0, arity=2)
array = [8, 5, 2, 1, 3, 4, 6, 7, 7, 7]
nb = len(array)  # number of indices
hierq = Qinit(len(array), state=array) + (
    Qcycle(stride=1, step=1, offset=0, mapping=h_comparator, boundary="open") + Qmask("*1")
) * (nb - 1)

# Plot the circuit
plot_circuit(hierq, plot_width=40)
sorted_array = hierq()
print(f"Starting array: {array}\n Sorted array: {sorted_array}")

sorted

Implement a N - qubit QFT with one line of code.

Summary

The Quantum Fourier Transform has nice symmetry in it's circuit representation, as seen here from Nielsen and Chuang Chapter 5:
image

This amends itself well to being implementable with HierarQcal. We will however need a new primitive operation called Qpivot which given a 2 qubit unitary, cycles though each qubit and connects it to one pivot qubit (pivot acts as target, more detail below). The gist of this issue is implementing the new Qpivot primitive and showcasing it's usage in the examples notebook with QFT, which I think we can do in essentially one line.

Example usage

It will go something like this:

N = 5
h_top = Qpivot(pattern="1*", mapping=u_h)
controlled_rs = Qpivot(pattern="1*", mapping=u_cr, share_weights=False)
hcr = h_top + controlled_rs
qft = Qinit(N)  + (hcr + Qmask("1*"))*(N)

The Qpivot primitive is very similar to the Qmask primitive so use that as a reference (see Qmask examples in quickstart.ipynb), and I'm happy to explain in more detail how Qmask works to make the development easier. Qpivot will receive a pattern string, where '1' indicates the pivot qubit and 0 the control. The star is a wild card which gets filled with '0''s based on the number of available qubits. 1* pivots to the top qubit, *1 to the bottom, *1* to the middle, 1*1*1 has 3 pivots which can be connected based on nearest neighbour or the normal cycle pattern, something similar is already implemented in Qmask which I can take you through. For one qubit unitaries (such as the h_top for the Hadamard) the unitary gets placed only on pivot qubits. You can ignore the N>2-qubit unitary case, I will implement that logic but it will be the same idea as Qmask.

Here's some examples of the directed graphs corresponding the pivot primitive (qubits are nodes and 2-qubit unitaries edges):

Pivot "1*" pattern on 8 qubits

pivot_1

Pivot "*1" pattern on 8 qubits

pivot_8

Recommend Projects

  • React photo React

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

  • Vue.js photo Vue.js

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

  • Typescript photo Typescript

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

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

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

  • web

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

  • server

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

  • Machine learning

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

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

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

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.