diff --git a/qubitverse/visualizer/src/components/QuantumCircuit.jsx b/qubitverse/visualizer/src/components/QuantumCircuit.jsx
index 3198f46..24d2ae0 100644
--- a/qubitverse/visualizer/src/components/QuantumCircuit.jsx
+++ b/qubitverse/visualizer/src/components/QuantumCircuit.jsx
@@ -1,1592 +1,1673 @@
-import React, { useState, useRef, useEffect } from "react";
-import { Stage, Layer, Line, Rect, Text, Group, Circle, Shape } from "react-konva";
-import { MathJax, MathJaxContext } from "better-react-mathjax";
-import SendToBackEnd_Calculate from "./SendToBackEnd";
-import { Button } from "./ui/button";
-import ProbGraph from "./ProbGraph";
-import HilbertSpaceResult from "./HilbertSpaceResult";
-import { DataSet } from "vis-network/standalone";
-import MeasurementChart from "./MeasurementChart";
-
-// =======================
-// CONFIG CONSTANTS
-// =======================
-const qubitSpacing = 50; // vertical spacing between qubit lines
-const gateSize = 45; // width/height for single-qubit gate squares
-const canvasMinX = 50; // left bound for gates on the stage
-const canvasMaxX = window.innerWidth-300 - gateSize; // right bound so gate stays visible
-
-
-// =======================
-// GATE LIST
-// =======================
-const gatesList = [
- "I",
- "X",
- "Y",
- "Z",
- "H",
- "S",
- "T",
- "P",
- "Rx",
- "Ry",
- "Rz",
- "V",
- "V†",
- "CNOT",
- "CZ",
- "SWAP",
- "M"
-];
-
-// =======================
-// GATE TOOLTIP DATA (LaTeX + descriptions)
-// =======================
-const gateTooltips = {
- I: {
- desc: "Identity Gate",
- latex: "$$I = \\begin{pmatrix} 1 & 0 \\\\ 0 & 1 \\end{pmatrix}$$",
- },
- X: {
- desc: "Pauli-X (NOT) Gate",
- latex: "$$X = \\begin{pmatrix}0 & 1\\\\ 1 & 0\\end{pmatrix}$$",
- },
- Y: {
- desc: "Pauli-Y Gate",
- latex: "$$Y = \\begin{pmatrix}0 & -i\\\\ i & 0\\end{pmatrix}$$",
- },
- Z: {
- desc: "Pauli-Z Gate",
- latex: "$$Z = \\begin{pmatrix} 1 & 0 \\\\ 0 & -1 \\end{pmatrix}$$",
- },
- S: {
- desc: "Phase π/2 Shift",
- latex: "$$S = \\begin{pmatrix} 1 & 0 \\\\ 0 & i \\end{pmatrix}$$",
- },
- T: {
- desc: "Phase π/4 Shift",
- latex: "$$T = \\begin{pmatrix} 1 & 0 \\\\ 0 & e^{iπ/4} \\end{pmatrix}$$",
- },
- H: {
- desc: "Hadamard (Superposition) Gate",
- latex:
- "$$H = \\frac{1}{\\sqrt{2}} \\begin{pmatrix}1 & 1\\\\ 1 & -1\\end{pmatrix}$$",
- },
- P: {
- desc: "General Phase Shift Gate",
- latex:
- "$$P(\\theta) = \\begin{pmatrix} 1 & 0 \\\\ 0 & e^{i\\theta} \\end{pmatrix}$$",
- },
- Rx: {
- desc: "Rotation around X-axis",
- latex:
- "$$R_x(\\theta) = \\begin{pmatrix} \\cos(\\theta/2) & -i\\sin(\\theta/2) \\\\ -i\\sin(\\theta/2) & \\cos(\\theta/2) \\end{pmatrix}$$",
- },
- Ry: {
- desc: "Rotation around Y-axis",
- latex:
- "$$R_y(\\theta) = \\begin{pmatrix} \\cos(\\theta/2) & -\\sin(\\theta/2) \\\\ \\sin(\\theta/2) & \\cos(\\theta/2) \\end{pmatrix}$$",
- },
- Rz: {
- desc: "Rotation around Z-axis",
- latex:
- "$$R_z(\\theta) = \\begin{pmatrix} e^{-i\\theta/2} & 0 \\\\ 0 & e^{i\\theta/2} \\end{pmatrix}$$",
- },
- V: {
- desc: "Square-root of NOT Gate (alias for √X)",
- latex:
- "$$V = \\frac{1}{2} \\begin{pmatrix} 1 + i & 1 - i \\\\ 1 - i & 1 + i \\end{pmatrix}$$",
- },
- "V†": {
- desc: "Adjoint of the V gate (alias for (√X)⁻¹)",
- latex:
- "$$V† = \\frac{1}{2} \\begin{pmatrix} 1 - i & 1 + i \\\\ 1 + i & 1 - i \\end{pmatrix}$$",
- },
- CNOT: {
- desc: "Controlled-NOT (Entanglement) Gate",
- latex:
- "$$CNOT = \\begin{pmatrix}1 & 0 & 0 & 0\\\\ 0 & 1 & 0 & 0\\\\ 0 & 0 & 0 & 1\\\\ 0 & 0 & 1 & 0\\end{pmatrix}$$",
- },
- CZ: {
- desc: "Controlled-Z Gate",
- latex:
- "$$CZ = \\begin{pmatrix} 1 & 0 & 0 & 0 \\\\ 0 & 1 & 0 & 0 \\\\ 0 & 0 & 1 & 0 \\\\ 0 & 0 & 0 & -1 \\end{pmatrix}$$",
- },
- SWAP: {
- desc: "SWAP Gate",
- latex:
- "$$SWAP = \\begin{pmatrix} 1 & 0 & 0 & 0 \\\\ 0 & 0 & 1 & 0 \\\\ 0 & 1 & 0 & 0 \\\\ 0 & 0 & 0 & 1 \\end{pmatrix}$$",
- },
- M: {
- desc: "Measure",
- latex:
- "$$\\text{Measure }n^{\\text{th}}\\text{ Qubit}$$"
- }
-};
-
-
-// Helper to clamp a value between min and max
-const clamp = (value, min, max) => Math.max(min, Math.min(value, max));
-
-// =======================
-// SINGLE-QUBIT GATE COMPONENT
-// =======================
-const QuantumGate = ({
- x,
- y,
- text,
- draggable,
- onDragEnd,
- fixedY,
- onRightClick,
- order,
- params = {},
-}) => {
- const isRotationGate = params.theta !== undefined;
- let thetalength = 0;
- if (params.theta != null) {
- thetalength = params.theta.toString().length;
- }
- return (
- ({
- x: clamp(pos.x, canvasMinX, canvasMaxX),
- y: fixedY,
- })
- : undefined
- }
- onDragEnd={onDragEnd}
- onContextMenu={(e) => {
- e.evt.preventDefault();
- onRightClick();
- }}
- >
-
- 1 ? gateSize / 2 - 10 : gateSize / 2 - 5}
- y={gateSize / 2 - 10}
- />
- {isRotationGate && (
-
- )}
- {order !== undefined && (
-
- )}
-
- );
-};
-
-// =======================
-// CNOT GATE COMPONENT
-// =======================
-const CNOTGate = ({ x, control, target, onDragEnd, onRightClick, order }) => {
- const yControl = (control + 1) * qubitSpacing;
- const yTarget = (target + 1) * qubitSpacing;
- return (
- ({
- x: clamp(pos.x, canvasMinX, canvasMaxX),
- y: 0,
- })}
- onDragEnd={onDragEnd}
- onContextMenu={(e) => {
- e.evt.preventDefault();
- onRightClick();
- }}
- >
-
-
-
-
-
- {order !== undefined && (
-
- )}
-
- );
-};
-
-// =======================
-// CZ GATE COMPONENT
-// =======================
-const CZGate = ({
- x,
- control,
- target,
- onDragStart,
- onDragEnd,
- onRightClick,
- order,
-}) => {
- const yControl = (control + 1) * qubitSpacing;
- const yTarget = (target + 1) * qubitSpacing;
- return (
- ({
- x: clamp(pos.x, canvasMinX, canvasMaxX),
- y: 0,
- })}
- onDragStart={onDragStart}
- onDragEnd={onDragEnd}
- onContextMenu={(e) => {
- e.evt.preventDefault();
- onRightClick();
- }}
- >
-
-
-
-
- {order !== undefined && (
-
- )}
-
- );
-};
-
-// =======================
-// SWAP GATE COMPONENT
-// =======================
-const SWAPGate = ({
- x,
- qubit1,
- qubit2,
- onDragStart,
- onDragEnd,
- onRightClick,
- order,
-}) => {
- const y1 = (qubit1 + 1) * qubitSpacing;
- const y2 = (qubit2 + 1) * qubitSpacing;
- const topY = Math.min(y1, y2);
- const bottomY = Math.max(y1, y2);
- return (
- ({
- x: clamp(pos.x, canvasMinX, canvasMaxX),
- y: 0,
- })}
- onDragStart={onDragStart}
- onDragEnd={onDragEnd}
- onContextMenu={(e) => {
- e.evt.preventDefault();
- onRightClick();
- }}
- >
-
- {/* 'X' cross on qubit1 */}
-
-
- {/* 'X' cross on qubit2 */}
-
-
- {order !== undefined && (
-
- )}
-
- );
-};
-
-// =======================
-// Measure Nth COMPONENT
-// =======================
-const MeasureNthComponent = ({
- x,
- y,
- draggable,
- onDragEnd,
- fixedY,
- onRightClick,
- order
-}) => {
- return (
- ({
- x: clamp(pos.x, canvasMinX, canvasMaxX),
- y: fixedY,
- })
- : undefined
- }
- onDragEnd={onDragEnd}
- onContextMenu={(e) => {
- e.evt.preventDefault();
- onRightClick();
- }}
- >
- {/* Rectangle Border */}
-
-
- {/* Semicircle */}
- {
- context.beginPath();
- context.arc(gateSize / 2, gateSize / 2 + 5, gateSize / 2.5, Math.PI, 0, false);
- context.strokeShape(shape);
- }}
- stroke="red"
- strokeWidth={2}
- />
-
- {/* Diagonal Line */}
-
- {/* Small Circle */}
-
- {order !== undefined && (
-
- )}
-
- );
-};
-
-// =======================
-// MAIN QUANTUM CIRCUIT COMPONENT
-// =======================
-const QuantumCircuit = ({ numQubits, setNumQubits }) => {
- // Result or Log Data from the Backend
- const [resultData, setResultData] = useState(null);
- // Probs Data for BarGraph
- const [probData, setProbData] = useState([]);
- // Result Graph Edges
- const [edgesResultGraph, setEdgesResultGraph] = useState(null);
- // Result Graph Vertices
- const [verticesResultGraph, setVerticesResultGraph] = useState(null);
- // Result Measurement
- const [measuredValue, setMeasuredValue] = useState(NaN);
- // Measurement History
- const [measurementHist, setMeasurementHist] = useState([]);
- // Single-qubit gates
- const [gates, setGates] = useState([]); // { x, y, text, params? }
- // CNOT gates
- const [cnotGates, setCnotGates] = useState([]); // { x, control, target }
- // CZ gates
- const [czGates, setCzGates] = useState([]); // { x, control, target }
- // SWAP gates
- const [swapGates, setSwapGates] = useState([]); // { x, qubit1, qubit2 }
- // Measure Nth Qubit
- const [measureNthQubit, setMeasureNthQubit] = useState([]); // {x, y}
- // Error to show when delete Qubit is clicked and numQubits goes less than 1
- const [delQubError, setDelQubError] = useState(false);
-
- // For rotation/phase gates
- const [rotationModalOpen, setRotationModalOpen] = useState(false);
- const [rotationValue, setRotationValue] = useState(45);
- const [rotationX, setRotationX] = useState(0);
- const [rotationY, setRotationY] = useState(0);
- const [rotationType, setRotationType] = useState("P");
-
- // For CNOT selection
- const [cnotModalOpen, setCnotModalOpen] = useState(false);
- const [cnotX, setCnotX] = useState(0);
- const [cnotControl, setCnotControl] = useState(0);
- const [cnotTarget, setCnotTarget] = useState(1);
-
- // For CZ selection
- const [czModalOpen, setCzModalOpen] = useState(false);
- const [czX, setCzX] = useState(0);
- const [czControl, setCzControl] = useState(0);
- const [czTarget, setCzTarget] = useState(1);
-
- // For SWAP selection
- const [swapModalOpen, setSwapModalOpen] = useState(false);
- const [swapX, setSwapX] = useState(0);
- const [swapQubit1, setSwapQubit1] = useState(0);
- const [swapQubit2, setSwapQubit2] = useState(1);
-
- // Tooltip state
- const [tooltip, setTooltip] = useState({
- visible: false,
- x: 0,
- y: 0,
- desc: "",
- latex: "",
- });
- const [isDragging, setIsDragging] = useState(false);
-
- // Tabs state ("Circuit" or "Result")
- const [activeTab, setActiveTab] = useState("Circuit");
-
- const stageRef = useRef(null);
-
- // =======================
- // ORDERING: Combined ordering for all gates on a qubit line
- // =======================
- const combinedGroups = {};
- // Single-qubit
- gates.forEach((g, i) => {
- const qid = Math.round((g.y + gateSize / 2) / qubitSpacing) - 1;
- if (!combinedGroups[qid]) combinedGroups[qid] = [];
- combinedGroups[qid].push({ type: "single", index: i, x: g.x });
- });
- // CNOT
- cnotGates.forEach((g, i) => {
- const qid = g.control;
- if (!combinedGroups[qid]) combinedGroups[qid] = [];
- combinedGroups[qid].push({ type: "cnot", index: i, x: g.x });
- });
- // CZ
- czGates.forEach((g, i) => {
- const qid = g.control;
- if (!combinedGroups[qid]) combinedGroups[qid] = [];
- combinedGroups[qid].push({ type: "cz", index: i, x: g.x });
- });
- // SWAP
- swapGates.forEach((g, i) => {
- const qid = Math.min(g.qubit1, g.qubit2);
- if (!combinedGroups[qid]) combinedGroups[qid] = [];
- combinedGroups[qid].push({ type: "swap", index: i, x: g.x });
- });
- // Measure Nth Qubit
- measureNthQubit.forEach((g, i) => {
- const qid = Math.round((g.y + gateSize / 2) / qubitSpacing) - 1;
- if (!combinedGroups[qid]) combinedGroups[qid] = [];
- combinedGroups[qid].push({ type: "measure", index: i, x: g.x });
- });
-
- const combinedOrders = {
- single: {},
- cnot: {},
- cz: {},
- swap: {},
- measure: {}
- };
- Object.keys(combinedGroups).forEach((qid) => {
- combinedGroups[qid].sort((a, b) => a.x - b.x);
- combinedGroups[qid].forEach((item, orderIndex) => {
- if (item.type === "single") {
- combinedOrders.single[item.index] = orderIndex + 1;
- } else if (item.type === "cnot") {
- combinedOrders.cnot[item.index] = orderIndex + 1;
- } else if (item.type === "cz") {
- combinedOrders.cz[item.index] = orderIndex + 1;
- } else if (item.type === "swap") {
- combinedOrders.swap[item.index] = orderIndex + 1;
- } else if (item.type === "measure") {
- combinedOrders.measure[item.index] = orderIndex + 1;
- }
- });
- });
-
- // =======================
- // QUBIT LINE COMPONENT
- // =======================
- const QubitLine = ({ y, label }) => (
-
-
-
-
- );
-
- // =======================
- // Helper: snap single-qubit gates to a line
- // =======================
- const snapY = (pointerY) => {
- const desiredCenter = Math.round(pointerY / qubitSpacing) * qubitSpacing;
- const clampedCenter = Math.max(
- qubitSpacing,
- Math.min(desiredCenter, numQubits * qubitSpacing)
- );
- return clampedCenter - gateSize / 2;
- };
-
- // =======================
- // DRAG & DROP LOGIC
- // =======================
-
- useEffect(() => {
- if (!stageRef.current) return;
- const container = stageRef.current.container();
-
- const handleDrop = (e) => {
- e.preventDefault();
- const rect = container.getBoundingClientRect();
- const pointerX = e.clientX - rect.left;
- const pointerY = e.clientY - rect.top;
- const gateType = e.dataTransfer.getData("text/plain");
- if (!gateType) return;
-
- if (gateType === "CNOT") {
- setCnotModalOpen(true);
- setCnotX(pointerX);
- } else if (gateType === "CZ") {
- setCzModalOpen(true);
- setCzX(pointerX);
- } else if (gateType === "SWAP") {
- setSwapModalOpen(true);
- setSwapX(pointerX);
- } else if (["P", "Rx", "Ry", "Rz"].includes(gateType)) {
- const snappedY = snapY(pointerY);
- setRotationModalOpen(true);
- setRotationX(pointerX);
- setRotationY(snappedY);
- setRotationType(gateType);
- setRotationValue(45); // default value
- } else if (gateType === "M") {
- const snappedY = snapY(pointerY);
- setMeasureNthQubit((prev) => [
- ...prev,
- { x: pointerX, y: snappedY, },
- ]);
- } else {
- // Single-qubit gate
- const snappedY = snapY(pointerY);
- setGates((prev) => [
- ...prev,
- { x: pointerX, y: snappedY, text: gateType },
- ]);
- }
- };
-
- const handleDragOver = (e) => e.preventDefault();
-
- container.addEventListener("drop", handleDrop);
- container.addEventListener("dragover", handleDragOver);
-
- return () => {
- container.removeEventListener("drop", handleDrop);
- container.removeEventListener("dragover", handleDragOver);
- };
- }, [stageRef.current, numQubits]);
-
- // =======================
- // DRAG END HANDLERS
- // =======================
- const handleGateDragEnd = (e, index) => {
- const { x } = e.target.position();
- setGates((prev) => {
- const newGates = [...prev];
- newGates[index] = {
- ...newGates[index],
- x: clamp(x, canvasMinX, canvasMaxX),
- };
- return newGates;
- });
- setIsDragging(false);
- };
-
- const handleMeasureDragEnd = (e, index) => {
- const { x } = e.target.position();
- setMeasureNthQubit((prev) => {
- const newArr = [...prev];
- newArr[index] = {
- ...newArr[index],
- x: clamp(x, canvasMinX, canvasMaxX),
- };
- return newArr;
- });
- setIsDragging(false);
- }
-
- const handleCnotDragEnd = (e, index) => {
- const { x } = e.target.position();
- setCnotGates((prev) => {
- const newArr = [...prev];
- newArr[index].x = clamp(x, canvasMinX, canvasMaxX);
- return newArr;
- });
- setIsDragging(false);
- };
-
- const handleCzDragEnd = (e, index) => {
- const { x } = e.target.position();
- setCzGates((prev) => {
- const newArr = [...prev];
- newArr[index].x = clamp(x, canvasMinX, canvasMaxX);
- return newArr;
- });
- setIsDragging(false);
- };
-
- const handleSwapDragEnd = (e, index) => {
- const { x } = e.target.position();
- setSwapGates((prev) => {
- const newArr = [...prev];
- newArr[index].x = clamp(x, canvasMinX, canvasMaxX);
- return newArr;
- });
- setIsDragging(false);
- };
-
- // =======================
- // DELETE HANDLERS (Right-click)
- // =======================
- const handleDeleteGate = (index) => {
- setGates((prev) => prev.filter((_, i) => i !== index));
- };
- const handleDeleteCnot = (index) => {
- setCnotGates((prev) => prev.filter((_, i) => i !== index));
- };
- const handleDeleteCz = (index) => {
- setCzGates((prev) => prev.filter((_, i) => i !== index));
- };
- const handleDeleteSwap = (index) => {
- setSwapGates((prev) => prev.filter((_, i) => i !== index));
- };
- const handleDeleteMeasure = (index) => {
- setMeasureNthQubit((prev) => prev.filter((_, i) => i !== index));
- }
-
- // =======================
- // TOOLTIP HANDLERS
- // =======================
- const handleTooltipEnter = (e, gate) => {
- if (isDragging) return;
- const rect = e.target.getBoundingClientRect();
- setTooltip({
- visible: true,
- x: rect.left + 120,
- y: rect.bottom - 100,
- desc: gateTooltips[gate].desc,
- latex: gateTooltips[gate].latex,
- });
- };
-
- const handleTooltipLeave = () => {
- setTooltip({ visible: false, x: 0, y: 0, desc: "", latex: "" });
- };
-
- const handleDragStart = () => {
- setIsDragging(true);
- setTooltip((prev) => ({ ...prev, visible: false }));
- };
-
- // =======================
- // ROTATION/PHASE GATE MODAL HANDLERS
- // =======================
- const validateRotationValue = (value) => (value === 0 ? 1 : value);
- const handleRotationConfirm = () => {
- const validTheta = validateRotationValue(rotationValue);
- setGates((prev) => [
- ...prev,
- {
- x: rotationX,
- y: rotationY,
- text: rotationType,
- params: { theta: validTheta },
- },
- ]);
- setRotationModalOpen(false);
- };
- const handleRotationCancel = () => {
- setRotationModalOpen(false);
- };
- const handleRotationInputChange = (e) => {
- const val = parseFloat(e.target.value) || 1;
- setRotationValue(val === 0 ? 1 : val);
- };
- const getRotationModalContent = () => {
- switch (rotationType) {
- case "Rx":
- return {
- title: "Rotation around X-axis (θ)",
- latex:
- "$$R_x(\\theta) = \\begin{pmatrix} \\cos(\\theta/2) & -i\\sin(\\theta/2) \\\\ -i\\sin(\\theta/2) & \\cos(\\theta/2) \\end{pmatrix}$$",
- };
- case "Ry":
- return {
- title: "Rotation around Y-axis (θ)",
- latex:
- "$$R_y(\\theta) = \\begin{pmatrix} \\cos(\\theta/2) & -\\sin(\\theta/2) \\\\ \\sin(\\theta/2) & \\cos(\\theta/2) \\end{pmatrix}$$",
- };
- case "Rz":
- return {
- title: "Rotation around Z-axis (θ)",
- latex:
- "$$R_z(\\theta) = \\begin{pmatrix} e^{-i\\theta/2} & 0 \\\\ 0 & e^{i\\theta/2} \\end{pmatrix}$$",
- };
- default:
- return {
- title: "Phase Angle (θ)",
- latex:
- "$$P(\\theta) = \\begin{pmatrix} 1 & 0 \\\\ 0 & e^{i\\theta} \\end{pmatrix}$$",
- };
- }
- };
-
- // =======================
- // CNOT MODAL HANDLERS
- // =======================
- const handleCnotConfirm = () => {
- if (cnotControl === cnotTarget) {
- alert("Control and target qubits must be different!");
- return;
- }
- setCnotGates((prev) => [
- ...prev,
- { x: cnotX, control: cnotControl, target: cnotTarget },
- ]);
- setCnotModalOpen(false);
- };
- const handleCnotCancel = () => {
- setCnotModalOpen(false);
- };
-
- // =======================
- // CZ MODAL HANDLERS
- // =======================
- const handleCzConfirm = () => {
- if (czControl === czTarget) {
- alert("Control and target qubits must be different!");
- return;
- }
- setCzGates((prev) => [
- ...prev,
- { x: czX, control: czControl, target: czTarget },
- ]);
- setCzModalOpen(false);
- };
- const handleCzCancel = () => {
- setCzModalOpen(false);
- };
-
- // =======================
- // SWAP MODAL HANDLERS
- // =======================
- const handleSwapConfirm = () => {
- if (swapQubit1 === swapQubit2) {
- alert("SWAP requires two distinct qubits!");
- return;
- }
- setSwapGates((prev) => [
- ...prev,
- { x: swapX, qubit1: swapQubit1, qubit2: swapQubit2 },
- ]);
- setSwapModalOpen(false);
- };
- const handleSwapCancel = () => {
- setSwapModalOpen(false);
- };
-
- // =======================
- // Add or Remove Qubits
- // =======================
- const handleAddQubit = () => {
- let q = numQubits + 1;
- setNumQubits(q);
- setMeasurementHist([]);
- }
-
- const handleDeleteQubit = () => {
- const newNumQubits = numQubits - 1;
-
- if (newNumQubits < 1) {
- setDelQubError(true);
- return;
- }
-
- setGates(prevGates =>
- prevGates.filter(g => {
- const gateQubit = Math.round((g.y + gateSize / 2) / qubitSpacing) - 1;
- return gateQubit < newNumQubits;
- })
- );
-
- setMeasureNthQubit(prevMeasures =>
- prevMeasures.filter(g => {
- const gateQubit = Math.round((g.y + gateSize / 2) / qubitSpacing) - 1;
- return gateQubit < newNumQubits;
- })
- );
-
- setCnotGates(prevCnot =>
- prevCnot.filter(g => g.control < newNumQubits && g.target < newNumQubits)
- );
- setCzGates(prevCz =>
- prevCz.filter(g => g.control < newNumQubits && g.target < newNumQubits)
- );
-
- setSwapGates(prevSwap =>
- prevSwap.filter(g => g.qubit1 < newNumQubits && g.qubit2 < newNumQubits)
- );
-
- setNumQubits(newNumQubits);
-
- setMeasurementHist([]);
- }
-const [Dragging, setDragging] = useState(false);
- const [position, setPosition] = useState({ x: 100, y: 100 });
- const [offset, setOffset] = useState({ x: 0, y: 0 });
- const boxRef = useRef(null);
-
- const startDrag = (e) => {
- setDragging(true);
- setOffset({ x: e.clientX - position.x, y: e.clientY - position.y });
- };
-
- const handleMouseMove = (e) => {
- if (!Dragging) return;
- setPosition({ x: e.clientX - offset.x, y: e.clientY - offset.y });
- };
-
- const handleMouseUp = () => setDragging(false);
-
- useEffect(() => {
- if (Dragging) {
- window.addEventListener("mousemove", handleMouseMove);
- window.addEventListener("mouseup", handleMouseUp);
- }
- return () => {
- window.removeEventListener("mousemove", handleMouseMove);
- window.removeEventListener("mouseup", handleMouseUp);
- };
- }, [Dragging, offset]);
-
- return (
-
-
- {/* Tab Buttons */}
-
- {["Circuit", "Result", "Measurement", "Probability", "Log"].map((tab) => (
-
- ))}
-
-
- {/* Left Menu: single box with gates on top and 3 buttons below */}
-
-
-
-
Quantum Gates
-
- {/* Gates box */}
-
- {gatesList.map((gate, index) => {
- // Hide multi-qubit gates if only 1 qubit
- if (numQubits < 2 && ["CNOT", "CZ", "SWAP"].includes(gate)) {
- return null;
- }
-
- const isActive = activeTab === "Circuit";
- const defaultBackground = isActive ? "white" : "#eee";
-
- return (
-
{
- if (isActive) {
- e.dataTransfer.setData("text/plain", gate);
- }
- }}
- onMouseEnter={(e) => {
- if (isActive) handleTooltipEnter(e, gate);
- }}
- onMouseMove={(e) => {
- if (isActive) {
- e.currentTarget.style.background = "oklch(80.9% 0.105 251.813)";
- }
- }}
- onMouseLeave={(e) => {
- e.currentTarget.style.background = defaultBackground;
- if (isActive) handleTooltipLeave(e);
- }}
- >
- {gate}
-
- );
- })}
-
-
- {/* Buttons under gates */}
-
-
-
- {/* Right Content: depends on active tab */}
-
- {/* TOOLTIP */}
- {!isDragging && tooltip.visible && (
-
-
- {tooltip.desc}
-
-
- {tooltip.latex}
-
-
- )}
- {activeTab === "Circuit" ? (
- <>
- {/* STAGE: QUBIT LINES & GATES */}
-
-
- {Array.from({ length: numQubits }).map((_, i) => (
-
- ))}
- {/* Render single-qubit gates */}
- {gates.map((g, i) => (
- handleGateDragEnd(e, i)}
- onRightClick={() => handleDeleteGate(i)}
- order={combinedOrders.single[i]}
- />
- ))}
- {/* Render CNOT gates */}
- {cnotGates.map((g, i) => (
- handleCnotDragEnd(e, i)}
- onRightClick={() => handleDeleteCnot(i)}
- order={combinedOrders.cnot[i]}
- />
- ))}
- {/* Render CZ gates */}
- {czGates.map((g, i) => (
- handleCzDragEnd(e, i)}
- onRightClick={() => handleDeleteCz(i)}
- order={combinedOrders.cz[i]}
- />
- ))}
- {/* Render SWAP gates */}
- {swapGates.map((g, i) => (
- handleSwapDragEnd(e, i)}
- onRightClick={() => handleDeleteSwap(i)}
- order={combinedOrders.swap[i]}
- />
- ))}
- {/* Render Measure Nth Component */}
- {measureNthQubit.map((g, i) => (
- handleMeasureDragEnd(e, i)}
- onRightClick={() => handleDeleteMeasure(i)}
- onDragStart={handleDragStart}
- order={combinedOrders.measure[i]}
- />
- ))}
-
-
- >
- ) : activeTab === "Result" ? (
-
- ) : activeTab === "Measurement" ? (
-
- ) : activeTab === "Probability" ? (
- // an interactive graph
-
- ) : activeTab === "Log" ? (
-
- ) : (null)}
-
-
-
- {/* Error Modal */}
- {delQubError && (
- { setDelQubError(false); }}
- style={{
- position: "fixed",
- top: 0,
- left: 0,
- width: "100vw",
- height: "100vh",
- background: "rgba(0,0,0,0.5)",
- display: "flex",
- alignItems: "center",
- justifyContent: "center",
- userSelect: "none"
- }}
- >
-
e.stopPropagation()}
- style={{
- background: "white",
- padding: "20px",
- borderRadius: "10px",
- textAlign: "center",
- minWidth: "300px",
- }}
- >
-
- Number of Qubits must be greater than or equal to 1.
-
-
- {"$$\\text{numQubits}\\geq1$$"}
-
-
-
-
- )
- }
-
- {/* ROTATION/PHASE GATE MODAL */}
- {
- rotationModalOpen && (
-
-
e.stopPropagation()}
- style={{
- background: "white",
- padding: "20px",
- borderRadius: "10px",
- textAlign: "center",
- minWidth: "300px",
- }}
- >
-
{getRotationModalContent().title}
-
- {getRotationModalContent().latex}
-
-
-
-
-
-
-
-
- Note: Angle must be between 1° and 360°
-
-
-
-
-
-
- )
- }
-
- {/* CNOT MODAL */}
- {
- cnotModalOpen && (
-
-
e.stopPropagation()}
- style={{
- background: "white",
- padding: "20px",
- borderRadius: "10px",
- textAlign: "center",
- minWidth: "300px",
- }}
- >
-
Select Control and Target Qubit
-
-
-
-
-
-
-
-
-
-
-
-
- )
- }
-
- {/* CZ MODAL */}
- {
- czModalOpen && (
-
-
e.stopPropagation()}
- style={{
- background: "white",
- padding: "20px",
- borderRadius: "10px",
- textAlign: "center",
- minWidth: "300px",
- }}
- >
-
Select Control and Target Qubit (CZ)
-
-
-
-
-
-
-
-
-
-
-
-
- )
- }
-
- {/* SWAP MODAL */}
- {
- swapModalOpen && (
-
-
e.stopPropagation()}
- style={{
- background: "white",
- padding: "20px",
- borderRadius: "10px",
- textAlign: "center",
- minWidth: "300px",
- }}
- >
-
Select Qubits to SWAP
-
-
-
-
-
-
-
-
-
-
-
-
- )
- }
-
- );
-};
-
-export default QuantumCircuit;
+import React, { useState, useRef, useEffect } from "react";
+import { Stage, Layer, Line, Rect, Text, Group, Circle, Shape } from "react-konva";
+import { MathJax, MathJaxContext } from "better-react-mathjax";
+import SendToBackEnd_Calculate from "./SendToBackEnd";
+import { Button } from "./ui/button";
+import ProbGraph from "./ProbGraph";
+import HilbertSpaceResult from "./HilbertSpaceResult";
+import { DataSet } from "vis-network/standalone";
+import MeasurementChart from "./MeasurementChart";
+import { evaluate } from "mathjs";
+
+
+// =======================
+// CONFIG CONSTANTS
+// =======================
+const qubitSpacing = 50; // vertical spacing between qubit lines
+const gateSize = 45; // width/height for single-qubit gate squares
+const canvasMinX = 50; // left bound for gates on the stage
+const canvasMaxX = window.innerWidth-300 - gateSize; // right bound so gate stays visible
+
+
+// =======================
+// GATE LIST
+// =======================
+const gatesList = [
+ "I",
+ "X",
+ "Y",
+ "Z",
+ "H",
+ "S",
+ "T",
+ "P",
+ "Rx",
+ "Ry",
+ "Rz",
+ "V",
+ "V†",
+ "CNOT",
+ "CZ",
+ "SWAP",
+ "M"
+];
+
+// =======================
+// GATE TOOLTIP DATA (LaTeX + descriptions)
+// =======================
+const gateTooltips = {
+ I: {
+ desc: "Identity Gate",
+ latex: "$$I = \\begin{pmatrix} 1 & 0 \\\\ 0 & 1 \\end{pmatrix}$$",
+ },
+ X: {
+ desc: "Pauli-X (NOT) Gate",
+ latex: "$$X = \\begin{pmatrix}0 & 1\\\\ 1 & 0\\end{pmatrix}$$",
+ },
+ Y: {
+ desc: "Pauli-Y Gate",
+ latex: "$$Y = \\begin{pmatrix}0 & -i\\\\ i & 0\\end{pmatrix}$$",
+ },
+ Z: {
+ desc: "Pauli-Z Gate",
+ latex: "$$Z = \\begin{pmatrix} 1 & 0 \\\\ 0 & -1 \\end{pmatrix}$$",
+ },
+ S: {
+ desc: "Phase π/2 Shift",
+ latex: "$$S = \\begin{pmatrix} 1 & 0 \\\\ 0 & i \\end{pmatrix}$$",
+ },
+ T: {
+ desc: "Phase π/4 Shift",
+ latex: "$$T = \\begin{pmatrix} 1 & 0 \\\\ 0 & e^{iπ/4} \\end{pmatrix}$$",
+ },
+ H: {
+ desc: "Hadamard (Superposition) Gate",
+ latex:
+ "$$H = \\frac{1}{\\sqrt{2}} \\begin{pmatrix}1 & 1\\\\ 1 & -1\\end{pmatrix}$$",
+ },
+ P: {
+ desc: "General Phase Shift Gate",
+ latex:
+ "$$P(\\theta) = \\begin{pmatrix} 1 & 0 \\\\ 0 & e^{i\\theta} \\end{pmatrix}$$",
+ },
+ Rx: {
+ desc: "Rotation around X-axis",
+ latex:
+ "$$R_x(\\theta) = \\begin{pmatrix} \\cos(\\theta/2) & -i\\sin(\\theta/2) \\\\ -i\\sin(\\theta/2) & \\cos(\\theta/2) \\end{pmatrix}$$",
+ },
+ Ry: {
+ desc: "Rotation around Y-axis",
+ latex:
+ "$$R_y(\\theta) = \\begin{pmatrix} \\cos(\\theta/2) & -\\sin(\\theta/2) \\\\ \\sin(\\theta/2) & \\cos(\\theta/2) \\end{pmatrix}$$",
+ },
+ Rz: {
+ desc: "Rotation around Z-axis",
+ latex:
+ "$$R_z(\\theta) = \\begin{pmatrix} e^{-i\\theta/2} & 0 \\\\ 0 & e^{i\\theta/2} \\end{pmatrix}$$",
+ },
+ V: {
+ desc: "Square-root of NOT Gate (alias for √X)",
+ latex:
+ "$$V = \\frac{1}{2} \\begin{pmatrix} 1 + i & 1 - i \\\\ 1 - i & 1 + i \\end{pmatrix}$$",
+ },
+ "V†": {
+ desc: "Adjoint of the V gate (alias for (√X)⁻¹)",
+ latex:
+ "$$V† = \\frac{1}{2} \\begin{pmatrix} 1 - i & 1 + i \\\\ 1 + i & 1 - i \\end{pmatrix}$$",
+ },
+ CNOT: {
+ desc: "Controlled-NOT (Entanglement) Gate",
+ latex:
+ "$$CNOT = \\begin{pmatrix}1 & 0 & 0 & 0\\\\ 0 & 1 & 0 & 0\\\\ 0 & 0 & 0 & 1\\\\ 0 & 0 & 1 & 0\\end{pmatrix}$$",
+ },
+ CZ: {
+ desc: "Controlled-Z Gate",
+ latex:
+ "$$CZ = \\begin{pmatrix} 1 & 0 & 0 & 0 \\\\ 0 & 1 & 0 & 0 \\\\ 0 & 0 & 1 & 0 \\\\ 0 & 0 & 0 & -1 \\end{pmatrix}$$",
+ },
+ SWAP: {
+ desc: "SWAP Gate",
+ latex:
+ "$$SWAP = \\begin{pmatrix} 1 & 0 & 0 & 0 \\\\ 0 & 0 & 1 & 0 \\\\ 0 & 1 & 0 & 0 \\\\ 0 & 0 & 0 & 1 \\end{pmatrix}$$",
+ },
+ M: {
+ desc: "Measure",
+ latex:
+ "$$\\text{Measure }n^{\\text{th}}\\text{ Qubit}$$"
+ }
+};
+
+
+// Helper to clamp a value between min and max
+const clamp = (value, min, max) => Math.max(min, Math.min(value, max));
+
+// =======================
+// SINGLE-QUBIT GATE COMPONENT
+// =======================
+const QuantumGate = ({
+ x,
+ y,
+ text,
+ draggable,
+ onDragEnd,
+ fixedY,
+ onRightClick,
+ order,
+ params = {},
+}) => {
+ const isRotationGate = params.theta !== undefined;
+ let thetalength = 0;
+ if (params.theta != null) {
+ thetalength = params.theta.toString().length;
+ }
+ return (
+ ({
+ x: clamp(pos.x, canvasMinX, canvasMaxX),
+ y: fixedY,
+ })
+ : undefined
+ }
+ onDragEnd={onDragEnd}
+ onContextMenu={(e) => {
+ e.evt.preventDefault();
+ onRightClick();
+ }}
+ >
+
+ 1 ? gateSize / 2 - 10 : gateSize / 2 - 5}
+ y={gateSize / 2 - 10}
+ />
+ {isRotationGate && (
+
+ )}
+ {order !== undefined && (
+
+ )}
+
+ );
+};
+
+
+
+
+// =======================
+// CZ GATE COMPONENT
+// =======================
+const CZGate = ({
+ x,
+ control,
+ target,
+ onDragStart,
+ onDragEnd,
+ onRightClick,
+ order,
+}) => {
+ const yControl = (control + 1) * qubitSpacing;
+ const yTarget = (target + 1) * qubitSpacing;
+ return (
+ ({
+ x: clamp(pos.x, canvasMinX, canvasMaxX),
+ y: 0,
+ })}
+ onDragStart={onDragStart}
+ onDragEnd={onDragEnd}
+ onContextMenu={(e) => {
+ e.evt.preventDefault();
+ onRightClick();
+ }}
+ >
+
+
+
+
+ {order !== undefined && (
+
+ )}
+
+ );
+};
+
+// =======================
+// SWAP GATE COMPONENT
+// =======================
+const SWAPGate = ({
+ x,
+ qubit1,
+ qubit2,
+ onDragStart,
+ onDragEnd,
+ onRightClick,
+ order,
+}) => {
+ const y1 = (qubit1 + 1) * qubitSpacing;
+ const y2 = (qubit2 + 1) * qubitSpacing;
+ const topY = Math.min(y1, y2);
+ const bottomY = Math.max(y1, y2);
+ return (
+ ({
+ x: clamp(pos.x, canvasMinX, canvasMaxX),
+ y: 0,
+ })}
+ onDragStart={onDragStart}
+ onDragEnd={onDragEnd}
+ onContextMenu={(e) => {
+ e.evt.preventDefault();
+ onRightClick();
+ }}
+ >
+
+ {/* 'X' cross on qubit1 */}
+
+
+ {/* 'X' cross on qubit2 */}
+
+
+ {order !== undefined && (
+
+ )}
+
+ );
+};
+
+// =======================
+// Measure Nth COMPONENT
+// =======================
+const MeasureNthComponent = ({
+ x,
+ y,
+ draggable,
+ onDragEnd,
+ fixedY,
+ onRightClick,
+ order
+}) => {
+ return (
+ ({
+ x: clamp(pos.x, canvasMinX, canvasMaxX),
+ y: fixedY,
+ })
+ : undefined
+ }
+ onDragEnd={onDragEnd}
+ onContextMenu={(e) => {
+ e.evt.preventDefault();
+ onRightClick();
+ }}
+ >
+ {/* Rectangle Border */}
+
+
+ {/* Semicircle */}
+ {
+ context.beginPath();
+ context.arc(gateSize / 2, gateSize / 2 + 5, gateSize / 2.5, Math.PI, 0, false);
+ context.strokeShape(shape);
+ }}
+ stroke="red"
+ strokeWidth={2}
+ />
+
+ {/* Diagonal Line */}
+
+ {/* Small Circle */}
+
+ {order !== undefined && (
+
+ )}
+
+ );
+};
+
+// =======================
+// MAIN QUANTUM CIRCUIT COMPONENT
+// =======================
+const QuantumCircuit = ({ numQubits, setNumQubits }) => {
+ // Result or Log Data from the Backend
+ const [resultData, setResultData] = useState(null);
+ // Probs Data for BarGraph
+ const [probData, setProbData] = useState([]);
+ // Result Graph Edges
+ const [edgesResultGraph, setEdgesResultGraph] = useState(null);
+ // Result Graph Vertices
+ const [verticesResultGraph, setVerticesResultGraph] = useState(null);
+ // Result Measurement
+ const [measuredValue, setMeasuredValue] = useState(NaN);
+ // Measurement History
+ const [measurementHist, setMeasurementHist] = useState([]);
+ // Single-qubit gates
+ const [gates, setGates] = useState([]); // { x, y, text, params? }
+ // CNOT gates
+ const [cnotGates, setCnotGates] = useState([]); // { x, control, target }
+ // CZ gates
+ const [czGates, setCzGates] = useState([]); // { x, control, target }
+ // SWAP gates
+ const [swapGates, setSwapGates] = useState([]); // { x, qubit1, qubit2 }
+ // Measure Nth Qubit
+ const [measureNthQubit, setMeasureNthQubit] = useState([]); // {x, y}
+ // Error to show when delete Qubit is clicked and numQubits goes less than 1
+ const [delQubError, setDelQubError] = useState(false);
+
+ // For rotation/phase gates
+ const [rotationModalOpen, setRotationModalOpen] = useState(false);
+ const [rotationValue, setRotationValue] = useState(45);
+ const [rotationX, setRotationX] = useState(0);
+ const [rotationY, setRotationY] = useState(0);
+ const [rotationType, setRotationType] = useState("P");
+
+ // For CNOT selection
+ const [cnotModalOpen, setCnotModalOpen] = useState(false);
+ const [cnotX, setCnotX] = useState(0);
+ const [cnotControl, setCnotControl] = useState(0);
+ const [cnotTarget, setCnotTarget] = useState(1);
+
+ // For CZ selection
+ const [czModalOpen, setCzModalOpen] = useState(false);
+ const [czX, setCzX] = useState(0);
+ const [czControl, setCzControl] = useState(0);
+ const [czTarget, setCzTarget] = useState(1);
+
+ // For SWAP selection
+ const [swapModalOpen, setSwapModalOpen] = useState(false);
+ const [swapX, setSwapX] = useState(0);
+ const [swapQubit1, setSwapQubit1] = useState(0);
+ const [swapQubit2, setSwapQubit2] = useState(1);
+
+ // Tooltip state
+ const [tooltip, setTooltip] = useState({
+ visible: false,
+ x: 0,
+ y: 0,
+ desc: "",
+ latex: "",
+ });
+ const [isDragging, setIsDragging] = useState(false);
+
+ // Tabs state ("Circuit" or "Result")
+ const [activeTab, setActiveTab] = useState("Circuit");
+
+ const stageRef = useRef(null);
+
+ const [circuit, setCircuit] = useState([]);
+
+ const createGate = (type, id, order) => {
+ switch (type) {
+ case "Rx":
+ case "Ry":
+ case "Rz":
+ return { id, type, order, params: { theta: 0 } };
+ case "U3":
+ return { id, type, order, params: { theta: 0, phi: 0, lambda: 0 } };
+ default:
+ return { id, type, order };
+ }
+ };
+
+//only for testing
+ const addTestGates = () => {
+ setCircuit([
+ createGate("Rx", "rx1", 1),
+ createGate("Ry", "ry1", 2),
+ createGate("Rz", "rz1", 3),
+ createGate("U3", "u31", 4),
+ ]);
+ };
+
+
+
+ const handleParamChange = (gateId, paramName, value) => {
+ let radianValue = value;
+
+ try {
+ // Convert user input into radians
+ radianValue = evaluate(value, { pi: Math.PI });
+ } catch (err) {
+ console.error("Invalid angle expression:", value);
+ alert("Invalid angle expression! Please enter something like pi/2 or 1.57");
+ return;
+ }
+
+ // Store radians
+ setCircuit((prev) =>
+ prev.map((g) =>
+ g.id === gateId
+ ? { ...g, params: { ...g.params, [paramName]: evaluate(value) } }
+ : g
+ )
+ );
+ }
+
+ // =======================
+ // ORDERING: Combined ordering for all gates on a qubit line
+ // =======================
+ const combinedGroups = {};
+ // Single-qubit
+ gates.forEach((g, i) => {
+ const qid = Math.round((g.y + gateSize / 2) / qubitSpacing) - 1;
+ if (!combinedGroups[qid]) combinedGroups[qid] = [];
+ combinedGroups[qid].push({ type: "single", index: i, x: g.x });
+ });
+ // CNOT
+ cnotGates.forEach((g, i) => {
+ const qid = g.control;
+ if (!combinedGroups[qid]) combinedGroups[qid] = [];
+ combinedGroups[qid].push({ type: "cnot", index: i, x: g.x });
+ });
+ // CZ
+ czGates.forEach((g, i) => {
+ const qid = g.control;
+ if (!combinedGroups[qid]) combinedGroups[qid] = [];
+ combinedGroups[qid].push({ type: "cz", index: i, x: g.x });
+ });
+ // SWAP
+ swapGates.forEach((g, i) => {
+ const qid = Math.min(g.qubit1, g.qubit2);
+ if (!combinedGroups[qid]) combinedGroups[qid] = [];
+ combinedGroups[qid].push({ type: "swap", index: i, x: g.x });
+ });
+ // Measure Nth Qubit
+ measureNthQubit.forEach((g, i) => {
+ const qid = Math.round((g.y + gateSize / 2) / qubitSpacing) - 1;
+ if (!combinedGroups[qid]) combinedGroups[qid] = [];
+ combinedGroups[qid].push({ type: "measure", index: i, x: g.x });
+ });
+
+ const combinedOrders = {
+ single: {},
+ cnot: {},
+ cz: {},
+ swap: {},
+ measure: {}
+ };
+ Object.keys(combinedGroups).forEach((qid) => {
+ combinedGroups[qid].sort((a, b) => a.x - b.x);
+ combinedGroups[qid].forEach((item, orderIndex) => {
+ if (item.type === "single") {
+ combinedOrders.single[item.index] = orderIndex + 1;
+ } else if (item.type === "cnot") {
+ combinedOrders.cnot[item.index] = orderIndex + 1;
+ } else if (item.type === "cz") {
+ combinedOrders.cz[item.index] = orderIndex + 1;
+ } else if (item.type === "swap") {
+ combinedOrders.swap[item.index] = orderIndex + 1;
+ } else if (item.type === "measure") {
+ combinedOrders.measure[item.index] = orderIndex + 1;
+ }
+ });
+ });
+
+ // =======================
+ // QUBIT LINE COMPONENT
+ // =======================
+ const QubitLine = ({ y, label }) => (
+
+
+
+
+ );
+
+ // =======================
+ // Helper: snap single-qubit gates to a line
+ // =======================
+ const snapY = (pointerY) => {
+ const desiredCenter = Math.round(pointerY / qubitSpacing) * qubitSpacing;
+ const clampedCenter = Math.max(
+ qubitSpacing,
+ Math.min(desiredCenter, numQubits * qubitSpacing)
+ );
+ return clampedCenter - gateSize / 2;
+ };
+
+ // =======================
+ // DRAG & DROP LOGIC
+ // =======================
+
+ useEffect(() => {
+ if (!stageRef.current) return;
+ const container = stageRef.current.container();
+
+ const handleDrop = (e) => {
+ e.preventDefault();
+ const rect = container.getBoundingClientRect();
+ const pointerX = e.clientX - rect.left;
+ const pointerY = e.clientY - rect.top;
+ const gateType = e.dataTransfer.getData("text/plain");
+ if (!gateType) return;
+
+ if (gateType === "CNOT") {
+ setCnotModalOpen(true);
+ setCnotX(pointerX);
+ } else if (gateType === "CZ") {
+ setCzModalOpen(true);
+ setCzX(pointerX);
+ } else if (gateType === "SWAP") {
+ setSwapModalOpen(true);
+ setSwapX(pointerX);
+ } else if (["P", "Rx", "Ry", "Rz"].includes(gateType)) {
+ const snappedY = snapY(pointerY);
+ setRotationModalOpen(true);
+ setRotationX(pointerX);
+ setRotationY(snappedY);
+ setRotationType(gateType);
+ setRotationValue(45); // default value
+ } else if (gateType === "M") {
+ const snappedY = snapY(pointerY);
+ setMeasureNthQubit((prev) => [
+ ...prev,
+ { x: pointerX, y: snappedY, },
+ ]);
+ } else {
+ // Single-qubit gate
+ const snappedY = snapY(pointerY);
+ setGates((prev) => [
+ ...prev,
+ { x: pointerX, y: snappedY, text: gateType },
+ ]);
+ }
+ };
+
+ const handleDragOver = (e) => e.preventDefault();
+
+ container.addEventListener("drop", handleDrop);
+ container.addEventListener("dragover", handleDragOver);
+
+ return () => {
+ container.removeEventListener("drop", handleDrop);
+ container.removeEventListener("dragover", handleDragOver);
+ };
+ }, [stageRef.current, numQubits]);
+
+ // =======================
+ // DRAG END HANDLERS
+ // =======================
+ const handleGateDragEnd = (e, index) => {
+ const { x } = e.target.position();
+ setGates((prev) => {
+ const newGates = [...prev];
+ newGates[index] = {
+ ...newGates[index],
+ x: clamp(x, canvasMinX, canvasMaxX),
+ };
+ return newGates;
+ });
+ setIsDragging(false);
+ };
+
+ const handleMeasureDragEnd = (e, index) => {
+ const { x } = e.target.position();
+ setMeasureNthQubit((prev) => {
+ const newArr = [...prev];
+ newArr[index] = {
+ ...newArr[index],
+ x: clamp(x, canvasMinX, canvasMaxX),
+ };
+ return newArr;
+ });
+ setIsDragging(false);
+ }
+
+ const handleCnotDragEnd = (e, index) => {
+ const { x } = e.target.position();
+ setCnotGates((prev) => {
+ const newArr = [...prev];
+ newArr[index].x = clamp(x, canvasMinX, canvasMaxX);
+ return newArr;
+ });
+ setIsDragging(false);
+ };
+
+ const handleCzDragEnd = (e, index) => {
+ const { x } = e.target.position();
+ setCzGates((prev) => {
+ const newArr = [...prev];
+ newArr[index].x = clamp(x, canvasMinX, canvasMaxX);
+ return newArr;
+ });
+ setIsDragging(false);
+ };
+
+ const handleSwapDragEnd = (e, index) => {
+ const { x } = e.target.position();
+ setSwapGates((prev) => {
+ const newArr = [...prev];
+ newArr[index].x = clamp(x, canvasMinX, canvasMaxX);
+ return newArr;
+ });
+ setIsDragging(false);
+ };
+
+ // =======================
+ // DELETE HANDLERS (Right-click)
+ // =======================
+ const handleDeleteGate = (index) => {
+ setGates((prev) => prev.filter((_, i) => i !== index));
+ };
+ const handleDeleteCnot = (index) => {
+ setCnotGates((prev) => prev.filter((_, i) => i !== index));
+ };
+ const handleDeleteCz = (index) => {
+ setCzGates((prev) => prev.filter((_, i) => i !== index));
+ };
+ const handleDeleteSwap = (index) => {
+ setSwapGates((prev) => prev.filter((_, i) => i !== index));
+ };
+ const handleDeleteMeasure = (index) => {
+ setMeasureNthQubit((prev) => prev.filter((_, i) => i !== index));
+ }
+
+ // =======================
+ // TOOLTIP HANDLERS
+ // =======================
+ const handleTooltipEnter = (e, gate) => {
+ if (isDragging) return;
+ const rect = e.target.getBoundingClientRect();
+ setTooltip({
+ visible: true,
+ x: rect.left + 120,
+ y: rect.bottom - 100,
+ desc: gateTooltips[gate].desc,
+ latex: gateTooltips[gate].latex,
+ });
+ };
+
+ const handleTooltipLeave = () => {
+ setTooltip({ visible: false, x: 0, y: 0, desc: "", latex: "" });
+ };
+
+ const handleDragStart = () => {
+ setIsDragging(true);
+ setTooltip((prev) => ({ ...prev, visible: false }));
+ };
+
+ // =======================
+ // ROTATION/PHASE GATE MODAL HANDLERS
+ // =======================
+ const validateRotationValue = (value) => (value === 0 ? 1 : value);
+ const handleRotationConfirm = () => {
+ const validTheta = validateRotationValue(rotationValue);
+ setGates((prev) => [
+ ...prev,
+ {
+ x: rotationX,
+ y: rotationY,
+ text: rotationType,
+ params: { theta: validTheta },
+ },
+ ]);
+ setRotationModalOpen(false);
+ };
+ const handleRotationCancel = () => {
+ setRotationModalOpen(false);
+ };
+ const handleRotationInputChange = (e) => {
+ const val = parseFloat(e.target.value) || 1;
+ setRotationValue(val === 0 ? 1 : val);
+ };
+ const getRotationModalContent = () => {
+ switch (rotationType) {
+ case "Rx":
+ return {
+ title: "Rotation around X-axis (θ)",
+ latex:
+ "$$R_x(\\theta) = \\begin{pmatrix} \\cos(\\theta/2) & -i\\sin(\\theta/2) \\\\ -i\\sin(\\theta/2) & \\cos(\\theta/2) \\end{pmatrix}$$",
+ };
+ case "Ry":
+ return {
+ title: "Rotation around Y-axis (θ)",
+ latex:
+ "$$R_y(\\theta) = \\begin{pmatrix} \\cos(\\theta/2) & -\\sin(\\theta/2) \\\\ \\sin(\\theta/2) & \\cos(\\theta/2) \\end{pmatrix}$$",
+ };
+ case "Rz":
+ return {
+ title: "Rotation around Z-axis (θ)",
+ latex:
+ "$$R_z(\\theta) = \\begin{pmatrix} e^{-i\\theta/2} & 0 \\\\ 0 & e^{i\\theta/2} \\end{pmatrix}$$",
+ };
+ default:
+ return {
+ title: "Phase Angle (θ)",
+ latex:
+ "$$P(\\theta) = \\begin{pmatrix} 1 & 0 \\\\ 0 & e^{i\\theta} \\end{pmatrix}$$",
+ };
+ }
+ };
+
+ // =======================
+ // CNOT MODAL HANDLERS
+ // =======================
+ const handleCnotConfirm = () => {
+ if (cnotControl === cnotTarget) {
+ alert("Control and target qubits must be different!");
+ return;
+ }
+ setCnotGates((prev) => [
+ ...prev,
+ { x: cnotX, control: cnotControl, target: cnotTarget },
+ ]);
+ setCnotModalOpen(false);
+ };
+ const handleCnotCancel = () => {
+ setCnotModalOpen(false);
+ };
+
+ // =======================
+ // CZ MODAL HANDLERS
+ // =======================
+ const handleCzConfirm = () => {
+ if (czControl === czTarget) {
+ alert("Control and target qubits must be different!");
+ return;
+ }
+ setCzGates((prev) => [
+ ...prev,
+ { x: czX, control: czControl, target: czTarget },
+ ]);
+ setCzModalOpen(false);
+ };
+ const handleCzCancel = () => {
+ setCzModalOpen(false);
+ };
+
+ // =======================
+ // SWAP MODAL HANDLERS
+ // =======================
+ const handleSwapConfirm = () => {
+ if (swapQubit1 === swapQubit2) {
+ alert("SWAP requires two distinct qubits!");
+ return;
+ }
+ setSwapGates((prev) => [
+ ...prev,
+ { x: swapX, qubit1: swapQubit1, qubit2: swapQubit2 },
+ ]);
+ setSwapModalOpen(false);
+ };
+ const handleSwapCancel = () => {
+ setSwapModalOpen(false);
+ };
+
+ // =======================
+ // Add or Remove Qubits
+ // =======================
+ const handleAddQubit = () => {
+ let q = numQubits + 1;
+ setNumQubits(q);
+ setMeasurementHist([]);
+ }
+
+ const handleDeleteQubit = () => {
+ const newNumQubits = numQubits - 1;
+
+ if (newNumQubits < 1) {
+ setDelQubError(true);
+ return;
+ }
+
+ setGates(prevGates =>
+ prevGates.filter(g => {
+ const gateQubit = Math.round((g.y + gateSize / 2) / qubitSpacing) - 1;
+ return gateQubit < newNumQubits;
+ })
+ );
+
+ setMeasureNthQubit(prevMeasures =>
+ prevMeasures.filter(g => {
+ const gateQubit = Math.round((g.y + gateSize / 2) / qubitSpacing) - 1;
+ return gateQubit < newNumQubits;
+ })
+ );
+
+ setCnotGates(prevCnot =>
+ prevCnot.filter(g => g.control < newNumQubits && g.target < newNumQubits)
+ );
+ setCzGates(prevCz =>
+ prevCz.filter(g => g.control < newNumQubits && g.target < newNumQubits)
+ );
+
+ setSwapGates(prevSwap =>
+ prevSwap.filter(g => g.qubit1 < newNumQubits && g.qubit2 < newNumQubits)
+ );
+
+ setNumQubits(newNumQubits);
+
+ setMeasurementHist([]);
+ }
+const [Dragging, setDragging] = useState(false);
+ const [position, setPosition] = useState({ x: 100, y: 100 });
+ const [offset, setOffset] = useState({ x: 0, y: 0 });
+ const boxRef = useRef(null);
+
+ const startDrag = (e) => {
+ setDragging(true);
+ setOffset({ x: e.clientX - position.x, y: e.clientY - position.y });
+ };
+
+ const handleMouseMove = (e) => {
+ if (!Dragging) return;
+ setPosition({ x: e.clientX - offset.x, y: e.clientY - offset.y });
+ };
+
+ const handleMouseUp = () => setDragging(false);
+
+ useEffect(() => {
+ if (Dragging) {
+ window.addEventListener("mousemove", handleMouseMove);
+ window.addEventListener("mouseup", handleMouseUp);
+ }
+ return () => {
+ window.removeEventListener("mousemove", handleMouseMove);
+ window.removeEventListener("mouseup", handleMouseUp);
+ };
+ }, [Dragging, offset]);
+
+ return (
+
+
+ {/* Tab Buttons */}
+
+ {["Circuit", "Result", "Measurement", "Probability", "Log"].map((tab) => (
+
+ ))}
+
+
+ {/* Left Menu: single box with gates on top and 3 buttons below */}
+
+
+
+
Quantum Gates
+
+ {/* Gates box */}
+
+ {gatesList.map((gate, index) => {
+ // Hide multi-qubit gates if only 1 qubit
+ if (numQubits < 2 && ["CNOT", "CZ", "SWAP"].includes(gate)) {
+ return null;
+ }
+
+ const isActive = activeTab === "Circuit";
+ const defaultBackground = isActive ? "white" : "#eee";
+
+ return (
+ <>
+
+ {circuit.map((gate) => (
+ console.log("Right click")}
+ onDragEnd={() => console.log("Drag end")}
+ />
+ ))}
+
+ {/* ====== Parameters ====== */}
+
+
{
+ if (isActive) {
+ e.dataTransfer.setData("text/plain", gate);
+ }
+ }}
+ onMouseEnter={(e) => {
+ if (isActive) handleTooltipEnter(e, gate);
+ }}
+ onMouseMove={(e) => {
+ if (isActive) {
+ e.currentTarget.style.background = "oklch(80.9% 0.105 251.813)";
+ }
+ }}
+ onMouseLeave={(e) => {
+ e.currentTarget.style.background = defaultBackground;
+ if (isActive) handleTooltipLeave(e);
+ }}
+ >
+ {gate}
+
+ >
+ );
+ })}
+
+
+ {/* Buttons under gates */}
+
+
+
+ {/* Right Content: depends on active tab */}
+
+ {/* TOOLTIP */}
+ {!isDragging && tooltip.visible && (
+
+
+ {tooltip.desc}
+
+
+ {tooltip.latex}
+
+
+ )}
+ {activeTab === "Circuit" ? (
+ <>
+ {/* STAGE: QUBIT LINES & GATES */}
+
+
+ {Array.from({ length: numQubits }).map((_, i) => (
+
+ ))}
+ {/* Render single-qubit gates */}
+ {gates.map((g, i) => (
+ handleGateDragEnd(e, i)}
+ onRightClick={() => handleDeleteGate(i)}
+ order={combinedOrders.single[i]}
+ />
+ ))}
+ {/* Render CNOT gates */}
+ {cnotGates.map((g, i) => (
+ handleCnotDragEnd(e, i)}
+ onRightClick={() => handleDeleteCnot(i)}
+ order={combinedOrders.cnot[i]}
+ />
+ ))}
+ {/* Render CZ gates */}
+ {czGates.map((g, i) => (
+ handleCzDragEnd(e, i)}
+ onRightClick={() => handleDeleteCz(i)}
+ order={combinedOrders.cz[i]}
+ />
+ ))}
+ {/* Render SWAP gates */}
+ {swapGates.map((g, i) => (
+ handleSwapDragEnd(e, i)}
+ onRightClick={() => handleDeleteSwap(i)}
+ order={combinedOrders.swap[i]}
+ />
+ ))}
+ {/* Render Measure Nth Component */}
+ {measureNthQubit.map((g, i) => (
+ handleMeasureDragEnd(e, i)}
+ onRightClick={() => handleDeleteMeasure(i)}
+ onDragStart={handleDragStart}
+ order={combinedOrders.measure[i]}
+ />
+ ))}
+
+
+ >
+ ) : activeTab === "Result" ? (
+
+ ) : activeTab === "Measurement" ? (
+
+ ) : activeTab === "Probability" ? (
+ // an interactive graph
+
+ ) : activeTab === "Log" ? (
+
+ ) : (null)}
+
+
+
+ {/* Error Modal */}
+ {delQubError && (
+ { setDelQubError(false); }}
+ style={{
+ position: "fixed",
+ top: 0,
+ left: 0,
+ width: "100vw",
+ height: "100vh",
+ background: "rgba(0,0,0,0.5)",
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "center",
+ userSelect: "none"
+ }}
+ >
+
e.stopPropagation()}
+ style={{
+ background: "white",
+ padding: "20px",
+ borderRadius: "10px",
+ textAlign: "center",
+ minWidth: "300px",
+ }}
+ >
+
+ Number of Qubits must be greater than or equal to 1.
+
+
+ {"$$\\text{numQubits}\\geq1$$"}
+
+
+
+
+ )
+ }
+
+ {/* ROTATION/PHASE GATE MODAL */}
+ {
+ rotationModalOpen && (
+
+
e.stopPropagation()}
+ style={{
+ background: "white",
+ padding: "20px",
+ borderRadius: "10px",
+ textAlign: "center",
+ minWidth: "300px",
+ }}
+ >
+
{getRotationModalContent().title}
+
+ {getRotationModalContent().latex}
+
+
+
+
+
+
+
+
+ Note: Angle must be between 1° and 360°
+
+
+
+
+
+
+ )
+ }
+
+ {/* CNOT MODAL */}
+ {
+ cnotModalOpen && (
+
+
e.stopPropagation()}
+ style={{
+ background: "white",
+ padding: "20px",
+ borderRadius: "10px",
+ textAlign: "center",
+ minWidth: "300px",
+ }}
+ >
+
Select Control and Target Qubit
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+
+ {/* CZ MODAL */}
+ {
+ czModalOpen && (
+
+
e.stopPropagation()}
+ style={{
+ background: "white",
+ padding: "20px",
+ borderRadius: "10px",
+ textAlign: "center",
+ minWidth: "300px",
+ }}
+ >
+
Select Control and Target Qubit (CZ)
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+
+ {/* SWAP MODAL */}
+ {
+ swapModalOpen && (
+
+
e.stopPropagation()}
+ style={{
+ background: "white",
+ padding: "20px",
+ borderRadius: "10px",
+ textAlign: "center",
+ minWidth: "300px",
+ }}
+ >
+
Select Qubits to SWAP
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+
+ );
+};
+
+export default QuantumCircuit;
diff --git a/qubitverse/visualizer/src/components/SendToBackEnd.jsx b/qubitverse/visualizer/src/components/SendToBackEnd.jsx
index 97e1b03..8721c40 100644
--- a/qubitverse/visualizer/src/components/SendToBackEnd.jsx
+++ b/qubitverse/visualizer/src/components/SendToBackEnd.jsx
@@ -1,183 +1,196 @@
-import { Button } from "@/components/ui/button";
-import ParseResultData from "./ParseResultData";
-
-// This function extracts circuit data from the gates state
-function extractCircuitData(gates, cnotGates, czGates, swapGates, measureNthQ, nQ) {
- // Process single-qubit gates
- const processedGates = gates.map((gate) => {
- // Calculate which qubit this gate is on based on y position
- const qubitIndex = Math.round((gate.y + 20) / 50) - 1; // 20 is half of gateSize, 50 is qubitSpacing
- return {
- type: "single",
- gateType: (gate.text === "V†" ? "adjV" : gate.text), // X, Y, H, etc.
- qubit: qubitIndex,
- theta: Object.hasOwn(gate, "params") === false ? -1 : gate.params.theta,
- position: gate.x,
- };
- });
-
- // Process CNOT gates
- const processedCnotGates = cnotGates.map((gate) => {
- return {
- type: "cnot",
- control: gate.control,
- target: gate.target,
- position: gate.x,
- };
- });
-
- // Process CZ gates
- const processedCZGates = czGates.map((gate) => {
- return {
- type: "cz",
- control: gate.control,
- target: gate.target,
- position: gate.x,
- };
- });
-
- // Process SWAP gates
- const processedSwapGates = swapGates.map((gate) => {
- return {
- type: "swap",
- qubitA: gate.qubit1,
- qubitB: gate.qubit2,
- position: gate.x,
- };
- });
-
- // Process Measurement
- const measureNthQubits = measureNthQ.map((gate) => {
- const qubitIndex = Math.round((gate.y + 20) / 50) - 1; // 20 is half of gateSize, 50 is qubitSpacing
- return {
- type: "measurenth",
- qubit: qubitIndex,
- position: gate.x,
- }
- });
-
- // Combine all gates and sort by position (x coordinate)
- const allGates = [...processedGates, ...processedCnotGates, ...processedCZGates, ...processedSwapGates, ...measureNthQubits].sort(
- (a, b) => a.position - b.position
- );
-
- // Create the final circuit data object
- return {
- numQubits: nQ,
- gates: allGates,
- };
-}
-
-function quantum_encode(cktData, feature) {
- let s = feature + "n:" + cktData.numQubits + "\n";
- for (let i = 0; i < cktData.gates.length; i++) {
- for (const key in cktData.gates[i]) {
- if (Object.hasOwn(cktData.gates[i], key)) {
- s += key + ":" + cktData.gates[i][key] + "\n";
- }
- }
- s += "@\n";
- }
- return s;
-}
-
-export function SendToBackEnd_Calculate({ gates, cnotGates, czGates, swapGates, measureNthQ, numQubits, setLog, setProbData, setEdgesResultGraph, setVerticesResultGraph, setMeasuredValue, setMeasurementHist, funcAddQubits, funcRemoveQubits }) {
- const request_backend = async (dat) => {
- try {
- const response = await fetch('http://localhost:9080/api/endpoint', {
- method: 'POST',
- headers: {
- 'Content-Type': 'text/plain',
- },
- body: dat
- });
- return await response.text();
- } catch (error) {
- console.error('Error:', error);
- return null;
- }
- };
-
- const sendCalculate = () => {
- request_backend(
- quantum_encode(extractCircuitData(gates, cnotGates, czGates, swapGates, measureNthQ, numQubits), "0")
- ).then(responseText => { setLog(responseText); ParseResultData({ data: responseText, setProbData, setEdgesResultGraph, setVerticesResultGraph, setMeasuredValue, setMeasurementHist }) });
-
-
- };
-
- const sendProbability = () => {
- request_backend(
- quantum_encode(extractCircuitData(gates, cnotGates, czGates, swapGates, measureNthQ, numQubits), "1")
- ).then(responseText => { setLog(responseText); ParseResultData({ data: responseText, setProbData, setEdgesResultGraph, setVerticesResultGraph, setMeasuredValue, setMeasurementHist }) });
- };
-
- const sendMeasure = () => {
- request_backend(
- quantum_encode(extractCircuitData(gates, cnotGates, czGates, swapGates, measureNthQ, numQubits), "2")
- ).then(responseText => { setLog(responseText); ParseResultData({ data: responseText, setProbData, setEdgesResultGraph, setVerticesResultGraph, setMeasuredValue, setMeasurementHist }) });
- };
-
- return (
-
-
-
-
-
-
-
- );
-};
-
+import { Button } from "@/components/ui/button";
+import ParseResultData from "./ParseResultData";
+
+// This function extracts circuit data from the gates state
+function extractCircuitData(gates, cnotGates, czGates, swapGates, measureNthQ, nQ) {
+ // Process single-qubit gates
+ const processedGates = gates.map((gate) => {
+ // Calculate which qubit this gate is on based on y position
+ const qubitIndex = Math.round((gate.y + 20) / 50) - 1; // 20 is half of gateSize, 50 is qubitSpacing
+ return {
+ type: "single",
+ gateType: (gate.text === "V†" ? "adjV" : gate.text), // X, Y, H, etc.
+ qubit: qubitIndex,
+ params: {
+ theta: gate.params.theta ?? 0,
+ phi: gate.params.phi ?? 0,
+ lambda: gate.params.lambda ?? 0,
+ },
+ position: gate.x,
+ };
+ });
+
+ // Process CNOT gates
+ const processedCnotGates = cnotGates.map((gate) => {
+ return {
+ type: "cnot",
+ control: gate.control,
+ target: gate.target,
+ position: gate.x,
+ };
+ });
+
+ // Process CZ gates
+ const processedCZGates = czGates.map((gate) => {
+ return {
+ type: "cz",
+ control: gate.control,
+ target: gate.target,
+ position: gate.x,
+ };
+ });
+
+ // Process SWAP gates
+ const processedSwapGates = swapGates.map((gate) => {
+ return {
+ type: "swap",
+ qubitA: gate.qubit1,
+ qubitB: gate.qubit2,
+ position: gate.x,
+ };
+ });
+
+ // Process Measurement
+ const measureNthQubits = measureNthQ.map((gate) => {
+ const qubitIndex = Math.round((gate.y + 20) / 50) - 1; // 20 is half of gateSize, 50 is qubitSpacing
+ return {
+ type: "measurenth",
+ qubit: qubitIndex,
+ position: gate.x,
+ }
+ });
+
+ // Combine all gates and sort by position (x coordinate)
+ const allGates = [...processedGates, ...processedCnotGates, ...processedCZGates, ...processedSwapGates, ...measureNthQubits].sort(
+ (a, b) => a.position - b.position
+ );
+
+ // Create the final circuit data object
+ return {
+ numQubits: nQ,
+ gates: allGates,
+ };
+}
+
+function quantum_encode(cktData, feature) {
+ let s = "";
+ for (let i = 0; i < cktData.gates.length; i++) {
+ const gate = cktData.gates[i];
+ for (const key in gate) {
+ if (Object.hasOwn(gate, key)) {
+ if (key === "params") {
+ for (const p in gate.params) {
+ if (Object.hasOwn(gate.params, p)) {
+ s += p + ":" + gate.params[p] + "\n";
+ }
+ }
+ } else {
+ s += key + ":" + gate[key] + "\n";
+ }
+ }
+ }
+ s += "@\n";
+ }
+ return s;
+}
+
+export function SendToBackEnd_Calculate({ gates, cnotGates, czGates, swapGates, measureNthQ, numQubits, setLog, setProbData, setEdgesResultGraph, setVerticesResultGraph, setMeasuredValue, setMeasurementHist, funcAddQubits, funcRemoveQubits }) {
+ const request_backend = async (dat) => {
+ try {
+ const response = await fetch('http://localhost:9080/api/endpoint', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'text/plain',
+ },
+ body: dat
+ });
+ return await response.text();
+ } catch (error) {
+ console.error('Error:', error);
+ return null;
+ }
+ };
+
+ const sendCalculate = () => {
+ request_backend(
+ quantum_encode(extractCircuitData(gates, cnotGates, czGates, swapGates, measureNthQ, numQubits), "0")
+ ).then(responseText => { setLog(responseText); ParseResultData({ data: responseText, setProbData, setEdgesResultGraph, setVerticesResultGraph, setMeasuredValue, setMeasurementHist }) });
+
+
+ };
+
+ const sendProbability = () => {
+ request_backend(
+ quantum_encode(extractCircuitData(gates, cnotGates, czGates, swapGates, measureNthQ, numQubits), "1")
+ ).then(responseText => { setLog(responseText); ParseResultData({ data: responseText, setProbData, setEdgesResultGraph, setVerticesResultGraph, setMeasuredValue, setMeasurementHist }) });
+ };
+
+ const sendMeasure = () => {
+ request_backend(
+ quantum_encode(extractCircuitData(gates, cnotGates, czGates, swapGates, measureNthQ, numQubits), "2")
+ ).then(responseText => { setLog(responseText); ParseResultData({ data: responseText, setProbData, setEdgesResultGraph, setVerticesResultGraph, setMeasuredValue, setMeasurementHist }) });
+ };
+
+ return (
+
+
+
+
+
+
+
+ );
+};
+
export default SendToBackEnd_Calculate;
\ No newline at end of file