TensorCircuit SDK with TianYan Quantum Cloud¶
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.
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 for platform access and current service information.
Prerequisites¶
pip install "tensorcircuit-ng[cloud]"
pip install "cqlib>=1.3.10,<1.4"
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.
[ ]:
import os
import time
import tensorcircuit as tc
if not os.getenv("TC_TOKEN_TIANYAN"):
raise RuntimeError("Set the TC_TOKEN_TIANYAN environment variable first")
Provider configuration¶
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.
[ ]:
tc.cloud.apis.set_provider("tianyan")
# token is picked up automatically from the TC_TOKEN_TIANYAN env var
print("Providers:", tc.cloud.apis.list_providers())
print("Current provider:", tc.cloud.apis.get_provider())
Devices and properties¶
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.
[ ]:
devices = tc.cloud.apis.list_devices(provider="tianyan")
print(f"Available TianYan devices ({len(devices)}):")
for available_device in devices:
print(f" - {available_device}")
sim_device = tc.cloud.apis.get_device("tianyan::tianyan_sw")
real_device = tc.cloud.apis.get_device("tianyan::tianyan176")
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.
[ ]:
properties = real_device.list_properties()
print("Native gates:", real_device.native_gates())
print("Available qubits:", len(properties["bits"]))
print("Coupling edges:", len(properties["links"]) // 2)
print("First topology edges:", real_device.topology()[:10])
Tasks¶
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.
[ ]:
def bell_circuit():
circuit = tc.Circuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_instruction(0, 1)
return circuit
circuit = bell_circuit()
task = tc.cloud.apis.submit_task(circuit=circuit, device=sim_device, shots=1000)
print("Task ID:", task.id_)
results(blocked=True) waits until the task finishes and returns a counts dictionary. An ideal Bell state should be dominated by 00 and 11.
[ ]:
counts = task.results(blocked=True)
print("Counts:", counts)
tc.results.counts.plot_histogram(counts)
Asynchronous simulator submission¶
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.
[ ]:
async_task = tc.cloud.apis.submit_task(
circuit=bell_circuit(), device=sim_device, shots=100
)
print("Asynchronous task ID:", async_task.id_)
while True:
async_details = async_task.details()
print("State:", async_details["state"])
if async_details["state"] == "completed":
print("Counts:", async_task.results(blocked=False))
break
if async_details["state"] == "failed":
raise RuntimeError(async_details.get("err", "TianYan task failed"))
time.sleep(1)
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.
[ ]:
details = task.details()
print("State:", task.state())
print("Shots:", details["shots"])
print("QCIS:\n", details["source"])
restored_task = tc.cloud.apis.get_task(task.id_, device=sim_device)
print("Restored task result:", restored_task.results(blocked=True))
Cloud simulator¶
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.
[ ]:
circuits = [bell_circuit() for _ in range(3)]
tasks = tc.cloud.apis.submit_task(circuit=circuits, device=sim_device, shots=100)
for index, batch_task in enumerate(tasks, start=1):
print(f"Task {index}: {batch_task.results(blocked=True)}")
If you already have QCIS or OpenQASM 2 source, you can bypass TensorCircuit circuit construction. OpenQASM is converted to QCIS by cqlib before submission.
[ ]:
qcis = "H Q0\nH Q1\nCZ Q0 Q1\nH Q1\nM Q0\nM Q1"
qcis_task = tc.cloud.apis.submit_task(source=qcis, device=sim_device, shots=100)
print("Direct QCIS result:", qcis_task.results(blocked=True))
[ ]:
qasm = """OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
cx q[0],q[1];
measure q -> c;
"""
qasm_task = tc.cloud.apis.submit_task(
source=qasm, lang="OPENQASM", device=sim_device, shots=100
)
print("OpenQASM result:", qasm_task.results(blocked=True))
Gate conversion and topology validation¶
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.
[ ]:
q1, q2 = sorted(real_device.topology()[0])
hardware_circuit = bell_circuit().initial_mapping({0: q1, 1: q2}, n=q2 + 1)
hardware_task = tc.cloud.apis.submit_task(
circuit=hardware_circuit, device=real_device, shots=100
)
hardware_counts = hardware_task.results(blocked=True)
hardware_details = hardware_task.details()
print("Physical qubits:", q1, q2)
print("Hardware counts:", hardware_counts)
print("QCIS:\n", hardware_details["source"])
Provider differences and limitations¶
A shared API does not imply identical backend capabilities. The current TianYan provider has these boundaries:
tc.cloud.apis.list_tasks(...)andtc.cloud.apis.remove_task(...)raiseNotImplementedErrorbecause the currentcqlibrelease has no usable task-listing or cancellation endpoint.Measurements from TensorCircuit circuits are submitted as terminal measurements; mid-circuit measurement semantics are not preserved.
Topology validation applies to real hardware only; simulators do not impose hardware coupling constraints. Circuits must respect the device topology before submission.
Keep hardware shots small; execute the real-device cell only when you intend to use hardware resources.