Initial QVerify Space - verifier-only CPU Basic
Browse files- .gitignore +5 -0
- Dockerfile +22 -0
- README.md +26 -9
- app.py +318 -0
- requirements.txt +9 -0
.gitignore
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.venv/
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.pyc
|
| 4 |
+
.pytest_cache/
|
| 5 |
+
.cache/
|
Dockerfile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.11-slim
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
# Install verifier-only Python deps. requirements.txt deliberately omits
|
| 6 |
+
# torch / transformers / outlines because the Space does not load Gemma.
|
| 7 |
+
COPY requirements.txt .
|
| 8 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 9 |
+
|
| 10 |
+
# Install qverify itself without its declared dependencies (those include
|
| 11 |
+
# torch / transformers, which the verifier-only Space does not need).
|
| 12 |
+
RUN pip install --no-cache-dir --no-deps \
|
| 13 |
+
"qverify @ git+https://github.com/Quantum-Labor/qverify.git@main"
|
| 14 |
+
|
| 15 |
+
COPY app.py .
|
| 16 |
+
|
| 17 |
+
# HuggingFace Spaces expect the app to listen on 0.0.0.0:7860.
|
| 18 |
+
ENV GRADIO_SERVER_NAME=0.0.0.0 \
|
| 19 |
+
GRADIO_SERVER_PORT=7860
|
| 20 |
+
EXPOSE 7860
|
| 21 |
+
|
| 22 |
+
CMD ["python", "app.py"]
|
README.md
CHANGED
|
@@ -1,14 +1,31 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
-
sdk:
|
| 7 |
-
|
| 8 |
-
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
license: apache-2.0
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
---
|
| 13 |
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: QVerify
|
| 3 |
+
emoji: 🔬
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: orange
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
|
|
|
| 8 |
pinned: false
|
| 9 |
license: apache-2.0
|
| 10 |
+
hardware: cpu-basic
|
| 11 |
+
tags:
|
| 12 |
+
- quantum-computing
|
| 13 |
+
- qiskit
|
| 14 |
+
- pennylane
|
| 15 |
+
- llm-verification
|
| 16 |
+
- logic
|
| 17 |
+
- grover
|
| 18 |
---
|
| 19 |
|
| 20 |
+
# QVerify (verifier-only Space)
|
| 21 |
+
|
| 22 |
+
This Space exposes the QVerify verifier component: a CNF is fed
|
| 23 |
+
straight to Grover's search, on either a CPU-side PennyLane simulator
|
| 24 |
+
or IBM Quantum's Heron r2 processor.
|
| 25 |
+
|
| 26 |
+
The translator (Gemma 4 E4B with grammar-constrained generation)
|
| 27 |
+
requires a GPU and is not loaded here. The full pipeline (translator
|
| 28 |
+
plus grounding plus verifier) runs locally from the GitHub repo.
|
| 29 |
+
|
| 30 |
+
[Code](https://github.com/Quantum-Labor/qverify) ·
|
| 31 |
+
[Documentation](https://github.com/Quantum-Labor/qverify/tree/main/docs)
|
app.py
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""QVerify HuggingFace Space - verifier-only demo, runs on CPU Basic.
|
| 2 |
+
|
| 3 |
+
This Space exposes the QVerify *verifier* component: a CNF is fed
|
| 4 |
+
straight to Grover's search, on either the PennyLane simulator (local
|
| 5 |
+
to this Space's CPU container) or IBM Heron r2 hardware (delegated to
|
| 6 |
+
IBM Cloud over the network, account credentials read from Space
|
| 7 |
+
Secrets).
|
| 8 |
+
|
| 9 |
+
The *translator* component (Gemma 4 E4B with grammar-constrained
|
| 10 |
+
generation) is intentionally not loaded here: it needs a GPU, which
|
| 11 |
+
CPU Basic does not provide. The full pipeline runs locally from the
|
| 12 |
+
GitHub repository, see https://github.com/Quantum-Labor/qverify.
|
| 13 |
+
"""
|
| 14 |
+
|
| 15 |
+
from __future__ import annotations
|
| 16 |
+
|
| 17 |
+
import os
|
| 18 |
+
import time
|
| 19 |
+
from dataclasses import dataclass
|
| 20 |
+
from typing import Any
|
| 21 |
+
|
| 22 |
+
import gradio as gr
|
| 23 |
+
|
| 24 |
+
from qverify.translator.cnf import CNF, Clause, Literal
|
| 25 |
+
from qverify.verifier import verify
|
| 26 |
+
from qverify.verifier._universe import Universe
|
| 27 |
+
from qverify.verifier.backends import IBMQuantumBackend, PennyLaneBackend
|
| 28 |
+
from qverify.verifier.grounding import ground_cnf
|
| 29 |
+
|
| 30 |
+
IBM_CONSOLE_BASE = "https://quantum.cloud.ibm.com/workloads?search="
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
@dataclass(frozen=True)
|
| 34 |
+
class CnfExample:
|
| 35 |
+
"""One ready-to-run CNF example surfaced in the Space's dropdown."""
|
| 36 |
+
|
| 37 |
+
label: str
|
| 38 |
+
description: str
|
| 39 |
+
cnf: CNF
|
| 40 |
+
universe: Universe
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def _atom(predicate: str, *args: str, neg: bool = False) -> Literal:
|
| 44 |
+
return Literal(predicate=predicate, args=args, negated=neg)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def _clause(*lits: Literal) -> Clause:
|
| 48 |
+
return Clause(literals=lits)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def _build_examples() -> dict[str, CnfExample]:
|
| 52 |
+
"""Three pre-built CNFs covering propositional, ground first-order, and grounded universal."""
|
| 53 |
+
cat_fur_consistency = CnfExample(
|
| 54 |
+
label="Cat and HasFur consistency",
|
| 55 |
+
description=(
|
| 56 |
+
"Two propositional atoms, both asserted: Cat AND HasFur. The "
|
| 57 |
+
"verifier should report contradiction_found=False (the formula "
|
| 58 |
+
"is consistent: setting both to True satisfies it)."
|
| 59 |
+
),
|
| 60 |
+
cnf=CNF(
|
| 61 |
+
clauses=(
|
| 62 |
+
_clause(_atom("Cat")),
|
| 63 |
+
_clause(_atom("HasFur")),
|
| 64 |
+
)
|
| 65 |
+
),
|
| 66 |
+
universe=Universe(constants=()),
|
| 67 |
+
)
|
| 68 |
+
|
| 69 |
+
tom_is_a_cat = CnfExample(
|
| 70 |
+
label="Tom is a cat",
|
| 71 |
+
description=(
|
| 72 |
+
"A single ground first-order atom: Cat(Tom). Universe = {Tom}. "
|
| 73 |
+
"Trivially satisfiable; consistency mode reports no contradiction."
|
| 74 |
+
),
|
| 75 |
+
cnf=CNF(clauses=(_clause(_atom("Cat", "Tom")),)),
|
| 76 |
+
universe=Universe(constants=("Tom",)),
|
| 77 |
+
)
|
| 78 |
+
|
| 79 |
+
universal_rule = CnfExample(
|
| 80 |
+
label="Universal cat-fur rule",
|
| 81 |
+
description=(
|
| 82 |
+
"First-order rule 'forall x. Cat(x) -> HasFur(x)' grounded over "
|
| 83 |
+
"{Tom, Whiskers}. The grounded CNF has two clauses, one per "
|
| 84 |
+
"constant. Consistent: any assignment that makes both Cat(Tom) "
|
| 85 |
+
"and Cat(Whiskers) false satisfies the formula."
|
| 86 |
+
),
|
| 87 |
+
cnf=CNF(
|
| 88 |
+
clauses=(
|
| 89 |
+
_clause(
|
| 90 |
+
_atom("Cat", "x", neg=True),
|
| 91 |
+
_atom("HasFur", "x"),
|
| 92 |
+
),
|
| 93 |
+
)
|
| 94 |
+
),
|
| 95 |
+
universe=Universe(constants=("Tom", "Whiskers")),
|
| 96 |
+
)
|
| 97 |
+
|
| 98 |
+
return {
|
| 99 |
+
cat_fur_consistency.label: cat_fur_consistency,
|
| 100 |
+
tom_is_a_cat.label: tom_is_a_cat,
|
| 101 |
+
universal_rule.label: universal_rule,
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
EXAMPLES = _build_examples()
|
| 106 |
+
EXAMPLE_LABELS = list(EXAMPLES.keys())
|
| 107 |
+
DEFAULT_LABEL = EXAMPLE_LABELS[0]
|
| 108 |
+
|
| 109 |
+
IBM_TOKEN_PRESENT = bool(os.environ.get("IBM_QUANTUM_TOKEN"))
|
| 110 |
+
IBM_INSTANCE_PRESENT = bool(os.environ.get("IBM_QUANTUM_INSTANCE"))
|
| 111 |
+
IBM_AVAILABLE = IBM_TOKEN_PRESENT and IBM_INSTANCE_PRESENT
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def _format_cnf(cnf: CNF) -> str:
|
| 115 |
+
"""Render a CNF as a readable multi-line string."""
|
| 116 |
+
if not cnf.clauses:
|
| 117 |
+
return "(empty CNF, trivially satisfied)"
|
| 118 |
+
lines = []
|
| 119 |
+
for c in cnf.clauses:
|
| 120 |
+
lits = []
|
| 121 |
+
for lit in c.literals:
|
| 122 |
+
args = f"({', '.join(lit.args)})" if lit.args else ""
|
| 123 |
+
lits.append(f"{'¬' if lit.negated else ''}{lit.predicate}{args}")
|
| 124 |
+
lines.append("(" + " ∨ ".join(lits) + ")")
|
| 125 |
+
return "\n".join(lines)
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
def _on_example_change(label: str) -> tuple[str, str, str]:
|
| 129 |
+
"""Update the CNF preview, universe preview, and description on dropdown change."""
|
| 130 |
+
ex = EXAMPLES[label]
|
| 131 |
+
universe_str = ", ".join(ex.universe.constants) if ex.universe.constants else "(empty)"
|
| 132 |
+
return _format_cnf(ex.cnf), universe_str, ex.description
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def _run_verify(label: str, mode: str, backend_kind: str) -> dict[str, Any]:
|
| 136 |
+
"""Ground the example CNF, run Grover's search, and return a JSON-friendly result."""
|
| 137 |
+
if label not in EXAMPLES:
|
| 138 |
+
return {"error": f"unknown example: {label}"}
|
| 139 |
+
|
| 140 |
+
ex = EXAMPLES[label]
|
| 141 |
+
grounded = ground_cnf(ex.cnf, ex.universe)
|
| 142 |
+
|
| 143 |
+
if backend_kind == "pennylane":
|
| 144 |
+
backend = PennyLaneBackend()
|
| 145 |
+
elif backend_kind == "ibm":
|
| 146 |
+
if not IBM_AVAILABLE:
|
| 147 |
+
return {
|
| 148 |
+
"error": (
|
| 149 |
+
"IBM_QUANTUM_TOKEN and/or IBM_QUANTUM_INSTANCE are not "
|
| 150 |
+
"set in this Space's Secrets. The IBM hardware path is "
|
| 151 |
+
"unavailable; use the simulator button."
|
| 152 |
+
)
|
| 153 |
+
}
|
| 154 |
+
backend = IBMQuantumBackend()
|
| 155 |
+
else:
|
| 156 |
+
return {"error": f"unknown backend kind: {backend_kind}"}
|
| 157 |
+
|
| 158 |
+
start = time.monotonic()
|
| 159 |
+
result = verify(grounded, backend=backend, mode=mode)
|
| 160 |
+
wall = round(time.monotonic() - start, 1)
|
| 161 |
+
|
| 162 |
+
counter_model: Any
|
| 163 |
+
if result.counter_model is None:
|
| 164 |
+
if mode == "consistency":
|
| 165 |
+
counter_model = (
|
| 166 |
+
"(consistency mode: no satisfying assignment is surfaced; "
|
| 167 |
+
"this is expected when the formula is consistent because "
|
| 168 |
+
"the verifier does not display a model in this mode, and "
|
| 169 |
+
"when inconsistent because UNSAT means there is none)"
|
| 170 |
+
)
|
| 171 |
+
else:
|
| 172 |
+
counter_model = "no counter-model found (formula is entailed)"
|
| 173 |
+
else:
|
| 174 |
+
counter_model = result.counter_model.assignment
|
| 175 |
+
|
| 176 |
+
out: dict[str, Any] = {
|
| 177 |
+
"example": label,
|
| 178 |
+
"mode": mode,
|
| 179 |
+
"backend": result.backend_name,
|
| 180 |
+
"contradiction_found": result.contradiction_found,
|
| 181 |
+
"counter_model": counter_model,
|
| 182 |
+
"n_variables": result.n_variables,
|
| 183 |
+
"n_clauses": result.n_clauses,
|
| 184 |
+
"n_grover_iterations": result.n_grover_iterations,
|
| 185 |
+
"shots": result.shots,
|
| 186 |
+
"wall_clock_seconds": wall,
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
job_id = result.metadata.get("job_id") if result.metadata else None
|
| 190 |
+
if isinstance(job_id, str) and job_id:
|
| 191 |
+
out["ibm_job_id"] = job_id
|
| 192 |
+
out["ibm_job_url"] = IBM_CONSOLE_BASE + job_id
|
| 193 |
+
|
| 194 |
+
return out
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
def verify_on_simulator(label: str, mode: str) -> dict[str, Any]:
|
| 198 |
+
return _run_verify(label, mode, "pennylane")
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
def verify_on_ibm(label: str, mode: str) -> dict[str, Any]:
|
| 202 |
+
return _run_verify(label, mode, "ibm")
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
_initial_cnf, _initial_universe, _initial_description = _on_example_change(DEFAULT_LABEL)
|
| 206 |
+
|
| 207 |
+
_ibm_status_md = (
|
| 208 |
+
"IBM Quantum credentials detected in Space Secrets. "
|
| 209 |
+
"The hardware button is enabled; runs consume your free-tier "
|
| 210 |
+
"monthly budget (10 minutes shared)."
|
| 211 |
+
if IBM_AVAILABLE
|
| 212 |
+
else (
|
| 213 |
+
"IBM Quantum credentials are not configured. "
|
| 214 |
+
"Add `IBM_QUANTUM_TOKEN` and `IBM_QUANTUM_INSTANCE` to this "
|
| 215 |
+
"Space's Settings -> Variables and secrets to enable hardware runs."
|
| 216 |
+
)
|
| 217 |
+
)
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
with gr.Blocks(title="QVerify") as demo:
|
| 221 |
+
gr.Markdown(
|
| 222 |
+
"# QVerify · quantum-assisted CNF verifier\n\n"
|
| 223 |
+
"This Space exposes the QVerify **verifier** component: a CNF is "
|
| 224 |
+
"fed directly to Grover's search, on either a CPU-side PennyLane "
|
| 225 |
+
"simulator or IBM Quantum's Heron r2 processor.\n\n"
|
| 226 |
+
"Pick a pre-built example, choose a verification mode, then run."
|
| 227 |
+
)
|
| 228 |
+
|
| 229 |
+
with gr.Row():
|
| 230 |
+
with gr.Column(scale=1):
|
| 231 |
+
gr.Markdown("### 1. Pick a CNF")
|
| 232 |
+
example_dd = gr.Dropdown(
|
| 233 |
+
label="Example",
|
| 234 |
+
choices=EXAMPLE_LABELS,
|
| 235 |
+
value=DEFAULT_LABEL,
|
| 236 |
+
)
|
| 237 |
+
description_box = gr.Markdown(_initial_description)
|
| 238 |
+
cnf_box = gr.Textbox(
|
| 239 |
+
label="CNF (read-only)",
|
| 240 |
+
value=_initial_cnf,
|
| 241 |
+
lines=4,
|
| 242 |
+
interactive=False,
|
| 243 |
+
)
|
| 244 |
+
universe_box = gr.Textbox(
|
| 245 |
+
label="Universe of constants",
|
| 246 |
+
value=_initial_universe,
|
| 247 |
+
interactive=False,
|
| 248 |
+
)
|
| 249 |
+
|
| 250 |
+
gr.Markdown("### 2. Choose a mode")
|
| 251 |
+
mode_radio = gr.Radio(
|
| 252 |
+
label="Mode",
|
| 253 |
+
choices=["consistency", "entailment"],
|
| 254 |
+
value="consistency",
|
| 255 |
+
info=(
|
| 256 |
+
"consistency: SAT means the CNF is consistent. "
|
| 257 |
+
"entailment: SAT yields a counter-model showing the "
|
| 258 |
+
"step is not entailed by the premises."
|
| 259 |
+
),
|
| 260 |
+
)
|
| 261 |
+
|
| 262 |
+
gr.Markdown("### 3. Run")
|
| 263 |
+
with gr.Row():
|
| 264 |
+
btn_sim = gr.Button("Verify on PennyLane simulator", variant="primary")
|
| 265 |
+
btn_hw = gr.Button(
|
| 266 |
+
"Verify on IBM Heron r2",
|
| 267 |
+
variant="secondary",
|
| 268 |
+
interactive=IBM_AVAILABLE,
|
| 269 |
+
)
|
| 270 |
+
gr.Markdown(_ibm_status_md)
|
| 271 |
+
|
| 272 |
+
with gr.Column(scale=1):
|
| 273 |
+
gr.Markdown("### Result")
|
| 274 |
+
output = gr.JSON(label="Verification result")
|
| 275 |
+
|
| 276 |
+
example_dd.change(
|
| 277 |
+
_on_example_change,
|
| 278 |
+
inputs=[example_dd],
|
| 279 |
+
outputs=[cnf_box, universe_box, description_box],
|
| 280 |
+
)
|
| 281 |
+
btn_sim.click(
|
| 282 |
+
verify_on_simulator,
|
| 283 |
+
inputs=[example_dd, mode_radio],
|
| 284 |
+
outputs=output,
|
| 285 |
+
)
|
| 286 |
+
btn_hw.click(
|
| 287 |
+
verify_on_ibm,
|
| 288 |
+
inputs=[example_dd, mode_radio],
|
| 289 |
+
outputs=output,
|
| 290 |
+
)
|
| 291 |
+
|
| 292 |
+
gr.Markdown("---")
|
| 293 |
+
gr.Markdown(
|
| 294 |
+
"### About\n\n"
|
| 295 |
+
"**This Space demos the verifier component of QVerify.** A CNF "
|
| 296 |
+
"is grounded over its declared universe, encoded into a Grover "
|
| 297 |
+
"circuit, and run on the chosen backend. The classical "
|
| 298 |
+
"post-check walks the most-frequent measured bitstrings until "
|
| 299 |
+
"one satisfies the CNF.\n\n"
|
| 300 |
+
"**The full pipeline (translator + grounding + verifier) "
|
| 301 |
+
"requires a GPU and runs locally**: it loads Gemma 4 E4B with "
|
| 302 |
+
"grammar-constrained generation to convert natural-language "
|
| 303 |
+
"premises into CNF before verification. CPU Basic Spaces cannot "
|
| 304 |
+
"host the translator, so this Space is verifier-only. See the "
|
| 305 |
+
"[GitHub repository](https://github.com/Quantum-Labor/qverify) "
|
| 306 |
+
"for the end-to-end pipeline.\n\n"
|
| 307 |
+
"**Real quantum hardware runs are routed through your IBM "
|
| 308 |
+
"Quantum free-tier account** (Open Plan, ~10 minutes of quantum "
|
| 309 |
+
"time per month, shared across users). The Space orchestrates "
|
| 310 |
+
"the call; the actual circuit executes on `ibm_fez` (Heron r2, "
|
| 311 |
+
"156 qubits) via IBM Cloud. A previously verified hardware run "
|
| 312 |
+
"is documented [here](https://github.com/Quantum-Labor/qverify"
|
| 313 |
+
"#hardware-run)."
|
| 314 |
+
)
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
if __name__ == "__main__":
|
| 318 |
+
demo.launch()
|
requirements.txt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
qiskit>=2.0
|
| 2 |
+
qiskit-ibm-runtime>=0.40
|
| 3 |
+
pennylane>=0.39
|
| 4 |
+
pennylane-qiskit>=0.39
|
| 5 |
+
numpy<2.1
|
| 6 |
+
pydantic>=2.9
|
| 7 |
+
pydantic-settings>=2.6
|
| 8 |
+
python-dotenv>=1.0
|
| 9 |
+
gradio>=5.0
|