32static constexpr int WIN_W = 1280;
33static constexpr int WIN_H = 720;
36static constexpr int CIR_X = 10;
37static constexpr int CIR_Y = 80;
38static constexpr int CIR_W = 720;
39static constexpr int CIR_H = 500;
42static constexpr int HIS_X = 750;
43static constexpr int HIS_Y = 80;
44static constexpr int HIS_W = 510;
45static constexpr int HIS_H = 500;
48static constexpr int GATE_W = 64;
49static constexpr int GATE_H = 36;
50static constexpr int WIRE_PITCH = 80;
53static constexpr Color COL_BG = {0, 26, 48, 255};
54static constexpr Color COL_PANEL = {0, 30, 56, 255};
55static constexpr Color COL_WIRE = {80, 120, 160, 255};
56static constexpr Color COL_GOLD = {254, 188, 17, 255};
57static constexpr Color COL_TEXT = {232, 238, 244, 255};
58static constexpr Color COL_DIM = {120, 150, 180, 255};
59static constexpr Color COL_ACTIVE = {255, 255, 255, 255};
62static Color gate_color(
int kind,
const std::string& label) {
63 if (kind == 2)
return {180, 60, 180, 255};
64 if (kind == 3)
return { 40, 160, 160, 255};
65 if (kind == 1)
return { 40, 160, 160, 255};
67 if (label ==
"H")
return {254, 188, 17, 255};
68 if (label ==
"X" || label ==
"(+)")
return {210, 60, 60, 255};
69 if (label ==
"Y")
return { 60, 180, 60, 255};
70 if (label ==
"Z")
return { 60, 100, 210, 255};
71 if (label ==
"S" || label ==
"S†")
return {200, 120, 40, 255};
72 if (label ==
"T" || label ==
"T†")
return {200, 120, 40, 255};
73 if (label[0] ==
'R')
return {140, 60, 200, 255};
74 return {100, 140, 180, 255};
80static std::vector<Preset> make_presets() {
81 const real pi = 3.141592653589793;
82 std::vector<Preset> p;
88 p.push_back({
"Bell State |Phi+>", std::move(c)});
93 c.h(0).cx(0, 1).cx(0, 2);
94 p.push_back({
"GHZ State", std::move(c)});
101 .h(0).h(1).x(0).x(1).cz(0,1).x(0).x(1).h(0).h(1);
102 p.push_back({
"Grover Search |11>", std::move(c)});
111 p.push_back({
"Quantum Teleportation", std::move(c)});
117 .h(2).cp(
pi/2, 1, 2).cp(
pi/4, 0, 2)
121 p.push_back({
"QFT\xe2\x82\x83 on |001\xe2\x9f\xa9", std::move(c)});
129static void draw_panel(
int x,
int y,
int w,
int h,
const char* title) {
130 DrawRectangle(x, y, w, h, COL_PANEL);
131 DrawRectangleLinesEx({(float)x,(
float)y,(float)w,(
float)h}, 1, COL_WIRE);
132 if (title && title[0])
133 DrawText(title, x + 8, y + 6, 16, COL_DIM);
136static void draw_gate_box(
int cx,
int cy,
int w,
int h,
137 Color fill,
const char* label,
bool active) {
138 int x = cx - w/2, y = cy - h/2;
139 DrawRectangle(x, y, w, h, fill);
141 DrawRectangleLinesEx({(float)x-1,(
float)y-1,(float)(w+2),(float)(h+2)}, 2, COL_ACTIVE);
143 DrawRectangleLinesEx({(float)x,(
float)y,(float)w,(
float)h}, 1, {0,0,0,80});
145 int font = (int(strlen(label)) > 2) ? 12 : 16;
146 int tw = MeasureText(label, font);
147 DrawText(label, cx - tw/2, cy - font/2, font, COL_TEXT);
152static void draw_circuit(
const std::vector<GateView>& views,
int n_qubits,
153 int current_step,
int active_gate,
154 int origin_x,
int origin_y,
int panel_w) {
155 if (views.empty())
return;
159 for (
const auto& v : views) total_cols = std::max(total_cols, v.col + 1);
162 auto wire_y = [&](
int q) {
return origin_y + 40 + q * WIRE_PITCH; };
164 auto gate_x = [&](
int col) {
return origin_x + 50 + col * GATE_W; };
167 for (
int q = 0; q < n_qubits; ++q) {
169 char label[16]; std::snprintf(label,
sizeof(label),
"q[%d]", q);
170 DrawText(label, origin_x + 4, wy - 8, 16, COL_DIM);
172 int wire_end_x =
gate_x(total_cols);
173 DrawLine(origin_x + 46, wy, std::min(wire_end_x + 10, origin_x + panel_w - 10), wy, COL_WIRE);
177 for (
int i = 0; i < (int)views.size(); ++i) {
178 const auto& v = views[i];
179 bool applied = (i < current_step);
180 bool active = (i == active_gate);
181 Color base = gate_color(v.kind, v.label);
184 base.r = (
unsigned char)(base.r * 0.4f);
185 base.g = (
unsigned char)(base.g * 0.4f);
186 base.b = (
unsigned char)(base.b * 0.4f);
192 draw_gate_box(gx, wire_y(v.q0), GATE_W - 8, GATE_H, base, v.label.c_str(), active);
193 }
else if (v.kind == 1) {
195 int cy_ctrl = wire_y(v.q0);
196 int cy_tgt = wire_y(v.q1);
198 DrawLine(gx, std::min(cy_ctrl, cy_tgt), gx, std::max(cy_ctrl, cy_tgt),
199 applied ? COL_WIRE : COL_DIM);
201 DrawCircle(gx, cy_ctrl, 7, applied ? base : COL_DIM);
202 if (active) DrawCircleLines(gx, cy_ctrl, 9, COL_ACTIVE);
204 const char* tgt_sym = (v.label ==
"CX") ?
"\xe2\x8a\x95" :
205 (v.label ==
"CZ") ?
"Z" :
206 (v.label ==
"CY") ?
"Y" :
"P";
207 draw_gate_box(gx, cy_tgt, GATE_W - 8, GATE_H, base, tgt_sym, active);
208 }
else if (v.kind == 2) {
210 int cy0 = wire_y(v.q0), cy1 = wire_y(v.q1);
211 DrawLine(gx, cy0, gx, cy1, applied ? COL_WIRE : COL_DIM);
212 draw_gate_box(gx, cy0, GATE_W - 8, GATE_H, base,
"\xc3\x97", active);
213 draw_gate_box(gx, cy1, GATE_W - 8, GATE_H, base,
"\xc3\x97", active);
216 int c0 = wire_y(v.q0), c1 = wire_y(v.q1), c2 = wire_y(v.q2);
217 int y_lo = std::min({c0,c1,c2}), y_hi = std::max({c0,c1,c2});
218 DrawLine(gx, y_lo, gx, y_hi, applied ? COL_WIRE : COL_DIM);
219 DrawCircle(gx, c0, 7, applied ? base : COL_DIM);
220 DrawCircle(gx, c1, 7, applied ? base : COL_DIM);
221 draw_gate_box(gx, c2, GATE_W - 8, GATE_H, base,
"\xe2\x8a\x95", active);
223 DrawCircleLines(gx, c0, 9, COL_ACTIVE);
224 DrawCircleLines(gx, c1, 9, COL_ACTIVE);
232 int ox,
int oy,
int panel_w,
int panel_h) {
233 int N = 1 << n_qubits;
237 int ax = ox + 10, aw = panel_w - 20;
238 int ay = oy + 30, ah = panel_h - 80;
240 int bar_w = std::max(4, (aw - N * 2) / N);
241 int spacing = aw / N;
243 for (
int k = 0; k < N; ++k) {
244 float p = (float)probs[k];
245 int bar_h = (int)(p * ah);
246 int bx = ax + k * spacing;
247 int by = ay + ah - bar_h;
250 Color col = (p > 0.4f) ? COL_GOLD : Color{40,160,160,255};
251 if (p < 0.001f) col = {40, 60, 80, 255};
253 DrawRectangle(bx, by, bar_w, bar_h, col);
254 DrawRectangleLinesEx({(float)bx,(
float)(ay),(
float)bar_w,(float)ah}, 1, {60,80,100,120});
257 std::string lbl(n_qubits,
'0');
258 for (
int b = 0; b < n_qubits; ++b)
259 lbl[n_qubits-1-b] = ((k >> b) & 1) ?
'1' :
'0';
260 int font = (n_qubits <= 3) ? 14 : 11;
261 DrawText((
"|" + lbl +
"\xe2\x9f\xa9").c_str(), bx, ay + ah + 4, font, COL_DIM);
265 char pct[8]; std::snprintf(pct,
sizeof(pct),
"%3.0f%%", p*100.f);
266 DrawText(pct, bx, by - 18, 12, COL_TEXT);
274 SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_WINDOW_HIGHDPI);
275 InitWindow(WIN_W, WIN_H,
"Quantum Circuit Demo -- numerics");
278 auto presets = make_presets();
281 bool auto_step =
false;
282 double auto_timer = 0.0;
283 const double AUTO_INTERVAL = 0.55;
285 auto load_preset = [&](
int idx) {
293 while (!WindowShouldClose()) {
295 const Circuit& circ = presets[preset_idx].circuit;
299 if (IsKeyPressed(KEY_RIGHT) || IsKeyPressed(KEY_L))
300 step = std::min(step + 1, n_gates);
301 if (IsKeyPressed(KEY_LEFT) || IsKeyPressed(KEY_H))
302 step = std::max(step - 1, 0);
303 if (IsKeyPressed(KEY_R)) step = 0;
304 if (IsKeyPressed(KEY_SPACE)) auto_step = !auto_step;
306 for (
int i = 0; i < 5; ++i)
307 if (IsKeyPressed(KEY_ONE + i)) load_preset(i);
310 auto_timer += GetFrameTime();
311 if (auto_timer >= AUTO_INTERVAL) {
313 if (step < n_gates) ++step;
314 else auto_step =
false;
320 auto views = circ.
views();
321 int active = (step > 0 && step <= n_gates) ? step - 1 : -1;
325 ClearBackground(COL_BG);
328 DrawText(
"QUANTUM CIRCUIT DEMO", 12, 12, 22, COL_GOLD);
329 DrawText(presets[preset_idx].name.c_str(), 12, 40, 18, COL_TEXT);
333 std::snprintf(step_buf,
sizeof(step_buf),
"STEP %d / %d", step, n_gates);
334 int sw = MeasureText(step_buf, 18);
335 DrawText(step_buf, WIN_W - sw - 12, 40, 18,
336 (step == n_gates) ? COL_GOLD : COL_DIM);
339 if (auto_step) DrawText(
"[AUTO]", WIN_W - 90, 12, 16, {100,210,100,255});
342 draw_panel(CIR_X, CIR_Y, CIR_W, CIR_H,
"Circuit");
343 draw_circuit(views, n_qubits, step, active,
344 CIR_X + 4, CIR_Y + 20, CIR_W - 8);
347 draw_panel(HIS_X, HIS_Y, HIS_W, HIS_H,
"Measurement Probabilities");
348 draw_histogram(sv, n_qubits, HIS_X + 4, HIS_Y + 20, HIS_W - 8, HIS_H - 30);
351 int sy = CIR_Y + CIR_H + 10;
352 DrawRectangle(CIR_X, sy, CIR_W, 80, COL_PANEL);
353 DrawRectangleLinesEx({(float)CIR_X,(
float)sy,(float)CIR_W,80}, 1, COL_WIRE);
357 int best_k = (int)(std::max_element(probs.begin(), probs.end()) - probs.begin());
358 std::string best_lbl(n_qubits,
'0');
359 for (
int b = 0; b < n_qubits; ++b)
360 best_lbl[n_qubits-1-b] = ((best_k >> b) & 1) ?
'1' :
'0';
362 std::snprintf(stat_buf,
sizeof(stat_buf),
363 "Most likely: |%s\xe2\x9f\xa9 (%.1f%%)",
364 best_lbl.c_str(), probs[best_k]*100.0);
365 DrawText(stat_buf, CIR_X + 10, sy + 8, 16, COL_TEXT);
370 std::snprintf(ent_buf,
sizeof(ent_buf),
"S(q[0]) = %.3f ebit%s",
371 S, S > 0.999 ?
" (max entangled)" :
"");
372 DrawText(ent_buf, CIR_X + 10, sy + 30, 16,
373 S > 0.5 ? COL_GOLD : COL_DIM);
378 std::snprintf(nrm_buf,
sizeof(nrm_buf),
"|\u03c8| = %.6f", nrm);
379 DrawText(nrm_buf, CIR_X + 10, sy + 52, 14, COL_DIM);
382 DrawRectangle(HIS_X, sy, HIS_W, 80, COL_PANEL);
383 DrawRectangleLinesEx({(float)HIS_X,(
float)sy,(float)HIS_W,80}, 1, COL_WIRE);
384 DrawText(
"All amplitudes", HIS_X + 10, sy + 8, 14, COL_DIM);
386 int N = 1 << n_qubits;
388 for (
int k = 0; k < N && row < 3; ++k) {
389 if (std::abs(sv[k]) < 0.005)
continue;
390 std::string lbl(n_qubits,
'0');
391 for (
int b = 0; b < n_qubits; ++b)
392 lbl[n_qubits-1-b] = ((k >> b) & 1) ?
'1' :
'0';
394 std::snprintf(amp,
sizeof(amp),
"|%s\xe2\x9f\xa9 %+.3f%+.3fi",
395 lbl.c_str(), (
float)sv[k].real(), (
float)sv[k].imag());
396 DrawText(amp, HIS_X + 10, sy + 24 + row * 18, 14, COL_TEXT);
399 if (row == 3 && N > 4)
400 DrawText(
"...", HIS_X + 10, sy + 62, 14, COL_DIM);
403 int ctrl_y = WIN_H - 38;
404 DrawRectangle(0, ctrl_y, WIN_W, 38, {0, 14, 28, 255});
405 DrawLine(0, ctrl_y, WIN_W, ctrl_y, COL_WIRE);
406 DrawText(
"[<-/->] Step [SPACE] Auto [R] Reset [1-5] Load Circuit",
407 12, ctrl_y + 10, 16, COL_DIM);
410 for (
int i = 0; i < 5; ++i) {
411 char key[4]; std::snprintf(key,
sizeof(key),
"[%d]", i+1);
412 int kx = WIN_W - 300 + i * 56;
413 DrawText(key, kx, ctrl_y + 10, 16,
414 (i == preset_idx) ? COL_GOLD : COL_DIM);
Fluent quantum circuit builder and statevector simulator.
Dense vector with optional GPU storage, templated over scalar type T.
Chainable quantum circuit builder.
std::vector< GateView > views() const
Gate descriptions with layout columns – for renderers.
quantum::Statevector statevector_at(int n) const
Apply first n gates only (0 = bare |0...0>). Useful for stepping through the circuit in a visualiser.
real norm(const Statevector &sv)
L2 norm of the statevector (should be 1 for a valid quantum state)
Gate gate_x()
Pauli-X (NOT)
std::vector< real > probabilities(const Statevector &sv)
Measurement probability for each basis state: p_i = |a_i|^2.
real entanglement_entropy(const Statevector &sv, int n_qubits, int qubit)
Von Neumann entropy of a single qubit's reduced density matrix.
Statevector-based quantum circuit simulator.