<commit_before>import Config from "src/Config.js"
import Complex from "src/math/Complex.js"
import Gate from "src/circuit/Gate.js"
import GateFactory from "src/ui/GateFactory.js"
import MathPainter from "src/ui/MathPainter.js"
import Matrix from "src/math/Matrix.js"
import Point from "src/math/Point.js"
import Rect from "src/math/Rect.js"
import Seq from "src/base/Seq.js"

const τ = Math.PI * 2;

let Gates = {};
export default Gates;

/**
 * Gates that have special behavior requiring custom code / logic to handle.
 */
Gates.Special = {
    Control: new Gate(
        "•",
        Matrix.identity(2),
        "Control",
        "Conditions on a qubit being ON.\nGates in the same column will only apply to states meeting the condition.",
        args => {
            if (args.isInToolbox || args.isHighlighted) {
                GateFactory.DEFAULT_DRAWER(args);
            }
            args.painter.fillCircle(args.rect.center(), 5, "black");
        }),

    AntiControl: new Gate(
        "◦",
        Matrix.identity(2),
        "Anti-Control",
        "Conditions on a qubit being OFF.\nGates in the same column will only apply to states meeting the condition.",
        args => {
            if (args.isInToolbox || args.isHighlighted) {
                GateFactory.DEFAULT_DRAWER(args);
            }
            let p = args.rect.center();
            args.painter.fillCircle(p, 5);
            args.painter.strokeCircle(p, 5);
        }),

    Measurement: new Gate(
        "Measure",
        Matrix.identity(2),
        "Measurement Gate",
        "Measures a wire in the computational basis, along the Z axis.",
        args => {
            let backColor = Config.GATE_FILL_COLOR;
            if (args.isHighlighted) {
                backColor = Config.HIGHLIGHTED_GATE_FILL_COLOR;
            }
            args.painter.fillRect(args.rect, backColor);
            args.painter.strokeRect(args.rect);

            let r = args.rect.w*0.4;
            let {x, y} = args.rect.center();
            y += r*0.6;
            let a = -τ/6;
            let [c, s] = [Math.cos(a)*r*1.5, Math.sin(a)*r*1.5];
            let [p, q] = [x + c, y + s];

            // Draw the dial and shaft.
            args.painter.trace(trace => {
                trace.ctx.arc(x, y, r, τ/2, τ);
                trace.line(x, y, p, q);
            }).thenStroke('black');
            // Draw the indicator head.
            args.painter.trace(trace => trace.arrowHead(p, q, r*0.3, a, τ/4)).thenFill('black');
        }),

    SwapHalf: new Gate(
        "Swap",
        Matrix.square(1, 0, 0, 0,
            0, 0, 1, 0,
            0, 1, 0, 0,
            0, 0, 0, 1),
        "Swap Gate [Half]",
        "Swaps the values of two qubits.\nPlace two swap gate halves in the same column to form a swap gate.",
        args => {
            if (args.isInToolbox || args.isHighlighted) {
                GateFactory.DEFAULT_DRAWER(args);
                return;
            }

            // A swap gate half is shown as a small X (joined by a line to the other half; that's handled elsewhere).
            let swapRect = Rect.centeredSquareWithRadius(args.rect.center(), args.rect.w / 6);
            args.painter.strokeLine(swapRect.topLeft(), swapRect.bottomRight());
            args.painter.strokeLine(swapRect.topRight(), swapRect.bottomLeft());
        })
};

/**
 * Gates that display information without affecting the state.
 * (In reality these would require multiple runs of the circuit to do tomography.)
 */
Gates.Displays = {
    ChanceDisplay: new Gate(
        "Chance",
        Matrix.identity(2),
        "Probability Display",
        "Shows the chance that measuring a wire would return ON.\nUse controls to see conditional probabilities.",
        args => {
            if (args.positionInCircuit === null || args.isHighlighted) {
                GateFactory.MAKE_HIGHLIGHTED_DRAWER(Config.DISPLAY_GATE_IN_TOOLBOX_FILL_COLOR)(args);
                return;
            }

            let {row, col} = args.positionInCircuit;
            MathPainter.paintProbabilityBox(
                args.painter,
                args.stats.controlledWireProbabilityJustAfter(row, col),
                args.rect);
        }),

    BlochSphereDisplay: new Gate(
        "Bloch",
        Matrix.identity(2),
        "Bloch Sphere Display",
        "Shows a wire's local state as a point on the Bloch Sphere.\nUse controls to see conditional states.",
        args => {
            if (args.positionInCircuit === null || args.isHighlighted) {
                GateFactory.MAKE_HIGHLIGHTED_DRAWER(Config.DISPLAY_GATE_IN_TOOLBOX_FILL_COLOR)(args);
                return;
            }

            let {row, col} = args.positionInCircuit;
            let ρ = args.stats.qubitDensityMatrix(row, col);
            MathPainter.paintBlochSphere(args.painter, ρ, args.rect);
        }),

    DensityMatrixDisplay: new Gate(
        "Density",
        Matrix.identity(2),
        "Density Matrix Display",
        "Shows a wire's local state as a density matrix.\nUse controls to see conditional states.",
        args => {
            if (args.positionInCircuit === null || args.isHighlighted) {
                GateFactory.MAKE_HIGHLIGHTED_DRAWER(Config.DISPLAY_GATE_IN_TOOLBOX_FILL_COLOR)(args);
                return;
            }

            let {row, col} = args.positionInCircuit;
            let ρ = args.stats.qubitDensityMatrix(row, col);
            MathPainter.paintDensityMatrix(args.painter, ρ, args.rect);
        })
};

/**
 * Gates that correspond to 180 degree rotations around the Bloch sphere, so they're their own inverses.
 */
Gates.HalfTurns = {
    X: new Gate(
        "X",
        Matrix.PAULI_X,
        "Pauli X Gate",
        "Toggles between ON and OFF.\nAlso known as the Not gate.",
        args => {
            // The X gate is drawn as a crossed circle when it has controls.

            let hasSingleWireControl =
                args.positionInCircuit !== null &&
                args.stats.circuitDefinition.colHasSingleWireControl(args.positionInCircuit.col);
            let hasDoubleWireControl =
                args.positionInCircuit !== null &&
                args.stats.circuitDefinition.colHasDoubleWireControl(args.positionInCircuit.col);
            if ((!hasSingleWireControl && !hasDoubleWireControl) || args.isHighlighted) {
                GateFactory.DEFAULT_DRAWER(args);
                return;
            }<commit_msg>Showing transparent overlay when dragging display gates<commit_after>import Config from "src/Config.js"
import Complex from "src/math/Complex.js"
import Gate from "src/circuit/Gate.js"
import GateFactory from "src/ui/GateFactory.js"
import MathPainter from "src/ui/MathPainter.js"
import Matrix from "src/math/Matrix.js"
import Point from "src/math/Point.js"
import Rect from "src/math/Rect.js"
import Seq from "src/base/Seq.js"

const τ = Math.PI * 2;

let Gates = {};
export default Gates;

/**
 * Gates that have special behavior requiring custom code / logic to handle.
 */
Gates.Special = {
    Control: new Gate(
        "•",
        Matrix.identity(2),
        "Control",
        "Conditions on a qubit being ON.\nGates in the same column will only apply to states meeting the condition.",
        args => {
            if (args.isInToolbox || args.isHighlighted) {
                GateFactory.DEFAULT_DRAWER(args);
            }
            args.painter.fillCircle(args.rect.center(), 5, "black");
        }),

    AntiControl: new Gate(
        "◦",
        Matrix.identity(2),
        "Anti-Control",
        "Conditions on a qubit being OFF.\nGates in the same column will only apply to states meeting the condition.",
        args => {
            if (args.isInToolbox || args.isHighlighted) {
                GateFactory.DEFAULT_DRAWER(args);
            }
            let p = args.rect.center();
            args.painter.fillCircle(p, 5);
            args.painter.strokeCircle(p, 5);
        }),

    Measurement: new Gate(
        "Measure",
        Matrix.identity(2),
        "Measurement Gate",
        "Measures a wire in the computational basis, along the Z axis.",
        args => {
            let backColor = Config.GATE_FILL_COLOR;
            if (args.isHighlighted) {
                backColor = Config.HIGHLIGHTED_GATE_FILL_COLOR;
            }
            args.painter.fillRect(args.rect, backColor);
            args.painter.strokeRect(args.rect);

            let r = args.rect.w*0.4;
            let {x, y} = args.rect.center();
            y += r*0.6;
            let a = -τ/6;
            let [c, s] = [Math.cos(a)*r*1.5, Math.sin(a)*r*1.5];
            let [p, q] = [x + c, y + s];

            // Draw the dial and shaft.
            args.painter.trace(trace => {
                trace.ctx.arc(x, y, r, τ/2, τ);
                trace.line(x, y, p, q);
            }).thenStroke('black');
            // Draw the indicator head.
            args.painter.trace(trace => trace.arrowHead(p, q, r*0.3, a, τ/4)).thenFill('black');
        }),

    SwapHalf: new Gate(
        "Swap",
        Matrix.square(1, 0, 0, 0,
            0, 0, 1, 0,
            0, 1, 0, 0,
            0, 0, 0, 1),
        "Swap Gate [Half]",
        "Swaps the values of two qubits.\nPlace two swap gate halves in the same column to form a swap gate.",
        args => {
            if (args.isInToolbox || args.isHighlighted) {
                GateFactory.DEFAULT_DRAWER(args);
                return;
            }

            // A swap gate half is shown as a small X (joined by a line to the other half; that's handled elsewhere).
            let swapRect = Rect.centeredSquareWithRadius(args.rect.center(), args.rect.w / 6);
            args.painter.strokeLine(swapRect.topLeft(), swapRect.bottomRight());
            args.painter.strokeLine(swapRect.topRight(), swapRect.bottomLeft());
        })
};

/**
 * Gates that display information without affecting the state.
 * (In reality these would require multiple runs of the circuit to do tomography.)
 */
Gates.Displays = {
    ChanceDisplay: new Gate(
        "Chance",
        Matrix.identity(2),
        "Probability Display",
        "Shows the chance that measuring a wire would return ON.\nUse controls to see conditional probabilities.",
        args => {
            let showState = args.positionInCircuit !== null;
            let showText = !showState || args.isHighlighted;

            if (showState) {
                let {row, col} = args.positionInCircuit;
                MathPainter.paintProbabilityBox(
                    args.painter,
                    args.stats.controlledWireProbabilityJustAfter(row, col),
                    args.rect);
            }

            if (showText) {
                if (showState) {
                    args.painter.ctx.globalAlpha = 0.8;
                }
                GateFactory.MAKE_HIGHLIGHTED_DRAWER(Config.DISPLAY_GATE_IN_TOOLBOX_FILL_COLOR)(args);
                if (showState) {
                    args.painter.ctx.globalAlpha = 1.0;
                }
            }
        }),

    BlochSphereDisplay: new Gate(
        "Bloch",
        Matrix.identity(2),
        "Bloch Sphere Display",
        "Shows a wire's local state as a point on the Bloch Sphere.\nUse controls to see conditional states.",
        args => {
            let showState = args.positionInCircuit !== null;
            let showText = !showState || args.isHighlighted;

            if (showState) {
                let {row, col} = args.positionInCircuit;
                let ρ = args.stats.qubitDensityMatrix(row, col);
                MathPainter.paintBlochSphere(args.painter, ρ, args.rect);
            }

            if (showText) {
                if (showState) {
                    args.painter.ctx.globalAlpha = 0.8;
                }
                GateFactory.MAKE_HIGHLIGHTED_DRAWER(Config.DISPLAY_GATE_IN_TOOLBOX_FILL_COLOR)(args);
                if (showState) {
                    args.painter.ctx.globalAlpha = 1.0;
                }
            }
        }),

    DensityMatrixDisplay: new Gate(
        "Density",
        Matrix.identity(2),
        "Density Matrix Display",
        "Shows a wire's local state as a density matrix.\nUse controls to see conditional states.",
        args => {
            let showState = args.positionInCircuit !== null;
            let showText = !showState || args.isHighlighted;

            if (showState) {
                let {row, col} = args.positionInCircuit;
                let ρ = args.stats.qubitDensityMatrix(row, col);
                MathPainter.paintDensityMatrix(args.painter, ρ, args.rect);
            }

            if (showText) {
                if (showState) {
                    args.painter.ctx.globalAlpha = 0.8;
                }
                GateFactory.MAKE_HIGHLIGHTED_DRAWER(Config.DISPLAY_GATE_IN_TOOLBOX_FILL_COLOR)(args);
                if (showState) {
                    args.painter.ctx.globalAlpha = 1.0;
                }
            }
        })
};

/**
 * Gates that correspond to 180 degree rotations around the Bloch sphere, so they're their own inverses.
 */
Gates.HalfTurns = {
    X: new Gate(
        "X",
        Matrix.PAULI_X,
        "Pauli X Gate",
        "Toggles between ON and OFF.\nAlso known as the Not gate.",
        args => {
            // The X gate is drawn as a crossed circle when it has controls.

            let hasSingleWireControl =
                args.positionInCircuit !== null &&
                args.stats.circuitDefinition.colHasSingleWireControl(args.positionInCircuit.col);
            let hasDoubleWireControl =
                args.positionInCircuit !== null &&
                args.stats.circuitDefinition.colHasDoubleWireControl(args.positionInCircuit.col);
            if ((!hasSingleWireControl && !hasDoubleWireControl) || args.isHighlighted) {
                GateFactory.DEFAULT_DRAWER(args);
                return;
            }
{'fraction_non_alphanumeric': 0.10933581715268324, 'fraction_numerical': 0.007021566239163144, 'mean_word_length': 1.818090046436503, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5582881', 'n_tokens_mistral': 4308, 'n_tokens_neox': 3986, 'n_words': 1031}