{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# TensorCircuit SDK with TianYan Quantum Cloud\n", "\n", "This tutorial follows the provider-agnostic TensorCircuit cloud workflow and uses the shared `tc.cloud.apis` entry point to connect to the China Telecom TianYan quantum computing platform. It covers device discovery, task lifecycle management, cloud simulation, batch submission, and topology-aware execution on real hardware.\n", "\n", "TianYan provides simulators such as `tianyan_sw` and superconducting devices such as `tianyan176`. Its native task format is QCIS. Device names and availability are always determined by the live platform response. Visit the [TianYan Quantum Cloud](https://qc.zdxlz.com/) for platform access and current service information.\n", "\n", "## Prerequisites\n", "\n", "```bash\n", "pip install \"tensorcircuit-ng[cloud]\"\n", "pip install \"cqlib>=1.3.10,<1.4\"\n", "```\n", "\n", "`cqlib` requires Python 3.10 or later and NumPy 2.1.2 or later. Provide the login key through the `TC_TOKEN_TIANYAN` environment variable (read automatically by the cloud token system) instead of storing it in the notebook." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n", "import time\n", "\n", "import tensorcircuit as tc\n", "\n", "if not os.getenv(\"TC_TOKEN_TIANYAN\"):\n", " raise RuntimeError(\"Set the TC_TOKEN_TIANYAN environment variable first\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Provider configuration\n", "\n", "As in the Tencent tutorial, cloud operations go through `tc.cloud.apis`. Switching providers does not change the device, task, or result abstractions. The token is kept in the current process only and is not written to the local cache." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tc.cloud.apis.set_provider(\"tianyan\")\n", "# token is picked up automatically from the TC_TOKEN_TIANYAN env var\n", "\n", "print(\"Providers:\", tc.cloud.apis.list_providers())\n", "print(\"Current provider:\", tc.cloud.apis.get_provider())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Devices and properties\n", "\n", "Query the live device list first, then select a simulator or a real quantum device. A `Device` object exposes common interfaces for properties, native gates, and coupling topology." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "devices = tc.cloud.apis.list_devices(provider=\"tianyan\")\n", "print(f\"Available TianYan devices ({len(devices)}):\")\n", "for available_device in devices:\n", " print(f\" - {available_device}\")\n", "\n", "sim_device = tc.cloud.apis.get_device(\"tianyan::tianyan_sw\")\n", "real_device = tc.cloud.apis.get_device(\"tianyan::tianyan176\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calibration data and coupling constraints determine whether a circuit can be mapped directly to a real device. The following cell only queries metadata; it does not submit a hardware task." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "properties = real_device.list_properties()\n", "print(\"Native gates:\", real_device.native_gates())\n", "print(\"Available qubits:\", len(properties[\"bits\"]))\n", "print(\"Coupling edges:\", len(properties[\"links\"]) // 2)\n", "print(\"First topology edges:\", real_device.topology()[:10])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tasks\n", "\n", "Create a Bell state and submit it to the cloud simulator. TensorCircuit converts the circuit to QCIS; measurements are submitted as terminal measurements in their recorded order." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def bell_circuit():\n", " circuit = tc.Circuit(2)\n", " circuit.h(0)\n", " circuit.cx(0, 1)\n", " circuit.measure_instruction(0, 1)\n", " return circuit\n", "\n", "\n", "circuit = bell_circuit()\n", "task = tc.cloud.apis.submit_task(circuit=circuit, device=sim_device, shots=1000)\n", "print(\"Task ID:\", task.id_)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`results(blocked=True)` waits until the task finishes and returns a counts dictionary. An ideal Bell state should be dominated by `00` and `11`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "counts = task.results(blocked=True)\n", "print(\"Counts:\", counts)\n", "tc.results.counts.plot_histogram(counts)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Asynchronous simulator submission\n", "\n", "`submit_task` returns immediately with a task ID. Each `details()` call is non-blocking; this cell polls explicitly and uses `results(blocked=False)` only after the task is complete." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "async_task = tc.cloud.apis.submit_task(\n", " circuit=bell_circuit(), device=sim_device, shots=100\n", ")\n", "print(\"Asynchronous task ID:\", async_task.id_)\n", "\n", "while True:\n", " async_details = async_task.details()\n", " print(\"State:\", async_details[\"state\"])\n", " if async_details[\"state\"] == \"completed\":\n", " print(\"Counts:\", async_task.results(blocked=False))\n", " break\n", " if async_details[\"state\"] == \"failed\":\n", " raise RuntimeError(async_details.get(\"err\", \"TianYan task failed\"))\n", " time.sleep(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `Task` workflow matches Tencent: inspect the current state, details, and ID, then reconstruct a task from its ID and device. TianYan details additionally retain the submitted QCIS source." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "details = task.details()\n", "print(\"State:\", task.state())\n", "print(\"Shots:\", details[\"shots\"])\n", "print(\"QCIS:\\n\", details[\"source\"])\n", "\n", "restored_task = tc.cloud.apis.get_task(task.id_, device=sim_device)\n", "print(\"Restored task result:\", restored_task.results(blocked=True))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Cloud simulator\n", "\n", "The simulator supports batch submission. As with Tencent, submitting a list of circuits returns a corresponding list of `Task` objects; a batch uses one shots value." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "circuits = [bell_circuit() for _ in range(3)]\n", "tasks = tc.cloud.apis.submit_task(circuit=circuits, device=sim_device, shots=100)\n", "\n", "for index, batch_task in enumerate(tasks, start=1):\n", " print(f\"Task {index}: {batch_task.results(blocked=True)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you already have QCIS or OpenQASM 2 source, you can bypass TensorCircuit circuit construction. OpenQASM is converted to QCIS by `cqlib` before submission." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "qcis = \"H Q0\\nH Q1\\nCZ Q0 Q1\\nH Q1\\nM Q0\\nM Q1\"\n", "qcis_task = tc.cloud.apis.submit_task(source=qcis, device=sim_device, shots=100)\n", "print(\"Direct QCIS result:\", qcis_task.results(blocked=True))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "qasm = \"\"\"OPENQASM 2.0;\n", "include \"qelib1.inc\";\n", "qreg q[2];\n", "creg c[2];\n", "h q[0];\n", "cx q[0],q[1];\n", "measure q -> c;\n", "\"\"\"\n", "qasm_task = tc.cloud.apis.submit_task(\n", " source=qasm, lang=\"OPENQASM\", device=sim_device, shots=100\n", ")\n", "print(\"OpenQASM result:\", qasm_task.results(blocked=True))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Gate conversion and topology validation\n", "\n", "Real devices impose native-gate and coupling constraints. The provider does not compile or remap qubits automatically: circuits submitted to real hardware must already respect the device topology. Use TensorCircuit or Qiskit compilation and mapping tools before submission. For simple cases, `Circuit.initial_mapping` maps a logical circuit onto chosen physical qubits; for larger circuits use `tensorcircuit.compiler`. TensorCircuit circuits are validated against the device topology before submission, and incompatible ones raise a `ValueError`. The following cell submits a real-device task; run it only when you intend to use hardware resources." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "q1, q2 = sorted(real_device.topology()[0])\n", "hardware_circuit = bell_circuit().initial_mapping({0: q1, 1: q2}, n=q2 + 1)\n", "hardware_task = tc.cloud.apis.submit_task(\n", " circuit=hardware_circuit, device=real_device, shots=100\n", ")\n", "hardware_counts = hardware_task.results(blocked=True)\n", "hardware_details = hardware_task.details()\n", "print(\"Physical qubits:\", q1, q2)\n", "print(\"Hardware counts:\", hardware_counts)\n", "print(\"QCIS:\\n\", hardware_details[\"source\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Provider differences and limitations\n", "\n", "A shared API does not imply identical backend capabilities. The current TianYan provider has these boundaries:\n", "\n", "- `tc.cloud.apis.list_tasks(...)` and `tc.cloud.apis.remove_task(...)` raise `NotImplementedError` because the current `cqlib` release has no usable task-listing or cancellation endpoint.\n", "- Measurements from TensorCircuit circuits are submitted as terminal measurements; mid-circuit measurement semantics are not preserved.\n", "- Topology validation applies to real hardware only; simulators do not impose hardware coupling constraints. Circuits must respect the device topology before submission.\n", "- Keep hardware shots small; execute the real-device cell only when you intend to use hardware resources." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.10.0" }, "nbsphinx": { "execute": "never" } }, "nbformat": 4, "nbformat_minor": 4 }