Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export static backend files for web app #1444

Merged
merged 9 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ dmypy.json
mod_exp_bloq.json
mod_exp_cbloq.json
musical_score_example.json
ui_export/

# Jupyter
jupyter_kernel.lock
850 changes: 6 additions & 844 deletions dev_tools/autogenerate-bloqs-notebooks-v2.py

Large diffs are not rendered by default.

869 changes: 869 additions & 0 deletions dev_tools/qualtran_dev_tools/notebook_specs.py

Large diffs are not rendered by default.

19 changes: 14 additions & 5 deletions dev_tools/qualtran_dev_tools/parse_docstrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,28 @@ def _template(name, desc_lines):
]


def get_markdown_docstring_lines(cls: Type) -> List[str]:
def get_markdown_docstring(cls: Type) -> List[str]:
"""From a class `cls`, return its docstring as Markdown lines."""

# 1. Sphinx incantation
config = Config()
docstring = cls.__doc__ if cls.__doc__ else ""
gds = _GoogleDocstringToMarkdown(inspect.cleandoc(docstring), config=config, what='class')

# 2. Pre-pend a header.
lines = [f'## `{cls.__name__}`'] + gds.lines()
# 2. Substitute restructured text inline-code blocks to markdown-style backticks.
lines = [re.sub(r':py:func:`(\w+)`', r'`\1`', line) for line in gds.lines()]

return lines


# 3. Substitute restructured text inline-code blocks to markdown-style backticks.
lines = [re.sub(r':py:func:`(\w+)`', r'`\1`', line) for line in lines]
def get_markdown_docstring_lines(cls: Type) -> List[str]:
"""From a class `cls`, return its docstring as Markdown lines with a header."""

# 1. Get documentation lines
lines = get_markdown_docstring(cls)

# 2. Pre-pend a header.
lines = [f'## `{cls.__name__}`'] + lines

return lines

Expand Down
189 changes: 189 additions & 0 deletions dev_tools/ui-export.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from qualtran.bloqs.factoring.mod_exp import ModExp\n",
"from qualtran.drawing import get_musical_score_data, draw_musical_score\n",
"\n",
"modexp_small = ModExp(base=3, mod=16, exp_bitsize=3, x_bitsize=2048)\n",
"ms = get_musical_score_data(modexp_small.decompose_bloq())\n",
"\n",
"draw_musical_score(ms)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"from sympy import Symbol\n",
"from typing import Any\n",
"\n",
"from qualtran.drawing.musical_score import MusicalScoreEncoder\n",
"from qualtran._infra.registers import Side\n",
"\n",
"class BloqEncoder(MusicalScoreEncoder):\n",
"\n",
" def default(self, o: Any) -> Any:\n",
" if isinstance(o, (Symbol)):\n",
" return f'Symbol({o})'\n",
" if isinstance(o, complex):\n",
" return f'{o.real}+{o.imag}i'\n",
" if isinstance(o, Side):\n",
" return 'Side.LEFT' if o == Side.LEFT else 'Side.RIGHT' if o == Side.RIGHT else 'Side.THRU'\n",
"\n",
" try:\n",
" return super().default(o)\n",
" except:\n",
" return 'NOT_SERIALIZABLE'"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"import attrs\n",
"import hashlib\n",
"\n",
"from qualtran import CompositeBloq\n",
"from qualtran.bloqs.rotations.programmable_rotation_gate_array import ProgrammableRotationGateArray\n",
"\n",
"def bloq_attrs(bloq):\n",
" if isinstance(bloq, CompositeBloq):\n",
" return {}\n",
" if isinstance(bloq, ProgrammableRotationGateArray):\n",
" return {}\n",
"\n",
" return attrs.asdict(bloq)\n",
"\n",
"def bloq_filename(bloq):\n",
" unhashed = json.dumps(bloq_attrs(bloq), cls=BloqEncoder)\n",
"\n",
" return hashlib.md5(unhashed.encode(), usedforsecurity=False).hexdigest() + '.json'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"from pathlib import Path\n",
"\n",
"from qualtran_dev_tools.notebook_specs import NB_BY_SECTION\n",
"\n",
"docs_by_section = {\n",
" section[0]: {\n",
" notebook_spec.title: list(\n",
" {\n",
" 'name': bloq_spec.bloq_cls.__name__,\n",
" 'examples': list(\n",
" {\n",
" 'name': example.name,\n",
" 'filename': bloq_filename(example.make())\n",
" }\n",
" for example in bloq_spec.examples\n",
" )\n",
" }\n",
" for bloq_spec in notebook_spec.bloq_specs\n",
" )\n",
" for notebook_spec in section[1]\n",
" }\n",
" for section in NB_BY_SECTION\n",
"}\n",
"\n",
"Path('ui_export').mkdir(parents=True, exist_ok=True)\n",
"\n",
"with open('ui_export/navigation.json', 'w') as f:\n",
" json.dump(docs_by_section, f, indent=2)"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"import os\n",
"from pathlib import Path\n",
"\n",
"from qualtran_dev_tools.notebook_specs import NB_BY_SECTION\n",
"from qualtran_dev_tools.parse_docstrings import get_markdown_docstring\n",
"from qualtran.drawing.musical_score import get_musical_score_data\n",
"\n",
"def bloq_score(bloq):\n",
" try:\n",
" return get_musical_score_data(bloq.decompose_bloq())\n",
" except:\n",
" return None\n",
"\n",
"def write_example(bloq):\n",
" call_graph, _ = bloq.call_graph(max_depth=1)\n",
"\n",
" for child_bloq, _ in call_graph.succ[bloq].items():\n",
" write_example(child_bloq)\n",
"\n",
" Path(f'ui_export/{bloq.__class__.__name__}').mkdir(parents=True, exist_ok=True)\n",
"\n",
" doc_name = f'ui_export/{bloq.__class__.__name__}/docs.txt'\n",
" if not os.path.isfile(doc_name):\n",
" with open(doc_name, 'w') as doc_file:\n",
" doc_file.write('\\n'.join(get_markdown_docstring(bloq.__class__)))\n",
"\n",
" file_name = f'ui_export/{bloq.__class__.__name__}/{bloq_filename(bloq)}'\n",
" if not os.path.isfile(file_name):\n",
" bloq_dict = {\n",
" 'name': bloq.__class__.__name__,\n",
" 'attrs': bloq_attrs(bloq),\n",
" 'score': bloq_score(bloq),\n",
" 'callees': list(\n",
" {\n",
" 'name': child_bloq.__class__.__name__,\n",
" 'filename': bloq_filename(child_bloq)\n",
" }\n",
" for child_bloq, _ in call_graph.succ[bloq].items()\n",
" )\n",
" }\n",
"\n",
" with open(file_name, 'w') as f:\n",
" json.dump(bloq_dict, f, indent=2, cls=BloqEncoder)\n",
"\n",
"for section in NB_BY_SECTION:\n",
" for notebook_spec in section[1]:\n",
" for bloq_spec in notebook_spec.bloq_specs:\n",
" for example in bloq_spec.examples:\n",
" write_example(example.make())"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "qualtran",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
2 changes: 1 addition & 1 deletion qualtran/Autodoc.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@
"\n",
"This code should be located in the module defining the bloq class.\n",
"\n",
"Each bloq class has one `BloqDocSpec` which may have multiple bloq examples. Each jupyter notebook roughly corresponds to one module or package and can document multiple bloq classes in it, so the final step is to plumb through the `BloqDocSpec` into a `NotebookSpec`. In `dev_tools/autogenerate-bloqs-notebooks-v2.py`, you can add a new `NotebookSpecV2` to the big list or add your `BloqDocSpec` to an existing one. If you execute this script, it will generate a new notebook or new cells in an existing notebook with documentation for your bloq. You may need to manually `git add` the new notebook.\n",
"Each bloq class has one `BloqDocSpec` which may have multiple bloq examples. Each jupyter notebook roughly corresponds to one module or package and can document multiple bloq classes in it, so the final step is to plumb through the `BloqDocSpec` into a `NotebookSpec`. In `dev_tools/qualtran_dev_tools/notebook_specs.py`, you can add a new `NotebookSpecV2` to the big list or add your `BloqDocSpec` to an existing one. If you execute this script, it will generate a new notebook or new cells in an existing notebook with documentation for your bloq. You may need to manually `git add` the new notebook.\n",
"\n",
"\n",
"```python\n",
Expand Down
6 changes: 4 additions & 2 deletions qualtran/bloqs/basic_gates/hadamard.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@
"\n",
"This converts between the X and Z basis.\n",
"\n",
"$$\\begin{aligned}\n",
"$$\n",
"\\begin{aligned}\n",
"H |0\\rangle = |+\\rangle \\\\\n",
"H |-\\rangle = |1\\rangle\n",
"\\end{aligned}$$\n",
"\\end{aligned}\n",
"$$\n",
"\n",
"#### Registers\n",
" - `q`: The qubit\n"
Expand Down
6 changes: 4 additions & 2 deletions qualtran/bloqs/basic_gates/hadamard.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ class Hadamard(Bloq):

This converts between the X and Z basis.

$$\begin{aligned}
$$
\begin{aligned}
H |0\rangle = |+\rangle \\
H |-\rangle = |1\rangle
\end{aligned}$$
\end{aligned}
$$

Registers:
q: The qubit
Expand Down
Loading