{"id":46391624,"url":"https://github.com/richarc/qx","last_synced_at":"2026-05-15T22:04:38.416Z","repository":{"id":318001525,"uuid":"1068102453","full_name":"richarc/qx","owner":"richarc","description":"A quantum computing simulator for Elixir with support for up to 20 qubits, statevector simulation, and circuit visualization. Available on Hex.pm as qx_sim.","archived":false,"fork":false,"pushed_at":"2026-02-19T19:45:09.000Z","size":1496,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-19T21:37:29.711Z","etag":null,"topics":["elixir","hexpm","nx","quantum-computing","quantum-simulator"],"latest_commit_sha":null,"homepage":"https://hex.pm/packages/qx_sim","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/richarc.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-10-01T21:24:56.000Z","updated_at":"2026-02-19T19:45:12.000Z","dependencies_parsed_at":"2025-10-04T13:29:22.990Z","dependency_job_id":null,"html_url":"https://github.com/richarc/qx","commit_stats":null,"previous_names":["richarc/qx"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/richarc/qx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/richarc%2Fqx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/richarc%2Fqx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/richarc%2Fqx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/richarc%2Fqx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/richarc","download_url":"https://codeload.github.com/richarc/qx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/richarc%2Fqx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30081230,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T12:28:08.313Z","status":"ssl_error","status_checked_at":"2026-03-04T12:27:28.210Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elixir","hexpm","nx","quantum-computing","quantum-simulator"],"created_at":"2026-03-05T09:01:42.649Z","updated_at":"2026-05-15T22:04:38.410Z","avatar_url":"https://github.com/richarc.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Qx - Quantum Computing Simulator for Elixir\n\n[![Hex.pm](https://img.shields.io/hexpm/v/qx_sim.svg)](https://hex.pm/packages/qx_sim)\n[![Documentation](https://img.shields.io/badge/docs-hexpm-blue.svg)](https://hexdocs.pm/qx_sim/)\n[![License](https://img.shields.io/hexpm/l/qx_sim.svg)](LICENSE)\n[![CI](https://github.com/richarc/qx/actions/workflows/ci.yml/badge.svg)](https://github.com/richarc/qx/actions/workflows/ci.yml)\n[![Release](https://github.com/richarc/qx/actions/workflows/release.yml/badge.svg)](https://github.com/richarc/qx/actions/workflows/release.yml)\n\nQx is a quantum computing simulator built for Elixir that provides an intuitive API for creating and simulating quantum circuits. The primary goal of the project is to enhance my understanding of quantum computing concepts, quantum simulators and the Elixir Nx library. My hope is that it is eventualy valuable for others to learn quantum computing. It supports up to 20 qubits (an arbitrary number that I feel is useful but still below the memory cliff that would occurs around 30 qubits).\n\n## Features\n\n- **Two Modes of Operation**:\n  - **Circuit Mode**: Build quantum circuits and execute them (traditional workflow)\n  - **Calculation Mode**: Apply gates in real-time and inspect states immediately (great for learning!)\n- **Simple API**: Easy-to-use functions for quantum circuit creation and simulation\n- **Up to 20 Qubits**: Supports quantum circuits with up to 20 qubits\n- **Statevector Simulation**: Uses statevector method for accurate quantum state representation\n- **Optional Acceleration**: Add EXLA or EMLX backends for speedup (CPU/GPU)\n- **Visualization**: Built-in plotting capabilities with SVG and VegaLite support, plus circuit diagram generation\n- **Growing Range of Gates**: Supports H, X, Y, Z, S, S†, T, RX, RY, RZ, CNOT, CZ, CP, SWAP, iSWAP, U (general single-qubit unitary), CSWAP (Fredkin), and Toffoli gates\n- **Measurements**: Quantum measurements with classical bit storage\n- **Conditional Operations**: Mid-circuit measurement with classical feedback for quantum processes like teleportation and error correction\n- **OpenQASM 3.0 Round-Trip**: Export Qx circuits to OpenQASM 3.0 and import OpenQASM 3.0 source produced by Qx, Qiskit, or IBM Quantum (`Qx.Export.OpenQASM.to_qasm/1` and `from_qasm/1`)\n- **Remote Execution**: Run circuits on real quantum hardware via QxServer, a standalone backend service supporting IBM Quantum and other providers\n- **LiveBook Integration**: Full support with interactive visualizations in LiveBook\n\n## Installation\n\n```elixir\ndef deps do\n  [\n    {:qx_sim, \"~\u003e 0.6.0\"}\n  ]\nend\n```\n\nThen run:\n\n```bash\nmix deps.get\n```\n\nOr install from GitHub for the latest development version:\n\n```elixir\ndef deps do\n  [\n    {:qx_sim, github: \"richarc/qx\", branch: \"main\"}\n  ]\nend\n```\n\nThis installs Qx with the default `Nx.BinaryBackend`, which works on all platforms but is slower for larger quantum circuits (10+ qubits).\n\n\u003e **Want better performance?** See [Performance \u0026 Acceleration](#performance--acceleration) to add optional EXLA (CPU/GPU) or EMLX (Apple Silicon GPU) backends.\n\n## Quick Start\n\n```elixir\niex\u003e # Create a qubit and put it in superposition\niex\u003e q = Qx.Qubit.new() |\u003e Qx.Qubit.h()\niex\u003e Qx.Qubit.measure_probabilities(q)\n#Nx.Tensor\u003c[0.5, 0.5]\u003e\n\niex\u003e # Build and run a Bell state circuit\niex\u003e result = Qx.bell_state() |\u003e Qx.run()\niex\u003e IO.inspect(result.counts)\n%{\"00\" =\u003e 512, \"11\" =\u003e 512}\n\niex\u003e # Visualize the results\niex\u003e Qx.draw(result)\n```\n\nFor the complete API, see the [hexdocs](https://hexdocs.pm/qx_sim/Qx.html).\n\n## Getting Started with LiveBook\n\n[LiveBook](https://livebook.dev/) is the perfect environment for interactive quantum computing with Qx. Create a new notebook and add this in the setup cell:\n\n```elixir\nMix.install([\n  {:qx, \"~\u003e 0.6.0\", hex: :qx_sim},\n  {:kino, \"~\u003e 0.12\"},\n  {:vega_lite, \"~\u003e 0.1.11\"},\n  {:kino_vega_lite, \"~\u003e 0.1.11\"}\n])\n```\n\nFor interactive guides and tutorials, visit [qxquantum.com/guides](https://www.qxquantum.com/guides).\n\nTry creating a Bell state and visualizing it:\n\n```elixir\ncircuit = Qx.create_circuit(2, 2)\n          |\u003e Qx.h(0)\n          |\u003e Qx.cx(0, 1)\n          |\u003e Qx.measure(0, 0)\n          |\u003e Qx.measure(1, 1)\n\nresult = Qx.run(circuit, 1000)\nQx.draw_counts(result)\n```\n\n**Tips for LiveBook users:**\n- Start with the basic setup for learning and small circuits, add [acceleration](#livebook-acceleration-snippets) when needed\n- Use Calculation Mode (`Qx.Qubit` / `Qx.Register`) for interactive exploration\n- `Qx.draw_counts/1` returns VegaLite specs that render beautifully in LiveBook\n- Use `tap_state/2` and `tap_probabilities/2` in pipelines for immediate feedback\n\n\n## Understanding the Two Modes\n\nQx offers two ways to work with quantum states:\n\n**Calculation Mode** (`Qx.Qubit` / `Qx.Register`): Gates apply immediately and you can inspect state at any step. Best for learning, debugging, and interactive exploration.\n\n**Circuit Mode** (`Qx.create_circuit`): Build a circuit description first, then execute it with `Qx.run/2`. Best for multi-shot simulations, measurements with classical feedback, OpenQASM 3.0 export and import, and running on real hardware.\n\n| | Calculation Mode | Circuit Mode |\n|---|---|---|\n| Gates apply | Immediately | On `Qx.run/2` |\n| State inspection | Anytime | Before measurements only |\n| Measurements | Probabilities only | Full measurement + classical bits |\n| Multi-shot | No | Yes |\n| Hardware export | No | Yes (OpenQASM) |\n\n## Calculation Mode\n\n### Single Qubits (Qx.Qubit)\n\nCreate qubits and apply gates in real-time:\n\n```elixir\n# Create and manipulate qubits directly - gates apply immediately!\nq = Qx.Qubit.new()\n  |\u003e Qx.Qubit.h()\n\nQx.Qubit.show_state(q)\n# Output:\n# %{\n#   state: \"0.707|0⟩ + 0.707|1⟩\",\n#   amplitudes: [{\"|0⟩\", \"0.707+0.000i\"}, {\"|1⟩\", \"0.707+0.000i\"}],\n#   probabilities: [{\"|0⟩\", 0.5}, {\"|1⟩\", 0.5}]\n# }\n\n# Inspect state at any step\nq = Qx.Qubit.new()\nQx.Qubit.measure_probabilities(q)  # [1.0, 0.0] - definitely |0⟩\n\nq = Qx.Qubit.x(q)\nQx.Qubit.measure_probabilities(q)  # [0.0, 1.0] - definitely |1⟩\n\nq = Qx.Qubit.h(q)\nQx.Qubit.measure_probabilities(q)  # [0.5, 0.5] - superposition!\n```\n\nQubits can be created from various starting points: `Qx.Qubit.new()` for |0⟩, `Qx.Qubit.one()` for |1⟩, `Qx.Qubit.plus()` / `Qx.Qubit.minus()` for superposition states, or `Qx.Qubit.from_bloch(theta, phi)` for arbitrary Bloch sphere coordinates.\n\n#### Pipeline Patterns \u0026 Debugging\n\n**Transformation operations** return qubits and continue the pipeline:\n```elixir\nresult = Qx.Qubit.new()\n  |\u003e Qx.Qubit.h()\n  |\u003e Qx.Qubit.x()\n  |\u003e Qx.Qubit.ry(:math.pi() / 4)\n```\n\n**`tap_state/2`** inspects state without breaking the chain:\n```elixir\nresult = Qx.Qubit.new()\n  |\u003e Qx.Qubit.h()\n  |\u003e Qx.Qubit.tap_state(label: \"After Hadamard\")  # Prints state, returns qubit\n  |\u003e Qx.Qubit.x()\n  |\u003e Qx.Qubit.tap_state(label: \"After X gate\")    # Prints state, returns qubit\n```\n\n**Terminal operations** return data and end the pipeline:\n```elixir\nstate_info = Qx.Qubit.new()\n  |\u003e Qx.Qubit.h()\n  |\u003e Qx.Qubit.x()\n  |\u003e Qx.Qubit.show_state()  # Returns map with state data\n\nIO.puts(state_info.state)  # \"0.707|0⟩ - 0.707|1⟩\"\n```\n\n### Multi-Qubit Registers (Qx.Register)\n\nRegisters support multi-qubit gates and entanglement with the same immediate-apply behavior:\n\n```elixir\n# Create a Bell state in real-time\nreg = Qx.Register.new(2)\n  |\u003e Qx.Register.h(0)\n  |\u003e Qx.Register.cx(0, 1)\n\nQx.Register.show_state(reg)\n# Output shows entangled state:\n# %{\n#   state: \"0.707|00⟩ + 0.707|11⟩\",\n#   amplitudes: [{\"|00⟩\", \"0.707+0.000i\"}, {\"|01⟩\", \"0.000+0.000i\"}, ...],\n#   probabilities: [{\"|00⟩\", 0.5}, {\"|01⟩\", 0.0}, {\"|10⟩\", 0.0}, {\"|11⟩\", 0.5}]\n# }\n\n# Create from basis states\nreg = Qx.Register.from_basis_states([0, 1, 0])  # |010⟩ state\n\n# Create in equal superposition\nreg = Qx.Register.from_superposition(3)  # All 8 states equally likely\n\n# Create register from existing qubits\nq1 = Qx.Qubit.new(0.6, 0.8)  # Custom state\nq2 = Qx.Qubit.plus()          # |+⟩ state\nreg = Qx.Register.new([q1, q2])\n  |\u003e Qx.Register.h(0)\n```\n\n## Circuit Mode\n\n### Building \u0026 Running Circuits\n\n```elixir\n# Create a circuit with 2 qubits and 2 classical bits\nqc = Qx.create_circuit(2, 2)\n     |\u003e Qx.h(0)           # Apply Hadamard gate to qubit 0\n     |\u003e Qx.cx(0, 1)       # Apply CNOT gate (control: 0, target: 1)\n     |\u003e Qx.measure(0, 0)  # Measure qubit 0, store in classical bit 0\n     |\u003e Qx.measure(1, 1)  # Measure qubit 1, store in classical bit 1\n\n# Run the simulation\nresult = Qx.run(qc, 1000)  # 1000 measurement shots\n\n# Display results\nIO.inspect(result.counts)\n```\n\nThe `Qx.run/2` function returns a `SimulationResult` struct with helper functions:\n\n```elixir\n{most_common, count} = Qx.SimulationResult.most_frequent(result)\noutcomes = Qx.SimulationResult.outcomes(result)\nprob = Qx.SimulationResult.probability(result, \"00\")\n```\n\nFor circuits without measurements, you can inspect the quantum state directly:\n\n```elixir\nstate = Qx.get_state(circuit)\nprobs = Qx.get_probabilities(circuit)\n```\n\nPipeline-friendly tap functions allow inspecting circuits during construction:\n\n```elixir\nresult = Qx.create_circuit(2)\n  |\u003e Qx.h(0)\n  |\u003e Qx.tap_state(\u0026IO.inspect(\u00261, label: \"State after H\"))\n  |\u003e Qx.cx(0, 1)\n  |\u003e Qx.tap_probabilities(fn p -\u003e IO.puts(\"Bell state created!\") end)\n  |\u003e Qx.run(1000)\n```\n\n### Conditional Operations \u0026 Mid-Circuit Measurement\n\n`Qx.c_if/4` applies gates conditionally based on classical bit values, enabling quantum teleportation, error correction, and adaptive algorithms:\n\n```elixir\n# Quantum teleportation with conditional corrections\nqc = Qx.create_circuit(3, 3)\n     |\u003e Qx.x(0)                    # State to teleport\n     |\u003e Qx.h(1) |\u003e Qx.cx(1, 2)     # Create Bell pair\n     |\u003e Qx.cx(0, 1) |\u003e Qx.h(0)     # Bell measurement\n     |\u003e Qx.measure(0, 0)\n     |\u003e Qx.measure(1, 1)\n     # Conditional corrections based on measurement\n     |\u003e Qx.c_if(1, 1, fn c -\u003e Qx.x(c, 2) end)\n     |\u003e Qx.c_if(0, 1, fn c -\u003e Qx.z(c, 2) end)\n     |\u003e Qx.measure(2, 2)\n\nresult = Qx.run(qc, 1000)\n# Qubit 2 now contains the teleported state!\n```\n\n## Examples\n\n### Bell State\n\n```elixir\nresult = Qx.bell_state() |\u003e Qx.run(1000)\nIO.inspect(result.counts)\n# =\u003e %{\"00\" =\u003e ~500, \"11\" =\u003e ~500}\nQx.draw_counts(result)\n```\n\n### Quantum Teleportation\n\n```elixir\n# Teleport |1⟩ state from qubit 0 to qubit 2\nqc = Qx.create_circuit(3, 3)\n     |\u003e Qx.x(0)                           # Prepare |1⟩ to teleport\n     |\u003e Qx.h(1)                           # Create Bell pair\n     |\u003e Qx.cx(1, 2)                       # between qubits 1 and 2\n     |\u003e Qx.cx(0, 1)                       # Bell measurement\n     |\u003e Qx.h(0)\n     |\u003e Qx.measure(0, 0)                  # Measure qubit 0\n     |\u003e Qx.measure(1, 1)                  # Measure qubit 1\n     |\u003e Qx.c_if(1, 1, fn c -\u003e Qx.x(c, 2) end)  # Conditional corrections\n     |\u003e Qx.c_if(0, 1, fn c -\u003e Qx.z(c, 2) end)\n     |\u003e Qx.measure(2, 2)                  # Measure teleported qubit\n\nresult = Qx.run(qc, 1000)\n\n# Analyze results\n{most_common, count} = Qx.SimulationResult.most_frequent(result)\nIO.puts(\"Most frequent: #{most_common} (#{count} times)\")\n# All outcomes should have rightmost bit = 1 (successful teleportation)\n\nQx.draw_counts(result)\n```\n\n### Grover's Algorithm (Simplified)\n\n```elixir\n# Simplified Grover's algorithm for 2 qubits\ngrover = Qx.create_circuit(2)\n         |\u003e Qx.h(0)        # Initialize superposition\n         |\u003e Qx.h(1)\n         # Oracle (flip phase of target state)\n         |\u003e Qx.z(0)\n         |\u003e Qx.z(1)\n         # Diffusion operator\n         |\u003e Qx.h(0)\n         |\u003e Qx.h(1)\n         |\u003e Qx.x(0)\n         |\u003e Qx.x(1)\n         |\u003e Qx.cx(0, 1)\n         |\u003e Qx.x(0)\n         |\u003e Qx.x(1)\n         |\u003e Qx.h(0)\n         |\u003e Qx.h(1)\n\nresult = Qx.run(grover)\nQx.draw(result)\n```\n\n### Working with Quantum States\n\n**Circuit Mode:**\n```elixir\n# Create a 3-qubit GHZ state and examine its properties\nghz_circuit = Qx.ghz_state()\n\n# Get the quantum state vector\nstate = Qx.get_state(ghz_circuit)\nIO.inspect(Nx.to_flat_list(state))\n\n# Get probabilities for all computational basis states\nprobs = Qx.get_probabilities(ghz_circuit)\nQx.histogram(probs)\n```\n\n**Calculation Mode:**\n```elixir\n# Create and inspect qubit states in real-time\nq = Qx.Qubit.new()\n  |\u003e Qx.Qubit.h()\n  |\u003e Qx.Qubit.z()\n\nstate_info = Qx.Qubit.show_state(q)\nIO.puts(state_info.state)  # \"0.707|0⟩ - 0.707|1⟩\"\nIO.inspect(state_info.probabilities)  # [{\"|0⟩\", 0.5}, {\"|1⟩\", 0.5}]\n\n# Create from Bloch sphere (theta=π/2, phi=0 gives |+⟩)\nq = Qx.Qubit.from_bloch(:math.pi() / 2, 0)\nQx.Qubit.show_state(q)\n\n# Chain rotation gates\nq = Qx.Qubit.new()\n  |\u003e Qx.Qubit.rx(:math.pi() / 4)\n  |\u003e Qx.Qubit.ry(:math.pi() / 3)\n  |\u003e Qx.Qubit.rz(:math.pi() / 6)\n\nQx.Qubit.show_state(q)\n```\n\n## Visualization\n\nQx provides several visualization functions that work in both LiveBook (VegaLite) and standalone (SVG) environments.\n\n**Results visualization:**\n\n```elixir\nresult = Qx.bell_state() |\u003e Qx.run(1000)\n\nQx.draw(result)                  # Probability distribution (VegaLite)\nQx.draw(result, format: :svg)    # Probability distribution (SVG)\nQx.draw_counts(result)           # Measurement counts\n```\n\n**Circuit diagrams:**\n\n```elixir\ncircuit = Qx.create_circuit(2, 2)\n          |\u003e Qx.h(0)\n          |\u003e Qx.cx(0, 1)\n          |\u003e Qx.measure(0, 0)\n          |\u003e Qx.measure(1, 1)\n\nsvg = Qx.Draw.circuit(circuit, \"Bell State\")\nFile.write!(\"bell_state.svg\", svg)\n```\n\nCircuit diagrams support all quantum gates with proper IEEE notation, parametric gates with displayed angles, multi-qubit gates, barriers, and measurements with classical bit connections.\n\n**Bloch sphere (Calculation Mode):**\n\n```elixir\nQx.Qubit.new() |\u003e Qx.Qubit.h() |\u003e Qx.Qubit.draw_bloch()\n```\n\n**Probability histograms:**\n\n```elixir\nprobs = Qx.get_probabilities(circuit)\nQx.histogram(probs)\n```\n\n## Importing OpenQASM\n\nQx can read OpenQASM 3.0 source produced by itself, by Qiskit, or by IBM Quantum. Combined with `Qx.Export.OpenQASM.to_qasm/1` this provides round-trip interoperability.\n\n### Import a complete program\n\n```elixir\nqasm = \"\"\"\nOPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc[0] = measure q[0];\nc[1] = measure q[1];\n\"\"\"\n\n{:ok, circuit} = Qx.Export.OpenQASM.from_qasm(qasm)\nresult = Qx.run(circuit, shots: 1024)\n```\n\nErrors come back as typed exceptions:\n\n* `Qx.QasmParseError` — grammar/syntax problems (with `:line`, `:column`, `:snippet`)\n* `Qx.QasmUnsupportedError` — valid QASM that uses a feature outside the supported subset (multi-register, gate modifiers, `else`, …)\n\n`from_qasm!/1` is the bang variant.\n\n### Import a `gate` definition as an Elixir function\n\nFor storing user-defined gates as reusable circuit-transforming functions (e.g. in [qxportal](https://github.com/richarc/qxportal)), use `from_qasm_function/1`:\n\n```elixir\nqasm = \"\"\"\nOPENQASM 3.0;\ninclude \"stdgates.inc\";\ngate bell a, b {\n  h a;\n  cx a, b;\n}\n\"\"\"\n\n{:ok, %{name: \"bell\", arity: 3, source: source}} =\n  Qx.Export.OpenQASM.from_qasm_function(qasm)\n\n# source is an Elixir `def …` string:\n#   def bell(circuit, a, b) do\n#     circuit\n#     |\u003e Qx.h(a)\n#     |\u003e Qx.cx(a, b)\n#   end\n\n# Compile and call it:\n[{module, _bin}] = Code.compile_string(\"defmodule MyGates do\\n  #{source}\\nend\")\nnew_circuit = MyGates.bell(Qx.create_circuit(2), 0, 1)\n```\n\nThe signature is `(circuit, params…, qubits…)` — circuit first, then declared parameters in source order, then qubit arguments in source order.\n\n### Supported subset\n\nSee `Qx.Export.OpenQASM` module documentation for the full list of supported gates, decompositions, and explicitly-excluded features.\n\n## Running on IBM Quantum Hardware\n\nQx can submit circuits directly to IBM Quantum hardware via `Qx.Hardware`. Circuits are exported to OpenQASM 3.0, transpiled through the qxportal service, submitted to IBM, and results are returned as `Qx.SimulationResult` structs.\n\n### Prerequisites\n\n1. A [qxportal](https://qxquantum.com) account and API token.\n2. An IBM Cloud account with the Quantum service enabled — you'll need:\n   - IBM Cloud API key\n   - Quantum service CRN (Cloud Resource Name)\n   - Region (e.g. `\"us-east\"`)\n\n### Setup\n\nThe simplest path uses environment variables and `Qx.Hardware.Config.from_env!/1`:\n\n```bash\nexport QX_PORTAL_URL=https://api.qxquantum.com\nexport QX_PORTAL_TOKEN=\u003cyour qxportal token\u003e\nexport QX_IBM_API_KEY=\u003cyour IBM Cloud API key\u003e\nexport QX_IBM_CRN=\u003cyour IBM Quantum service CRN\u003e\nexport QX_IBM_REGION=us-east\nexport QX_IBM_BACKEND=ibm_brisbane\n```\n\n```elixir\nconfig = Qx.Hardware.Config.from_env!()\n```\n\nOr construct the struct directly:\n\n```elixir\n{:ok, config} =\n  Qx.Hardware.Config.new(\n    portal_url: \"https://api.qxquantum.com\",\n    portal_token: System.fetch_env!(\"QX_PORTAL_TOKEN\"),\n    ibm_api_key: System.fetch_env!(\"QX_IBM_API_KEY\"),\n    ibm_crn: System.fetch_env!(\"QX_IBM_CRN\"),\n    ibm_region: \"us-east\",\n    backend: \"ibm_brisbane\",\n    optimization_level: 1,\n    shots: 4096\n  )\n```\n\n### Run a Circuit on Hardware\n\n```elixir\ncircuit =\n  Qx.QuantumCircuit.new(2, 2)\n  |\u003e Qx.h(0)\n  |\u003e Qx.cx(0, 1)\n  |\u003e Qx.measure(0, 0)\n  |\u003e Qx.measure(1, 1)\n\n{:ok, result} = Qx.Hardware.run(circuit, config, on_status: \u0026IO.inspect/1)\n\nIO.inspect(result.counts)\n# =\u003e %{\"00\" =\u003e 2050, \"11\" =\u003e 2046}  (approximately)\n```\n\n`Qx.Hardware.run/3` is synchronous: it blocks until the IBM job reaches a terminal status. Status callback events fire at each pipeline stage (authentication, transpile, submit, poll, results).\n\n### Lower-Level Entry Points\n\n  * `Qx.Hardware.submit_qasm/3` — submit a hand-authored OpenQASM 3.0 program.\n  * `Qx.Hardware.transpile/3` — transpile only (no submission), useful for inspection.\n  * `Qx.Hardware.list_backends/2` — enumerate backends visible to the configured account.\n  * `Qx.Hardware.cancel/3` — best-effort job cancellation.\n\n### Privacy invariant\n\n`Qx.Hardware` uses two independent HTTP clients (`Qx.Hardware.Portal` for qxportal, `Qx.Hardware.Ibm` for IBM Cloud). The portal token never reaches IBM, and the IBM API key never reaches the portal — both clients read only their own fields from the shared `Qx.Hardware.Config`.\n\n## Performance \u0026 Acceleration\n\nQx works out-of-the-box with `Nx.BinaryBackend` on all platforms, but you can add acceleration backends for significant speedups, especially for circuits with 10+ qubits.\n\n### Choosing a Backend\n\n| Backend | Platform | Compilation Required |\n|---------|----------|---------------------|\n| **Nx.BinaryBackend** | All | No (default) |\n| **EXLA (CPU)** | All | Yes (C++ compiler needed) |\n| **EXLA (CUDA)** | Linux/Windows + NVIDIA GPU | Yes + CUDA Toolkit |\n| **EXLA (ROCm)** | Linux + AMD GPU | Yes + ROCm |\n| **EMLX (Metal)** | macOS Apple Silicon | No (precompiled) |\n\n### EXLA CPU (Recommended)\n\n**Best for**: All platforms, no GPU required\n\nEXLA provides significant speedup through XLA's LLVM optimizations.\n\n**Prerequisites:**\n- **macOS:** `xcode-select --install`\n- **Linux (Debian/Ubuntu):** `sudo apt install build-essential`\n- **Linux (Fedora/RHEL):** `sudo dnf groupinstall \"Development Tools\"`\n- **Windows:** [Visual Studio Build Tools](https://visualstudio.microsoft.com/downloads/) with C++ support, or [WSL2](https://docs.microsoft.com/en-us/windows/wsl/install) (recommended)\n\n**Step 1:** Add EXLA to `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:qx_sim, \"~\u003e 0.6.0\"},\n    {:exla, \"~\u003e 0.10\"}  # Add this line\n  ]\nend\n```\n\n**Step 2:** Install and configure:\n\n```bash\nmix deps.get\n```\n\nCreate or edit `config/config.exs`:\n\n```elixir\nimport Config\nconfig :nx, :default_backend, EXLA.Backend\n```\n\n**Note**: First-time EXLA compilation takes several minutes. See [EXLA installation guide](https://hexdocs.pm/exla/EXLA.html) if compilation fails.\n\n**Step 3:** Verify:\n\n```elixir\niex\u003e Nx.default_backend()\nEXLA.Backend\n```\n\n---\n\n### EXLA + NVIDIA GPU (CUDA)\n\n**Best for**: Linux/Windows with NVIDIA GPU\n\n**Step 1:** Install [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) 11.8 or 12.0 and verify with `nvcc --version`.\n\n**Step 2:** Set environment variable in your shell profile:\n\n```bash\n# For CUDA 11.x\nexport XLA_TARGET=cuda118\n\n# For CUDA 12.x\nexport XLA_TARGET=cuda120\n```\n\n**Step 3:** Add EXLA to `mix.exs` (same as CPU above) and run `mix deps.get`.\n\n**Step 4:** Configure in `config/config.exs`:\n\n```elixir\nimport Config\nconfig :nx, :default_backend, {EXLA.Backend, client: :cuda}\n```\n\n**Step 5:** Verify GPU is detected:\n\n```elixir\niex\u003e :cuda in EXLA.Client.get_supported_platforms()\ntrue\n```\n\n**Troubleshooting:** If CUDA is not found, ensure `XLA_TARGET` is set correctly (`echo $XLA_TARGET`). For runtime errors, update NVIDIA drivers (`nvidia-smi` to check).\n\n---\n\n### EXLA + AMD GPU (ROCm)\n\n**Best for**: Linux with AMD GPU\n\n**Step 1:** Install [ROCm](https://rocm.docs.amd.com/) 5.4+ and verify with `rocm-smi`.\n\n**Step 2:** Add EXLA to `mix.exs` (same as CPU above) and run `mix deps.get`.\n\n**Step 3:** Configure in `config/config.exs`:\n\n```elixir\nimport Config\nconfig :nx, :default_backend, {EXLA.Backend, client: :rocm}\n```\n\n---\n\n### EMLX + Apple Silicon (Metal)\n\n**Best for**: macOS M1/M2/M3/M4, no compilation required\n\n**Note**: EXLA does not support Metal GPU acceleration. For CPU-only acceleration on Apple Silicon, use EXLA CPU instead.\n\n**Step 1:** Add EMLX to `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:qx_sim, \"~\u003e 0.6.0\"},\n    {:emlx, github: \"elixir-nx/emlx\", branch: \"main\"}  # Add this line\n  ]\nend\n```\n\n**Step 2:** `mix deps.get` (EMLX downloads precompiled binaries automatically).\n\n**Step 3:** Configure in `config/config.exs`:\n\n```elixir\nimport Config\nconfig :nx, :default_backend, {EMLX.Backend, device: :gpu}\n```\n\n**Notes:**\n- Metal does not support 64-bit floats, but Qx uses Complex64 which is fully supported\n- For CPU-only acceleration on Apple Silicon, use EXLA CPU instead\n\n---\n\n### Runtime Backend Selection\n\nStarting with Qx v0.3.0, you can select backends at runtime without compile-time configuration:\n\n```elixir\nqc = Qx.create_circuit(10) |\u003e Qx.h(0) |\u003e Qx.cx(0, 1)\n\n# Run with EXLA backend (even if binary backend is default)\nresult = Qx.run(qc, backend: EXLA.Backend)\n\n# Run with EXLA + CUDA\nresult = Qx.run(qc, backend: {EXLA.Backend, client: :cuda})\n\n# Run with EMLX on Apple Silicon\nresult = Qx.run(qc, backend: {EMLX.Backend, device: :gpu})\n\n# Combine with other options\nresult = Qx.run(qc, backend: EXLA.Backend, shots: 2048)\n```\n\nThe `:backend` option also works with `Qx.get_state/2` and `Qx.get_probabilities/2`.\n\nYou can combine both approaches: set a default in `config/config.exs` and override it at runtime when needed.\n\n---\n\n### LiveBook Acceleration Snippets\n\nFor LiveBook, add the acceleration backend to your `Mix.install` call:\n\n**EXLA CPU (all platforms):**\n```elixir\nMix.install([\n  {:qx, \"~\u003e 0.6.0\", hex: :qx_sim},\n  {:exla, \"~\u003e 0.10\"},\n  {:kino, \"~\u003e 0.12\"},\n  {:vega_lite, \"~\u003e 0.1.11\"},\n  {:kino_vega_lite, \"~\u003e 0.1.11\"}\n])\n\nApplication.put_env(:nx, :default_backend, EXLA.Backend)\n```\n\n**EMLX GPU (Apple Silicon):**\n```elixir\nMix.install([\n  {:qx, \"~\u003e 0.6.0\", hex: :qx_sim},\n  {:emlx, github: \"elixir-nx/emlx\", branch: \"main\"},\n  {:kino, \"~\u003e 0.12\"},\n  {:vega_lite, \"~\u003e 0.1.11\"},\n  {:kino_vega_lite, \"~\u003e 0.1.11\"}\n])\n\nApplication.put_env(:nx, :default_backend, {EMLX.Backend, device: :gpu})\n```\n\n**EXLA CUDA (NVIDIA GPU):** Requires `XLA_TARGET` env var set (see [CUDA setup](#exla--nvidia-gpu-cuda)).\n```elixir\nMix.install([\n  {:qx, \"~\u003e 0.6.0\", hex: :qx_sim},\n  {:exla, \"~\u003e 0.10\"},\n  {:kino, \"~\u003e 0.12\"},\n  {:vega_lite, \"~\u003e 0.1.11\"},\n  {:kino_vega_lite, \"~\u003e 0.1.11\"}\n])\n\nApplication.put_env(:nx, :default_backend, {EXLA.Backend, client: :cuda})\n```\n\n## Error Handling\n\nQx provides domain-specific exceptions for clear error messages:\n\n```elixir\ntry do\n  circuit |\u003e Qx.h(999)\nrescue\n  Qx.QubitIndexError -\u003e IO.puts(\"Invalid qubit index!\")\n  Qx.GateError -\u003e IO.puts(\"Gate operation failed!\")\nend\n```\n\nException types include `QubitIndexError`, `StateNormalizationError`, `MeasurementError`, `ConditionalError`, `ClassicalBitError`, `GateError`, `QubitCountError`, and `RemoteError`. See the [hexdocs](https://hexdocs.pm/qx_sim/Qx.html) for details.\n\n## Requirements \u0026 Limitations\n\n- Elixir 1.18+, Nx 0.10+, VegaLite 0.1+\n- Optional: EXLA 0.10+ or EMLX 0.2+ for acceleration\n- Maximum 20 qubits\n- Statevector simulation only (no density matrix or noise modeling)\n\n## Roadmap\n\nSee [ROADMAP.md](ROADMAP.md) for planned features and the strategic direction of Qx.\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Make your changes and ensure tests pass (`mix test`)\n4. Run code quality checks (`mix credo --strict`)\n5. Commit and open a Pull Request\n\nFor maintainers preparing a release, see [RELEASE.md](RELEASE.md).\n\n## License\n\nThis project is licensed under the Apache License 2.0.\n\n## Acknowledgments\n\n- Built with [Nx](https://github.com/elixir-nx/nx) for numerical computations\n- Visualization powered by [VegaLite](https://github.com/livebook-dev/vega_lite)\n- Inspired by quantum computing frameworks like Qiskit and Cirq\n\n## Version\n\nCurrent version: 0.6.0\n\nFor detailed API documentation, see the [hexdocs](https://hexdocs.pm/qx_sim/Qx.html).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fricharc%2Fqx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fricharc%2Fqx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fricharc%2Fqx/lists"}