Skip to content

Notebook illustrating Qualtran -> QIR Compiler#658

Draft
skushnir123 wants to merge 6 commits intoquantumlib:mainfrom
skushnir123:qir
Draft

Notebook illustrating Qualtran -> QIR Compiler#658
skushnir123 wants to merge 6 commits intoquantumlib:mainfrom
skushnir123:qir

Conversation

@skushnir123
Copy link
Copy Markdown
Contributor

@skushnir123 skushnir123 commented Feb 14, 2024

Part of #622

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the changes here mostly due to running the notebook? We typically clear output of all notebooks before committing to the repository.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, just from running stuff. I can revert these changes.

Copy link
Copy Markdown
Collaborator

@tanujkhattar tanujkhattar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great start! It'd be pretty cool if we can also hookup the QIR output of QFT with the microsoft resource estimator to produce resource estimation numbers. But we can also do that in a follow up PR

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's create a new folder qualtran/qir_interop/ and put all the code for QIR interop there.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok will do

"outputs": [],
"source": [
"import numpy as np\n",
"import pyqir\n",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll have to add pyqir to the requirements file and recompile dependencies using dev_tools/requirements/re-pip-compile.sh

Comment on lines +38 to +57
"@attrs.frozen\n",
"class Swap(Bloq):\n",
" n: int\n",
"\n",
" @property\n",
" def signature(self):\n",
" return Signature.build(x=self.n, y=self.n)\n",
"\n",
" def build_composite_bloq(\n",
" self, bb: BloqBuilder, *, x: SoquetT, y: SoquetT\n",
" ) -> Dict[str, SoquetT]:\n",
" xs = bb.split(x)\n",
" ys = bb.split(y)\n",
"\n",
" for i in range(self.n):\n",
" xs[i], ys[i] = bb.add(CNOT(), ctrl=xs[i], target=ys[i])\n",
" return {\n",
" 'x': bb.join(xs),\n",
" 'y': bb.join(ys),\n",
" }\n",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these three are good examples to use as test cases for the conversion code in the new bloq_to_qir_test.py file

Comment on lines +141 to +166
"def get_num_qubits_for_bloq(bloq: qualtran.Bloq):\n",
" num_qubits = 0\n",
" for register in bloq.signature.lefts():\n",
" shape = register.shape[0] if len(register.shape) != 0 else 1\n",
" num_qubits += register.bitsize*shape\n",
" return num_qubits\n",
"\n",
"def create_func_for_bloq(bloq: qualtran.Bloq, name, qubit_type, void_type, mod: pyqir.Module):\n",
" num_qubits = get_num_qubits_for_bloq(bloq)\n",
" return Function(\n",
" pyqir.FunctionType(void_type, [qubit_type]*num_qubits),\n",
" Linkage.EXTERNAL,\n",
" name,\n",
" mod\n",
" )\n",
"\n",
"def create_ir_map(bloq: qualtran.Bloq):\n",
" param_counter = 0\n",
" ir_map = {}\n",
" # Loop through all registers in signature\n",
" for register in bloq.signature.lefts():\n",
" shape = register.shape[0] if len(register.shape) != 0 else 1 # get the shape as an int (we are asumming its 1d for simplicity)\n",
" # map the (register_name, index_in_register) to the overall index\n",
" ir_map.update({(register.name, i*register.bitsize + j): param_counter + i*register.bitsize + j for i in range(shape) for j in range(register.bitsize)})\n",
" param_counter += register.bitsize * shape\n",
" return ir_map\n",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can move all the utility functions to a new file bloq_to_qir.py and add tests using the example cases shown above.

" ir_map = create_ir_map(bloq)\n",
" soq_map = {}\n",
"\n",
" # It seems like QFTTextBook and PhaseGradientUnitary can be decomposed even though supports_decompose_bloq returns false\n",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a bug in the GateWithRegisters base class. We should override this method for the GateWithRegister class to check whether the sub-bloq defines a cirq style decomposition and if yes, the return True from supports_decompose_bloq.

Can you open a separate issue to track this?

cc @mpharrigan

" return bloq_func, ir_map\n",
"\n",
"\n",
"def convert_qualtran(bloq: qualtran.Bloq):\n",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"def convert_qualtran(bloq: qualtran.Bloq):\n",
"def bloq_to_qir(bloq: qualtran.Bloq):\n",

" irs = generate_irs_from_soquet(soquet)\n",
" return [ir_map[ir] for ir in irs]\n",
"\n",
"def compile_bloq(bloq: qualtran.Bloq, qubit_type, void_type, module, context, builder, func_dict=dict()):\n",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add docstrings and return type annotations to all the helper functions.

" }\n",
"\n",
"@attrs.frozen\n",
"class ExampleNonTrivialShapeBloq(Bloq):\n",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another example to add (maybe as a followup) would be ExampleNonTrivialSideBloq which has LEFT and RIGHT directional registers instead of all registers being THRU registers.

I think in terms of QIR, a LEFT register implies de-allocation happens inside that function and a RIGHT register corresponds to allocations happening inside that function. If the concepts don't translate directly (eg: because QIR assumes you take care of qubit allocations and deallocations globally and have a sea of globally allocated qubits) then I think both LEFT & RIGHT registers would be treated as inputs to the corresponding the QIR function (we do this when supporting cirq style decomposition where decompose_from_registers() method gets both LEFT & RIGHT registers as preallocated ancilla qubits.

Tl;Dr - Converting bloqs with directional registers should be tracked as a future improvement in the issue

@tanujkhattar tanujkhattar self-assigned this Feb 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants