diff --git a/notebooks/05_p2p_fabric_sharing.ipynb b/notebooks/05_p2p_fabric_sharing.ipynb new file mode 100644 index 0000000..cf89438 --- /dev/null +++ b/notebooks/05_p2p_fabric_sharing.ipynb @@ -0,0 +1,186 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, + "colab": {"name": "knitweb-lens: P2P sharing of circuits, results & systems", "provenance": []} + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": ["# P2P sharing of circuits, **results** & **quantum systems**\n", + "\n", + "The quantum layer shares three content-addressed artifact kinds, each in its own CID namespace:\n", + "\n", + "| kind | type | CID |\n", + "|---|---|---|\n", + "| circuit | `QuantumCircuit` | `lcid:` |\n", + "| result | `QuantumResult` | `lres:` |\n", + "| system | `BackendDescriptor` | `lqpu:` |\n", + "\n", + "This notebook runs a circuit, captures its **result**, describes the **backend** it ran on, then shares all three between two nodes by content id — like file-sharing, but for quantum.\n", + "\n", + "[](https://colab.research.google.com/github/Knitweb/lens/blob/main/notebooks/05_p2p_fabric_sharing.ipynb)\n"] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": ["!pip install -q knitweb-lens qiskit qiskit-aer"] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": ["## 1. A circuit → its `lcid:`"] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from knitweb_lens.quantum import library, QuantumResult, BackendDescriptor, Store, search\n", + "\n", + "circ = library()['bell_phi_plus']\n", + "print('circuit :', circ.meta.name)\n", + "print('cid :', circ.cid) # lcid:...\n", + "print(circ.qasm)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": ["## 2. Run it → a `QuantumResult` (`lres:`)\n", + "We execute on Qiskit Aer and wrap the measured counts as a content-addressed result that links back to the circuit."] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit import qasm2, transpile\n", + "from qiskit_aer import AerSimulator\n", + "\n", + "sim = AerSimulator()\n", + "qc = qasm2.loads(circ.qasm)\n", + "counts = sim.run(transpile(qc, sim), shots=1024).result().get_counts()\n", + "counts = {k.replace(' ', ''): int(v) for k, v in counts.items()}\n", + "print('counts:', counts)\n", + "\n", + "result = QuantumResult(circuit_cid=circ.cid, counts=counts, author='demo')\n", + "print('result cid :', result.cid) # lres:...\n", + "print('of circuit :', result.circuit_cid)\n", + "print('most freq :', result.most_frequent)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": ["## 3. Describe the backend → a `BackendDescriptor` (`lqpu:`)"] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "backend = BackendDescriptor(name='aer_simulator', provider='local', n_qubits=32,\n", + " native_gates=['h', 'cx', 'rz', 'ry', 'rx', 'ccx'], simulator=True)\n", + "print('backend cid:', backend.cid) # lqpu:...\n", + "\n", + "# Bind the result to the system it ran on (provenance).\n", + "result = QuantumResult(circuit_cid=circ.cid, counts=counts,\n", + " backend_cid=backend.cid, author='demo')\n", + "print('result now records ran-on:', result.backend_cid)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": ["## 4. Node **A** publishes all three by content id\n", + "Set `KNITWEB_RELAY` to a live Knitweb relay to actually broadcast; otherwise this writes to a local node store and we simulate the peer sync in the next cell."] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os, tempfile\n", + "relay = os.environ.get('KNITWEB_RELAY') # e.g. 'https://relay.5mart.ml'\n", + "node_a = Store(root=tempfile.mkdtemp(prefix='nodeA_'), relay=relay)\n", + "\n", + "for art in (circ, backend, result):\n", + " cid = node_a.put(art)\n", + " print('published', cid)\n", + "\n", + "print('\\nnode A holds', len(node_a), 'artifacts across kinds:')\n", + "for item in node_a.list():\n", + " print(' ', item['kind'], item['cid'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": ["## 5. Node **B** pulls by CID — knowledge crosses the network\n", + "With a relay, node B fetches from it. Without one, we hand B the same store dir to stand in for a completed peer sync — the point is that **the CID is all B needs**."] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "node_b = Store(root=(tempfile.mkdtemp(prefix='nodeB_') if relay else node_a.root), relay=relay)\n", + "\n", + "got_circuit = node_b.get(circ.cid)\n", + "got_result = node_b.get(result.cid)\n", + "got_backend = node_b.get(backend.cid)\n", + "\n", + "print('B pulled circuit:', got_circuit.meta.name)\n", + "print('B pulled result :', got_result.most_frequent, 'from', got_result.circuit_cid)\n", + "print('B pulled backend:', got_backend.name, f'({got_backend.n_qubits}q)')\n", + "\n", + "# Content integrity: the CID B fetched recomputes to the same id A minted.\n", + "assert got_circuit.cid == circ.cid\n", + "assert got_result.cid == result.cid\n", + "assert got_backend.cid == backend.cid\n", + "print('\\nAll CIDs verified — bit-identical across nodes.')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": ["## 6. Query across kinds on node B"] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print('results on B :', [i['cid'] for i in node_b.list(kind='result')])\n", + "print('backends on B:', [i['cid'] for i in node_b.list(kind='backend')])\n", + "print('find \"aer\" :', [h['meta']['name'] for h in node_b.find(query='aer', kind='backend')])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": ["## 7. True P2P over the Knitweb fabric\n", + "For real peer-to-peer discovery (anti-entropy sync + a read-only `/interpret` query gateway + a proof-of-useful-work \"run this circuit, return verified counts\" job), a Knitweb **node** weaves these artifacts into the fabric via `knitweb.quantum` (in the [`Knitweb/pulse`](https://github.com/Knitweb/pulse) package):\n", + "\n", + "```python\n", + "from knitweb.quantum import QuantumCircuitRecord, publish, build_lens\n", + "rec = QuantumCircuitRecord(circuit_cid=circ.cid, name='bell', qubits=2, domain='fundamental')\n", + "await node.weave(rec.to_record()) # announces the CID to peers\n", + "# peers can then: query_space(space, 'circuits domain=fundamental') -> [lcid:...]\n", + "```\n", + "\n", + "The `knitweb-lens` SDK mints and stores the artifacts; the fabric carries the lean, queryable descriptors. Same CIDs, everywhere."] + } + ] +} diff --git a/web/index.html b/web/index.html index c96520d..c1ec360 100644 --- a/web/index.html +++ b/web/index.html @@ -7,7 +7,7 @@
@@ -120,8 +135,15 @@