Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Quantum Folk Lab is intended for:
## The learning journey

1. **Make a prediction.** Look at eight small, invented tune variants and predict how they belong
together.
together. The console records the split without revealing whether it is right.
2. **Reveal every answer.** The app checks all 256 possible groupings and shows the best answers.
3. **Compare a quantum simulation.** See how a bounded quantum method behaves when the exact result
is already known.
Expand All @@ -61,7 +61,9 @@ Quantum Folk Lab is intended for:
from IBM quantum hardware.
6. **Ask for an explanation.** Choose a learner level and optionally ask GPT-5.6 to explain the
validated evidence.
7. **Keep the record.** Download the governed result for inspection or further discussion in
7. **Check your understanding.** Answer five short questions about exact truth, measurement,
hardware noise and the role of GPT-5.6.
8. **Keep the record.** Download the governed result for inspection or further discussion in
ChatGPT or Codex.

The synthetic teaching example is deliberately small. Checking all 256 answers is simpler and
Expand Down Expand Up @@ -123,8 +125,10 @@ python -m streamlit run apps/learning_console/app.py

### What success looks like

Your browser should open the Quantum Folk Lab Learning Console. Select **Experiments**, begin with
**Start here · Guided experiment**, make a prediction, and press **Reveal all 256 answers**.
Your browser should open the Quantum Folk Lab Learning Console. Judges and first-time learners
should select **Experiments**, begin with **Start here · Guided experiment**, make a prediction,
press **Reveal all 256 answers**, and follow exact truth → simulation → hardware → explanation →
exit check.

Then visit **Real folk data & IBM results** to follow the same exact-first method using committed
real-data and hardware evidence. Use **Foundations** when you want the concepts explained from the
Expand Down
47 changes: 37 additions & 10 deletions apps/learning_console/renderers/compact_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ def render_compact_experiment() -> None:
"folk-tune families, check all sixteen combinations exactly, then compare simulation "
"with governed IBM hardware evidence."
)
st.info(
"You learned the method using a small invented eight-choice problem. This separate "
"registered experiment applies the same exact-first comparison method to a smaller "
"four-choice problem that was executed on IBM quantum hardware."
)
with st.expander("What stays the same—and what changes"):
st.markdown(
"**Stays the same:** define binary choices, calculate exact truth, inspect quantum "
"measurements, and compare their distribution with the reference.\n\n"
"**Changes:** the problem instance, number of variables, execution environment and "
"presence of physical hardware noise. These are not measurements from the synthetic "
"eight-choice circuit."
)
st.caption(
"EXP-010A · compact real-data formulation · four families · two choices each · "
"sixteen valid combinations"
Expand All @@ -56,6 +69,9 @@ def render_compact_experiment() -> None:

optimum = exact["optimum_bitstrings"][0]
st.markdown("## First: what is the exact answer?")
with st.container(border=True):
st.markdown("### ✓ EXACT CLASSICAL REFERENCE")
st.caption("Complete enumeration supplies the answer used to judge every quantum result.")
st.markdown("**Which combination is best when every possibility is checked?**")
st.write(
"Before looking at a simulator or quantum computer, the application checks all 16 "
Expand All @@ -64,13 +80,16 @@ def render_compact_experiment() -> None:
)
left, middle, right = st.columns(3)
left.metric("Exact optimum", optimum)
middle.metric("Mapped R2 state", "01100110")
middle.metric("Equivalent earlier encoding", "01100110")
right.metric("States checked", "16 / 16")
st.success(
f"Exact enumeration is authoritative. The minimum energy is {exact['minimum_energy']:.15f}."
)

st.markdown("## Ideal quantum simulation")
with st.container(border=True):
st.markdown("### ◫ IDEAL OR REGISTERED SIMULATION")
st.caption("Committed simulated measurement evidence; not physical hardware.")
st.markdown("**Does the ideal quantum circuit concentrate on the better choices?**")
st.write(
"R measures improvement over uniform sampling: higher positive values mean the circuit "
Expand All @@ -90,6 +109,14 @@ def render_compact_experiment() -> None:
)

st.markdown("## First IBM hardware validation")
with st.container(border=True):
st.markdown("### ◉ RECORDED IBM HARDWARE")
st.caption("Recorded physical-device evidence, subject to hardware imperfections.")
st.caption(
"Real quantum hardware is physically imperfect: gates and measurements sometimes "
"introduce small errors. That blurring of the ideal result is called noise. Noise is "
"one reason hardware and ideal simulation can differ."
)
st.markdown("**Did the correct answer remain visible on real hardware?**")
st.write(
"One IBM hardware run tested whether the compact real-data result remained visible under "
Expand Down Expand Up @@ -135,26 +162,26 @@ def render_compact_experiment() -> None:
{
"bit": "y0",
"family": "Blackbird",
"0 maps to": "R2 pair 10",
"1 maps to": "R2 pair 01",
"0 maps to": "earlier pair 10",
"1 maps to": "earlier pair 01",
},
{
"bit": "y1",
"family": "Bold Deserter",
"0 maps to": "R2 pair 10",
"1 maps to": "R2 pair 01",
"0 maps to": "earlier pair 10",
"1 maps to": "earlier pair 01",
},
{
"bit": "y2",
"family": "Catherine Tyrrell",
"0 maps to": "R2 pair 10",
"1 maps to": "R2 pair 01",
"0 maps to": "earlier pair 10",
"1 maps to": "earlier pair 01",
},
{
"bit": "y3",
"family": "The Merry Old Woman",
"0 maps to": "R2 pair 10",
"1 maps to": "R2 pair 01",
"0 maps to": "earlier pair 10",
"1 maps to": "earlier pair 01",
},
]
st.dataframe(choices, width="stretch", hide_index=True)
Expand All @@ -176,7 +203,7 @@ def render_compact_experiment() -> None:
)

st.markdown("## Technical evidence")
with st.expander("Encoding equivalence and earlier R2 comparison"):
with st.expander("Encoding equivalence and earlier technical comparison"):
st.markdown((EXPERIMENT_ROOT / "R2-COMPARISON.md").read_text(encoding="utf-8"))
with st.expander("Frozen QAOA report"):
st.markdown((EXPERIMENT_ROOT / "QAOA-REPORT.md").read_text(encoding="utf-8"))
Expand Down
106 changes: 97 additions & 9 deletions apps/learning_console/renderers/directives.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,104 @@


def render_visual(visual_id: str) -> None:
if visual_id == "bit-vs-qubit":
probability = st.slider(
"Chance of measuring 1",
min_value=0,
max_value=100,
value=50,
step=5,
key="foundations-qubit-probability",
help="The state also has phase information, which this probability view cannot show.",
)
st.bar_chart(
{"Measured outcome": ["0", "1"], "Probability": [100 - probability, probability]},
x="Measured outcome",
y="Probability",
horizontal=True,
)
st.caption(
"Takeaway: amplitudes determine measurement probabilities, while phase affects how "
"later operations interfere. A qubit is not simply ‘both values at once’."
)
return
if visual_id == "hadamard-probability-split":
shots = st.select_slider(
"Illustrated shot count",
options=[8, 32, 128, 512],
value=32,
key="foundations-shot-count",
)
zero_count = shots // 2
rows = [
{"Outcome": "0", "Count": zero_count},
{"Outcome": "1", "Count": shots - zero_count},
]
st.bar_chart(rows, x="Outcome", y="Count", horizontal=True)
st.caption(
"Takeaway: each shot produces one bit; repeated shots build an estimated distribution."
)
return
if visual_id == "ideal-vs-noisy":
noise = st.slider(
"Illustrative hardware noise",
min_value=0,
max_value=20,
value=8,
step=2,
key="foundations-noise-level",
help="A teaching illustration, not a model of a particular device.",
)
rows = [
{"Evidence": "Ideal simulator", "Expected answer": 80, "Other answers": 20},
{
"Evidence": "Illustrative hardware",
"Expected answer": 80 - noise,
"Other answers": 20 + noise,
},
]
st.bar_chart(rows, x="Evidence", y=["Expected answer", "Other answers"])
st.caption(
"Takeaway: noise can blur a distribution, so hardware is compared with an exact "
"reference rather than treated as truth by itself."
)
return
if visual_id == "z-phase-reveal":
st.markdown("**Same immediate probabilities:** 50% `0`, 50% `1` ")
st.markdown(
"**Different relative phase:** later gates can make the amplitudes add or cancel."
)
st.caption("Takeaway: probability alone does not describe phase or interference.")
return
if visual_id == "double-h-interference":
st.bar_chart(
{"Measured outcome": ["0", "1"], "Probability": [100, 0]},
x="Measured outcome",
y="Probability",
horizontal=True,
)
st.caption(
"Takeaway: two Hadamard gates can interfere back to the definite starting state."
)
return
if visual_id == "bell-correlation":
st.bar_chart(
{"Joint outcome": ["00", "01", "10", "11"], "Probability": [50, 0, 0, 50]},
x="Joint outcome",
y="Probability",
)
st.caption("Takeaway: the pair is correlated even though either result alone is uncertain.")
return
if visual_id == "x-gate-visual":
st.bar_chart(
{"Input": ["0", "1"], "After X": [1, 0]},
x="Input",
y="After X",
)
st.caption("Takeaway: X swaps the computational-basis states 0 and 1.")
return
captions = {
"bit-vs-qubit": "Classical bit: definite 0 or 1. Qubit: amplitudes until measurement.",
"hadamard-probability-split": "After H on |0⟩, Theory predicts equal P(0) and P(1).",
"z-phase-reveal": (
"A Z gate can change phase without changing computational-basis probabilities."
),
"double-h-interference": "H then H can return to |0⟩ because amplitudes interfere.",
"bell-correlation": "Bell outcomes favour 00 and 11; each bit alone looks random.",
"circuit-thumbnail": "Circuit sketch placeholder — use EXP-001 for full circuit diagrams.",
"x-gate-visual": "X gate swaps |0⟩ and |1⟩.",
"circuit-thumbnail": "Circuit journey: prepare → apply a gate → measure → record one bit.",
}
st.info(captions.get(visual_id, f"Visual: {visual_id}"))

Expand Down
Loading
Loading