qsharp-lang 1.14.5-dev → 1.15.1-dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.ts +1 -1
- package/dist/compiler/compiler.d.ts +1 -1
- package/dist/compiler/compiler.js +6 -1
- package/dist/debug-service/debug-service.d.ts +1 -1
- package/dist/debug-service/debug-service.js +6 -1
- package/dist/katas-content.generated.js +1 -1
- package/dist/katas-content.generated.md.js +1 -1
- package/dist/samples.generated.js +1 -1
- package/dist/shared/circuit.d.ts +86 -30
- package/dist/shared/circuit.js +4 -0
- package/dist/shared/legacyCircuitUpdate.d.ts +9 -0
- package/dist/shared/legacyCircuitUpdate.js +312 -0
- package/dist/shared/register.d.ts +3 -5
- package/dist/utils.d.ts +9 -0
- package/dist/utils.js +41 -0
- package/docs/Microsoft.Quantum.Core/Length.md +1 -1
- package/docs/Microsoft.Quantum.Core/Repeated.md +1 -1
- package/docs/Microsoft.Quantum.Core/index.md +1 -1
- package/docs/Std.Arithmetic/AddLE.md +1 -1
- package/docs/Std.Arithmetic/ApplyIfEqualL.md +1 -1
- package/docs/Std.Arithmetic/ApplyIfEqualLE.md +1 -1
- package/docs/Std.Arithmetic/ApplyIfGreaterL.md +1 -1
- package/docs/Std.Arithmetic/ApplyIfGreaterLE.md +1 -1
- package/docs/Std.Arithmetic/ApplyIfGreaterOrEqualL.md +1 -1
- package/docs/Std.Arithmetic/ApplyIfGreaterOrEqualLE.md +1 -1
- package/docs/Std.Arithmetic/ApplyIfLessL.md +1 -1
- package/docs/Std.Arithmetic/ApplyIfLessLE.md +1 -1
- package/docs/Std.Arithmetic/ApplyIfLessOrEqualL.md +1 -1
- package/docs/Std.Arithmetic/ApplyIfLessOrEqualLE.md +1 -1
- package/docs/Std.Arithmetic/FourierTDIncByLE.md +1 -1
- package/docs/Std.Arithmetic/IncByI.md +1 -1
- package/docs/Std.Arithmetic/IncByIUsingIncByLE.md +1 -1
- package/docs/Std.Arithmetic/IncByL.md +1 -1
- package/docs/Std.Arithmetic/IncByLE.md +1 -1
- package/docs/Std.Arithmetic/IncByLEUsingAddLE.md +1 -1
- package/docs/Std.Arithmetic/IncByLUsingIncByLE.md +1 -1
- package/docs/Std.Arithmetic/LookAheadDKRSAddLE.md +1 -1
- package/docs/Std.Arithmetic/MAJ.md +1 -1
- package/docs/Std.Arithmetic/ReflectAboutInteger.md +1 -1
- package/docs/Std.Arithmetic/RippleCarryCGAddLE.md +1 -1
- package/docs/Std.Arithmetic/RippleCarryCGIncByLE.md +1 -1
- package/docs/Std.Arithmetic/RippleCarryTTKIncByLE.md +1 -1
- package/docs/Std.Arithmetic/index.md +1 -1
- package/docs/Std.Arrays/All.md +1 -1
- package/docs/Std.Arrays/Any.md +1 -1
- package/docs/Std.Arrays/Chunks.md +1 -1
- package/docs/Std.Arrays/CircularlyShifted.md +1 -1
- package/docs/Std.Arrays/ColumnAt.md +1 -1
- package/docs/Std.Arrays/Count.md +1 -1
- package/docs/Std.Arrays/Diagonal.md +1 -1
- package/docs/Std.Arrays/DrawMany.md +1 -1
- package/docs/Std.Arrays/Enumerated.md +1 -1
- package/docs/Std.Arrays/Excluding.md +1 -1
- package/docs/Std.Arrays/Filtered.md +1 -1
- package/docs/Std.Arrays/FlatMapped.md +1 -1
- package/docs/Std.Arrays/Flattened.md +1 -1
- package/docs/Std.Arrays/Fold.md +1 -1
- package/docs/Std.Arrays/ForEach.md +1 -1
- package/docs/Std.Arrays/Head.md +1 -1
- package/docs/Std.Arrays/HeadAndRest.md +1 -1
- package/docs/Std.Arrays/IndexOf.md +1 -1
- package/docs/Std.Arrays/IndexRange.md +1 -1
- package/docs/Std.Arrays/Interleaved.md +1 -1
- package/docs/Std.Arrays/IsEmpty.md +1 -1
- package/docs/Std.Arrays/IsRectangularArray.md +1 -1
- package/docs/Std.Arrays/IsSorted.md +1 -1
- package/docs/Std.Arrays/IsSquareArray.md +1 -1
- package/docs/Std.Arrays/Mapped.md +1 -1
- package/docs/Std.Arrays/MappedByIndex.md +1 -1
- package/docs/Std.Arrays/MappedOverRange.md +1 -1
- package/docs/Std.Arrays/Most.md +1 -1
- package/docs/Std.Arrays/MostAndTail.md +1 -1
- package/docs/Std.Arrays/Padded.md +1 -1
- package/docs/Std.Arrays/Partitioned.md +1 -1
- package/docs/Std.Arrays/Rest.md +1 -1
- package/docs/Std.Arrays/Reversed.md +1 -1
- package/docs/Std.Arrays/SequenceI.md +1 -1
- package/docs/Std.Arrays/SequenceL.md +1 -1
- package/docs/Std.Arrays/Sorted.md +1 -1
- package/docs/Std.Arrays/Subarray.md +1 -1
- package/docs/Std.Arrays/Swapped.md +1 -1
- package/docs/Std.Arrays/Tail.md +1 -1
- package/docs/Std.Arrays/Transposed.md +1 -1
- package/docs/Std.Arrays/Unzipped.md +1 -1
- package/docs/Std.Arrays/Where.md +1 -1
- package/docs/Std.Arrays/Windows.md +1 -1
- package/docs/Std.Arrays/Zipped.md +1 -1
- package/docs/Std.Arrays/index.md +1 -1
- package/docs/Std.Canon/ApplyCNOTChain.md +1 -1
- package/docs/Std.Canon/ApplyControlledOnBitString.md +1 -1
- package/docs/Std.Canon/ApplyControlledOnInt.md +1 -1
- package/docs/Std.Canon/ApplyP.md +1 -1
- package/docs/Std.Canon/ApplyPauli.md +1 -1
- package/docs/Std.Canon/ApplyPauliFromBitString.md +1 -1
- package/docs/Std.Canon/ApplyPauliFromInt.md +1 -1
- package/docs/Std.Canon/ApplyQFT.md +1 -1
- package/docs/Std.Canon/ApplyToEach.md +1 -1
- package/docs/Std.Canon/ApplyToEachA.md +1 -1
- package/docs/Std.Canon/ApplyToEachC.md +1 -1
- package/docs/Std.Canon/ApplyToEachCA.md +1 -1
- package/docs/Std.Canon/ApplyXorInPlace.md +1 -1
- package/docs/Std.Canon/ApplyXorInPlaceL.md +1 -1
- package/docs/Std.Canon/CX.md +1 -1
- package/docs/Std.Canon/CY.md +1 -1
- package/docs/Std.Canon/CZ.md +1 -1
- package/docs/Std.Canon/Fst.md +1 -1
- package/docs/Std.Canon/Relabel.md +1 -1
- package/docs/Std.Canon/Snd.md +1 -1
- package/docs/Std.Canon/SwapReverseRegister.md +1 -1
- package/docs/Std.Canon/index.md +1 -1
- package/docs/Std.Convert/BigIntAsBoolArray.md +1 -1
- package/docs/Std.Convert/BoolArrayAsBigInt.md +1 -1
- package/docs/Std.Convert/BoolArrayAsInt.md +1 -1
- package/docs/Std.Convert/BoolArrayAsResultArray.md +1 -1
- package/docs/Std.Convert/BoolAsResult.md +1 -1
- package/docs/Std.Convert/ComplexAsComplexPolar.md +1 -1
- package/docs/Std.Convert/ComplexPolarAsComplex.md +1 -1
- package/docs/Std.Convert/DoubleAsStringWithPrecision.md +1 -1
- package/docs/Std.Convert/IntAsBigInt.md +1 -1
- package/docs/Std.Convert/IntAsBoolArray.md +1 -1
- package/docs/Std.Convert/IntAsDouble.md +1 -1
- package/docs/Std.Convert/ResultArrayAsBoolArray.md +1 -1
- package/docs/Std.Convert/ResultArrayAsInt.md +1 -1
- package/docs/Std.Convert/ResultAsBool.md +1 -1
- package/docs/Std.Convert/index.md +1 -1
- package/docs/Std.Core/Length.md +1 -1
- package/docs/Std.Core/Repeated.md +1 -1
- package/docs/Std.Core/index.md +1 -1
- package/docs/Std.Diagnostics/ApplyIdleNoise.md +1 -1
- package/docs/Std.Diagnostics/BitFlipNoise.md +1 -1
- package/docs/Std.Diagnostics/CheckAllZero.md +1 -1
- package/docs/Std.Diagnostics/CheckOperationsAreEqual.md +1 -1
- package/docs/Std.Diagnostics/CheckZero.md +1 -1
- package/docs/Std.Diagnostics/ConfigurePauliNoise.md +1 -1
- package/docs/Std.Diagnostics/DepolarizingNoise.md +1 -1
- package/docs/Std.Diagnostics/DumpMachine.md +1 -1
- package/docs/Std.Diagnostics/DumpOperation.md +1 -1
- package/docs/Std.Diagnostics/DumpRegister.md +1 -1
- package/docs/Std.Diagnostics/Fact.md +1 -1
- package/docs/Std.Diagnostics/NoNoise.md +1 -1
- package/docs/Std.Diagnostics/PhaseFlipNoise.md +1 -1
- package/docs/Std.Diagnostics/StartCountingFunction.md +1 -1
- package/docs/Std.Diagnostics/StartCountingOperation.md +1 -1
- package/docs/Std.Diagnostics/StartCountingQubits.md +1 -1
- package/docs/Std.Diagnostics/StopCountingFunction.md +1 -1
- package/docs/Std.Diagnostics/StopCountingOperation.md +1 -1
- package/docs/Std.Diagnostics/StopCountingQubits.md +1 -1
- package/docs/Std.Diagnostics/index.md +1 -1
- package/docs/Std.Intrinsic/AND.md +1 -1
- package/docs/Std.Intrinsic/ApplyUnitary.md +1 -1
- package/docs/Std.Intrinsic/CCNOT.md +1 -1
- package/docs/Std.Intrinsic/CNOT.md +1 -1
- package/docs/Std.Intrinsic/Exp.md +1 -1
- package/docs/Std.Intrinsic/H.md +1 -1
- package/docs/Std.Intrinsic/I.md +1 -1
- package/docs/Std.Intrinsic/M.md +1 -1
- package/docs/Std.Intrinsic/Measure.md +1 -1
- package/docs/Std.Intrinsic/Message.md +1 -1
- package/docs/Std.Intrinsic/R.md +1 -1
- package/docs/Std.Intrinsic/R1.md +1 -1
- package/docs/Std.Intrinsic/R1Frac.md +1 -1
- package/docs/Std.Intrinsic/RFrac.md +1 -1
- package/docs/Std.Intrinsic/Reset.md +1 -1
- package/docs/Std.Intrinsic/ResetAll.md +1 -1
- package/docs/Std.Intrinsic/Rx.md +1 -1
- package/docs/Std.Intrinsic/Rxx.md +1 -1
- package/docs/Std.Intrinsic/Ry.md +1 -1
- package/docs/Std.Intrinsic/Ryy.md +1 -1
- package/docs/Std.Intrinsic/Rz.md +1 -1
- package/docs/Std.Intrinsic/Rzz.md +1 -1
- package/docs/Std.Intrinsic/S.md +1 -1
- package/docs/Std.Intrinsic/SWAP.md +1 -1
- package/docs/Std.Intrinsic/T.md +1 -1
- package/docs/Std.Intrinsic/X.md +1 -1
- package/docs/Std.Intrinsic/Y.md +1 -1
- package/docs/Std.Intrinsic/Z.md +1 -1
- package/docs/Std.Intrinsic/index.md +1 -1
- package/docs/Std.Logical/Xor.md +1 -1
- package/docs/Std.Logical/index.md +1 -1
- package/docs/Std.Math/AbsComplex.md +1 -1
- package/docs/Std.Math/AbsComplexPolar.md +1 -1
- package/docs/Std.Math/AbsD.md +1 -1
- package/docs/Std.Math/AbsI.md +1 -1
- package/docs/Std.Math/AbsL.md +1 -1
- package/docs/Std.Math/AbsSquaredComplex.md +1 -1
- package/docs/Std.Math/AbsSquaredComplexPolar.md +1 -1
- package/docs/Std.Math/ApproximateFactorial.md +1 -1
- package/docs/Std.Math/ArcCos.md +1 -1
- package/docs/Std.Math/ArcCosh.md +1 -1
- package/docs/Std.Math/ArcSin.md +1 -1
- package/docs/Std.Math/ArcSinh.md +1 -1
- package/docs/Std.Math/ArcTan.md +1 -1
- package/docs/Std.Math/ArcTan2.md +1 -1
- package/docs/Std.Math/ArcTanh.md +1 -1
- package/docs/Std.Math/ArgComplex.md +1 -1
- package/docs/Std.Math/ArgComplexPolar.md +1 -1
- package/docs/Std.Math/Binom.md +1 -1
- package/docs/Std.Math/BitSizeI.md +1 -1
- package/docs/Std.Math/BitSizeL.md +1 -1
- package/docs/Std.Math/Ceiling.md +1 -1
- package/docs/Std.Math/Complex.md +1 -1
- package/docs/Std.Math/ComplexPolar.md +1 -1
- package/docs/Std.Math/ContinuedFractionConvergentI.md +1 -1
- package/docs/Std.Math/ContinuedFractionConvergentL.md +1 -1
- package/docs/Std.Math/Cos.md +1 -1
- package/docs/Std.Math/Cosh.md +1 -1
- package/docs/Std.Math/DivRemI.md +1 -1
- package/docs/Std.Math/DivRemL.md +1 -1
- package/docs/Std.Math/DividedByC.md +1 -1
- package/docs/Std.Math/DividedByCP.md +1 -1
- package/docs/Std.Math/E.md +1 -1
- package/docs/Std.Math/ExpModI.md +1 -1
- package/docs/Std.Math/ExpModL.md +1 -1
- package/docs/Std.Math/ExtendedGreatestCommonDivisorI.md +1 -1
- package/docs/Std.Math/ExtendedGreatestCommonDivisorL.md +1 -1
- package/docs/Std.Math/FactorialI.md +1 -1
- package/docs/Std.Math/FactorialL.md +1 -1
- package/docs/Std.Math/Floor.md +1 -1
- package/docs/Std.Math/GreatestCommonDivisorI.md +1 -1
- package/docs/Std.Math/GreatestCommonDivisorL.md +1 -1
- package/docs/Std.Math/HammingWeightI.md +1 -1
- package/docs/Std.Math/InverseModI.md +1 -1
- package/docs/Std.Math/InverseModL.md +1 -1
- package/docs/Std.Math/IsCoprimeI.md +1 -1
- package/docs/Std.Math/IsCoprimeL.md +1 -1
- package/docs/Std.Math/IsInfinite.md +1 -1
- package/docs/Std.Math/IsNaN.md +1 -1
- package/docs/Std.Math/LargestFixedPoint.md +1 -1
- package/docs/Std.Math/Lg.md +1 -1
- package/docs/Std.Math/Log.md +1 -1
- package/docs/Std.Math/Log10.md +1 -1
- package/docs/Std.Math/LogFactorialD.md +1 -1
- package/docs/Std.Math/LogGammaD.md +1 -1
- package/docs/Std.Math/LogOf2.md +1 -1
- package/docs/Std.Math/Max.md +1 -1
- package/docs/Std.Math/MaxD.md +1 -1
- package/docs/Std.Math/MaxI.md +1 -1
- package/docs/Std.Math/MaxL.md +1 -1
- package/docs/Std.Math/Min.md +1 -1
- package/docs/Std.Math/MinD.md +1 -1
- package/docs/Std.Math/MinI.md +1 -1
- package/docs/Std.Math/MinL.md +1 -1
- package/docs/Std.Math/MinusC.md +1 -1
- package/docs/Std.Math/MinusCP.md +1 -1
- package/docs/Std.Math/ModulusI.md +1 -1
- package/docs/Std.Math/ModulusL.md +1 -1
- package/docs/Std.Math/NegationC.md +1 -1
- package/docs/Std.Math/NegationCP.md +1 -1
- package/docs/Std.Math/PI.md +1 -1
- package/docs/Std.Math/PNorm.md +1 -1
- package/docs/Std.Math/PNormalized.md +1 -1
- package/docs/Std.Math/PlusC.md +1 -1
- package/docs/Std.Math/PlusCP.md +1 -1
- package/docs/Std.Math/PowC.md +1 -1
- package/docs/Std.Math/PowCP.md +1 -1
- package/docs/Std.Math/RealMod.md +1 -1
- package/docs/Std.Math/Round.md +1 -1
- package/docs/Std.Math/SignD.md +1 -1
- package/docs/Std.Math/SignI.md +1 -1
- package/docs/Std.Math/SignL.md +1 -1
- package/docs/Std.Math/Sin.md +1 -1
- package/docs/Std.Math/Sinh.md +1 -1
- package/docs/Std.Math/SmallestFixedPoint.md +1 -1
- package/docs/Std.Math/Sqrt.md +1 -1
- package/docs/Std.Math/SquaredNorm.md +1 -1
- package/docs/Std.Math/Tan.md +1 -1
- package/docs/Std.Math/Tanh.md +1 -1
- package/docs/Std.Math/TimesC.md +1 -1
- package/docs/Std.Math/TimesCP.md +1 -1
- package/docs/Std.Math/TrailingZeroCountI.md +1 -1
- package/docs/Std.Math/TrailingZeroCountL.md +1 -1
- package/docs/Std.Math/Truncate.md +1 -1
- package/docs/Std.Math/index.md +1 -1
- package/docs/Std.Measurement/MResetEachZ.md +1 -1
- package/docs/Std.Measurement/MResetX.md +1 -1
- package/docs/Std.Measurement/MResetY.md +1 -1
- package/docs/Std.Measurement/MResetZ.md +1 -1
- package/docs/Std.Measurement/MeasureAllZ.md +1 -1
- package/docs/Std.Measurement/MeasureEachZ.md +1 -1
- package/docs/Std.Measurement/MeasureInteger.md +1 -1
- package/docs/Std.Measurement/index.md +1 -1
- package/docs/Std.Random/DrawRandomBool.md +1 -1
- package/docs/Std.Random/DrawRandomDouble.md +1 -1
- package/docs/Std.Random/DrawRandomInt.md +1 -1
- package/docs/Std.Random/index.md +1 -1
- package/docs/Std.Range/IsRangeEmpty.md +1 -1
- package/docs/Std.Range/RangeEnd.md +1 -1
- package/docs/Std.Range/RangeReverse.md +1 -1
- package/docs/Std.Range/RangeStart.md +1 -1
- package/docs/Std.Range/RangeStep.md +1 -1
- package/docs/Std.Range/index.md +1 -1
- package/docs/Std.ResourceEstimation/AccountForEstimates.md +1 -1
- package/docs/Std.ResourceEstimation/AuxQubitCount.md +1 -1
- package/docs/Std.ResourceEstimation/BeginEstimateCaching.md +1 -1
- package/docs/Std.ResourceEstimation/BeginRepeatEstimates.md +1 -1
- package/docs/Std.ResourceEstimation/CczCount.md +1 -1
- package/docs/Std.ResourceEstimation/EndEstimateCaching.md +1 -1
- package/docs/Std.ResourceEstimation/EndRepeatEstimates.md +1 -1
- package/docs/Std.ResourceEstimation/MeasurementCount.md +1 -1
- package/docs/Std.ResourceEstimation/PSSPCLayout.md +1 -1
- package/docs/Std.ResourceEstimation/RepeatEstimates.md +1 -1
- package/docs/Std.ResourceEstimation/RotationCount.md +1 -1
- package/docs/Std.ResourceEstimation/RotationDepth.md +1 -1
- package/docs/Std.ResourceEstimation/SingleVariant.md +1 -1
- package/docs/Std.ResourceEstimation/TCount.md +1 -1
- package/docs/Std.ResourceEstimation/index.md +1 -1
- package/docs/Std.StatePreparation/ApproximatelyPreparePureStateCP.md +1 -1
- package/docs/Std.StatePreparation/PreparePureStateD.md +1 -1
- package/docs/Std.StatePreparation/PrepareUniformSuperposition.md +1 -1
- package/docs/Std.StatePreparation/index.md +1 -1
- package/docs/Std.TableLookup/Select.md +1 -1
- package/docs/Std.TableLookup/index.md +1 -1
- package/docs/index.md +1 -1
- package/lib/node/qsc_wasm.cjs +2 -2
- package/lib/node/qsc_wasm_bg.wasm +0 -0
- package/lib/web/qsc_wasm.js +2 -2
- package/lib/web/qsc_wasm_bg.wasm +0 -0
- package/package.json +1 -1
- package/ux/circuit-vis/circuit.ts +11 -0
- package/ux/circuit-vis/circuitManipulation.ts +549 -0
- package/ux/circuit-vis/constants.ts +7 -0
- package/ux/circuit-vis/contextMenu.ts +376 -0
- package/ux/circuit-vis/draggable.ts +352 -0
- package/ux/circuit-vis/events.ts +818 -0
- package/ux/circuit-vis/formatters/gateFormatter.ts +56 -23
- package/ux/circuit-vis/formatters/inputFormatter.ts +38 -7
- package/ux/circuit-vis/formatters/registerFormatter.ts +12 -30
- package/ux/circuit-vis/index.ts +16 -11
- package/ux/circuit-vis/metadata.ts +3 -1
- package/ux/circuit-vis/panel.ts +333 -0
- package/ux/circuit-vis/process.ts +136 -232
- package/ux/circuit-vis/sqore.ts +231 -116
- package/ux/circuit-vis/utils.ts +269 -1
- package/ux/circuit.tsx +71 -37
- package/ux/data.ts +4 -2
- package/ux/index.ts +1 -1
- package/ux/qsharp-circuit.css +260 -4
- package/ux/circuit-vis/styles.ts +0 -236
|
@@ -0,0 +1,818 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT license.
|
|
3
|
+
|
|
4
|
+
import cloneDeep from "lodash/cloneDeep";
|
|
5
|
+
import isEqual from "lodash/isEqual";
|
|
6
|
+
import { ComponentGrid, Operation, Qubit, Unitary } from "./circuit";
|
|
7
|
+
import { Sqore } from "./sqore";
|
|
8
|
+
import { toolboxGateDictionary } from "./panel";
|
|
9
|
+
import {
|
|
10
|
+
getGateLocationString,
|
|
11
|
+
findOperation,
|
|
12
|
+
getToolboxElems,
|
|
13
|
+
getGateElems,
|
|
14
|
+
getHostElems,
|
|
15
|
+
getWireData,
|
|
16
|
+
locationStringToIndexes,
|
|
17
|
+
findParentArray,
|
|
18
|
+
} from "./utils";
|
|
19
|
+
import { addContextMenuToHostElem, promptForArguments } from "./contextMenu";
|
|
20
|
+
import {
|
|
21
|
+
addControl,
|
|
22
|
+
addOperation,
|
|
23
|
+
findAndRemoveOperations,
|
|
24
|
+
moveOperation,
|
|
25
|
+
removeControl,
|
|
26
|
+
removeOperation,
|
|
27
|
+
} from "./circuitManipulation";
|
|
28
|
+
import {
|
|
29
|
+
createGhostElement,
|
|
30
|
+
createWireDropzone,
|
|
31
|
+
removeAllWireDropzones,
|
|
32
|
+
} from "./draggable";
|
|
33
|
+
import { getMinMaxRegIdx } from "../../src/utils";
|
|
34
|
+
|
|
35
|
+
let events: CircuitEvents | null = null;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Creates and attaches the events that allow editing of the circuit.
|
|
39
|
+
*
|
|
40
|
+
* @param container HTML element for rendering visualization into
|
|
41
|
+
* @param sqore Sqore object
|
|
42
|
+
*/
|
|
43
|
+
const enableEvents = (
|
|
44
|
+
container: HTMLElement,
|
|
45
|
+
sqore: Sqore,
|
|
46
|
+
useRefresh: () => void,
|
|
47
|
+
): void => {
|
|
48
|
+
if (events != null) {
|
|
49
|
+
events.dispose();
|
|
50
|
+
}
|
|
51
|
+
events = new CircuitEvents(container, sqore, useRefresh);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
class CircuitEvents {
|
|
55
|
+
renderFn: () => void;
|
|
56
|
+
componentGrid: ComponentGrid;
|
|
57
|
+
qubits: Qubit[];
|
|
58
|
+
private circuitSvg: SVGElement;
|
|
59
|
+
private dropzoneLayer: SVGGElement;
|
|
60
|
+
private wireData: number[];
|
|
61
|
+
private selectedOperation: Operation | null = null;
|
|
62
|
+
private selectedWire: number | null = null;
|
|
63
|
+
private movingControl: boolean = false;
|
|
64
|
+
private mouseUpOnCircuit: boolean = false;
|
|
65
|
+
private dragging: boolean = false;
|
|
66
|
+
private disableLeftAutoScroll: boolean = false;
|
|
67
|
+
|
|
68
|
+
constructor(
|
|
69
|
+
private container: HTMLElement,
|
|
70
|
+
sqore: Sqore,
|
|
71
|
+
useRefresh: () => void,
|
|
72
|
+
) {
|
|
73
|
+
this.renderFn = useRefresh;
|
|
74
|
+
|
|
75
|
+
this.circuitSvg = container.querySelector("svg[id]") as SVGElement;
|
|
76
|
+
this.dropzoneLayer = container.querySelector(
|
|
77
|
+
".dropzone-layer",
|
|
78
|
+
) as SVGGElement;
|
|
79
|
+
|
|
80
|
+
this.componentGrid = sqore.circuit.componentGrid;
|
|
81
|
+
this.qubits = sqore.circuit.qubits;
|
|
82
|
+
|
|
83
|
+
this.wireData = getWireData(this.container);
|
|
84
|
+
|
|
85
|
+
this._addContextMenuEvent();
|
|
86
|
+
this._addDropzoneLayerEvents();
|
|
87
|
+
this._addHostElementsEvents();
|
|
88
|
+
this._addGateElementsEvents();
|
|
89
|
+
this._addToolboxElementsEvents();
|
|
90
|
+
this._addDropzoneElementsEvents();
|
|
91
|
+
this._addQubitLineControlEvents();
|
|
92
|
+
this._addDocumentEvents();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Dispose the CircuitEvents instance and remove event listeners
|
|
97
|
+
*/
|
|
98
|
+
dispose() {
|
|
99
|
+
this._removeToolboxElementsEvents();
|
|
100
|
+
this._removeDocumentEvents();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/***************************
|
|
104
|
+
* Events Adding Functions *
|
|
105
|
+
***************************/
|
|
106
|
+
|
|
107
|
+
documentKeydownHandler = (ev: KeyboardEvent) => {
|
|
108
|
+
const selectedLocation = this.selectedOperation
|
|
109
|
+
? getGateLocationString(this.selectedOperation)
|
|
110
|
+
: null;
|
|
111
|
+
if (ev.ctrlKey && selectedLocation) {
|
|
112
|
+
this.container.classList.remove("moving");
|
|
113
|
+
this.container.classList.add("copying");
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
documentKeyupHandler = (ev: KeyboardEvent) => {
|
|
118
|
+
const selectedLocation = this.selectedOperation
|
|
119
|
+
? getGateLocationString(this.selectedOperation)
|
|
120
|
+
: null;
|
|
121
|
+
if (ev.ctrlKey && selectedLocation) {
|
|
122
|
+
this.container.classList.remove("copying");
|
|
123
|
+
this.container.classList.add("moving");
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
documentMousedownHandler = () => {
|
|
128
|
+
removeAllWireDropzones(this.circuitSvg);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
documentMouseupHandler = (ev: MouseEvent) => {
|
|
132
|
+
const copying = ev.ctrlKey;
|
|
133
|
+
this.container.classList.remove("moving", "copying");
|
|
134
|
+
if (this.container) {
|
|
135
|
+
const ghostElem = this.container.querySelector(".ghost");
|
|
136
|
+
if (ghostElem) {
|
|
137
|
+
this.container.removeChild(ghostElem);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Handle deleting operations that have been dragged outside the circuit
|
|
141
|
+
if (!this.mouseUpOnCircuit && this.dragging && !copying) {
|
|
142
|
+
const selectedLocation = this.selectedOperation
|
|
143
|
+
? getGateLocationString(this.selectedOperation)
|
|
144
|
+
: null;
|
|
145
|
+
if (this.selectedOperation != null && selectedLocation != null) {
|
|
146
|
+
// We are dragging a gate with a location (not from toolbox) outside the circuit
|
|
147
|
+
// If we are moving a control, remove it from the selectedOperation
|
|
148
|
+
if (
|
|
149
|
+
this.movingControl &&
|
|
150
|
+
this.selectedOperation.kind === "unitary" &&
|
|
151
|
+
this.selectedOperation.controls != null &&
|
|
152
|
+
this.selectedWire != null
|
|
153
|
+
) {
|
|
154
|
+
const controlIndex = this.selectedOperation.controls.findIndex(
|
|
155
|
+
(control) => control.qubit === this.selectedWire,
|
|
156
|
+
);
|
|
157
|
+
if (controlIndex !== -1)
|
|
158
|
+
this.selectedOperation.controls.splice(controlIndex, 1);
|
|
159
|
+
} else {
|
|
160
|
+
// Otherwise, remove the selectedOperation
|
|
161
|
+
removeOperation(this, selectedLocation);
|
|
162
|
+
}
|
|
163
|
+
this.renderFn();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
this.dragging = false;
|
|
168
|
+
this.disableLeftAutoScroll = false;
|
|
169
|
+
this.movingControl = false;
|
|
170
|
+
this.mouseUpOnCircuit = false;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Enable auto-scrolling when dragging near the edges of the container
|
|
175
|
+
*/
|
|
176
|
+
_enableAutoScroll() {
|
|
177
|
+
const scrollSpeed = 10; // Pixels per frame
|
|
178
|
+
const edgeThreshold = 50; // Distance from the edge to trigger scrolling
|
|
179
|
+
|
|
180
|
+
// Utility function to find the nearest scrollable ancestor
|
|
181
|
+
const getScrollableAncestor = (element: Element): HTMLElement => {
|
|
182
|
+
let currentElement: Element | null = element;
|
|
183
|
+
while (currentElement) {
|
|
184
|
+
const overflowY = window.getComputedStyle(currentElement).overflowY;
|
|
185
|
+
const overflowX = window.getComputedStyle(currentElement).overflowX;
|
|
186
|
+
if (
|
|
187
|
+
overflowY === "auto" ||
|
|
188
|
+
overflowY === "scroll" ||
|
|
189
|
+
overflowX === "auto" ||
|
|
190
|
+
overflowX === "scroll"
|
|
191
|
+
) {
|
|
192
|
+
return currentElement as HTMLElement;
|
|
193
|
+
}
|
|
194
|
+
currentElement = currentElement.parentElement;
|
|
195
|
+
}
|
|
196
|
+
return document.documentElement; // Fallback to the root element
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const scrollableAncestor = getScrollableAncestor(this.circuitSvg);
|
|
200
|
+
|
|
201
|
+
const onMouseMove = (ev: MouseEvent) => {
|
|
202
|
+
const rect = scrollableAncestor.getBoundingClientRect();
|
|
203
|
+
|
|
204
|
+
const topBoundary = rect.top;
|
|
205
|
+
const bottomBoundary = rect.bottom;
|
|
206
|
+
const leftBoundary = rect.left;
|
|
207
|
+
const rightBoundary = rect.right;
|
|
208
|
+
|
|
209
|
+
// If the mouse has moved past the left boundary, we want to re-enable left auto-scrolling
|
|
210
|
+
if (
|
|
211
|
+
this.disableLeftAutoScroll &&
|
|
212
|
+
ev.clientX > leftBoundary + 3 * edgeThreshold
|
|
213
|
+
) {
|
|
214
|
+
this.disableLeftAutoScroll = false;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Check if the cursor is near the edges
|
|
218
|
+
if (ev.clientY < topBoundary + edgeThreshold) {
|
|
219
|
+
// Scroll up
|
|
220
|
+
scrollableAncestor.scrollTop -= scrollSpeed;
|
|
221
|
+
} else if (ev.clientY > bottomBoundary - edgeThreshold) {
|
|
222
|
+
// Scroll down
|
|
223
|
+
scrollableAncestor.scrollTop += scrollSpeed;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (
|
|
227
|
+
!this.disableLeftAutoScroll &&
|
|
228
|
+
ev.clientX < leftBoundary + edgeThreshold
|
|
229
|
+
) {
|
|
230
|
+
// Scroll left
|
|
231
|
+
scrollableAncestor.scrollLeft -= scrollSpeed;
|
|
232
|
+
} else if (ev.clientX > rightBoundary - edgeThreshold) {
|
|
233
|
+
// Scroll right
|
|
234
|
+
scrollableAncestor.scrollLeft += scrollSpeed;
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const onMouseUp = () => {
|
|
239
|
+
// Remove the mousemove listener when dragging stops
|
|
240
|
+
document.removeEventListener("mousemove", onMouseMove);
|
|
241
|
+
document.removeEventListener("mouseup", onMouseUp);
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Add the mousemove listener when dragging starts
|
|
245
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
246
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Add events for document
|
|
251
|
+
*/
|
|
252
|
+
_addDocumentEvents() {
|
|
253
|
+
document.addEventListener("keydown", this.documentKeydownHandler);
|
|
254
|
+
document.addEventListener("keyup", this.documentKeyupHandler);
|
|
255
|
+
document.addEventListener("mouseup", this.documentMouseupHandler);
|
|
256
|
+
document.addEventListener("mousedown", this.documentMousedownHandler);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Remove events for document
|
|
261
|
+
*/
|
|
262
|
+
_removeDocumentEvents() {
|
|
263
|
+
document.removeEventListener("keydown", this.documentKeydownHandler);
|
|
264
|
+
document.removeEventListener("keyup", this.documentKeyupHandler);
|
|
265
|
+
document.removeEventListener("mouseup", this.documentMouseupHandler);
|
|
266
|
+
document.removeEventListener("mousedown", this.documentMousedownHandler);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Add events specifically for dropzoneLayer
|
|
271
|
+
*/
|
|
272
|
+
_addDropzoneLayerEvents() {
|
|
273
|
+
this.container.addEventListener(
|
|
274
|
+
"mouseup",
|
|
275
|
+
() => (this.dropzoneLayer.style.display = "none"),
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
this.circuitSvg.addEventListener("mouseup", () => {
|
|
279
|
+
this.mouseUpOnCircuit = true;
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Disable contextmenu default behaviors
|
|
285
|
+
*/
|
|
286
|
+
_addContextMenuEvent() {
|
|
287
|
+
this.container.addEventListener("contextmenu", (ev: MouseEvent) => {
|
|
288
|
+
ev.preventDefault();
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Add events for circuit objects in the circuit
|
|
294
|
+
*/
|
|
295
|
+
_addHostElementsEvents() {
|
|
296
|
+
const elems = getHostElems(this.container);
|
|
297
|
+
elems.forEach((elem) => {
|
|
298
|
+
elem.addEventListener("mousedown", (ev: MouseEvent) => {
|
|
299
|
+
if (ev.button !== 0) return;
|
|
300
|
+
if (elem.classList.contains("control-dot")) {
|
|
301
|
+
this.movingControl = true;
|
|
302
|
+
}
|
|
303
|
+
const selectedWireStr = elem.getAttribute("data-wire");
|
|
304
|
+
this.selectedWire =
|
|
305
|
+
selectedWireStr != null ? parseInt(selectedWireStr) : null;
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
addContextMenuToHostElem(this, elem);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Add events for circuit objects in the circuit
|
|
314
|
+
*/
|
|
315
|
+
_addGateElementsEvents() {
|
|
316
|
+
const elems = getGateElems(this.container);
|
|
317
|
+
elems.forEach((elem) => {
|
|
318
|
+
elem?.addEventListener("mousedown", (ev: MouseEvent) => {
|
|
319
|
+
// Allow dragging even when initiated on the arg-button
|
|
320
|
+
if ((ev.target as HTMLElement).classList.contains("arg-button")) {
|
|
321
|
+
// Find the sibling element with the data-wire attribute
|
|
322
|
+
const siblingWithWire = (
|
|
323
|
+
ev.target as HTMLElement
|
|
324
|
+
).parentElement?.querySelector("[data-wire]");
|
|
325
|
+
if (siblingWithWire) {
|
|
326
|
+
const selectedWireStr = siblingWithWire.getAttribute("data-wire");
|
|
327
|
+
this.selectedWire =
|
|
328
|
+
selectedWireStr != null ? parseInt(selectedWireStr) : null;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
let selectedLocation = null;
|
|
333
|
+
if (elem.getAttribute("data-expanded") !== "true") {
|
|
334
|
+
selectedLocation = elem.getAttribute("data-location");
|
|
335
|
+
this.selectedOperation = findOperation(
|
|
336
|
+
this.componentGrid,
|
|
337
|
+
selectedLocation,
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
if (ev.button !== 0) return;
|
|
341
|
+
ev.stopPropagation();
|
|
342
|
+
removeAllWireDropzones(this.circuitSvg);
|
|
343
|
+
if (this.selectedOperation == null || !selectedLocation) return;
|
|
344
|
+
|
|
345
|
+
this._createGhostElement(ev);
|
|
346
|
+
|
|
347
|
+
// Make sure the selectedOperation has location data
|
|
348
|
+
if (this.selectedOperation.dataAttributes == null) {
|
|
349
|
+
this.selectedOperation.dataAttributes = {
|
|
350
|
+
location: selectedLocation,
|
|
351
|
+
};
|
|
352
|
+
} else {
|
|
353
|
+
this.selectedOperation.dataAttributes["location"] = selectedLocation;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
this.container.classList.add("moving");
|
|
357
|
+
this.dropzoneLayer.style.display = "block";
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// Enable arg-button behavior
|
|
361
|
+
const argButtons = elem.querySelectorAll<SVGElement>(".arg-button");
|
|
362
|
+
argButtons.forEach((argButton) => {
|
|
363
|
+
argButton.classList.add("edit-mode");
|
|
364
|
+
|
|
365
|
+
// Add click event to trigger promptForArguments
|
|
366
|
+
argButton.addEventListener("click", async () => {
|
|
367
|
+
if (this.selectedOperation == null) return;
|
|
368
|
+
const params = this.selectedOperation.params;
|
|
369
|
+
const displayArgs = argButton.textContent || "";
|
|
370
|
+
if (params) {
|
|
371
|
+
const args = await promptForArguments(params, [displayArgs]);
|
|
372
|
+
if (args.length > 0) {
|
|
373
|
+
this.selectedOperation.args = args;
|
|
374
|
+
this.renderFn();
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
toolboxMousedownHandler = (ev: MouseEvent) => {
|
|
383
|
+
if (ev.button !== 0) return;
|
|
384
|
+
this.container.classList.add("moving");
|
|
385
|
+
this.dropzoneLayer.style.display = "block";
|
|
386
|
+
const elem = ev.currentTarget as HTMLElement;
|
|
387
|
+
const type = elem.getAttribute("data-type");
|
|
388
|
+
if (type == null) return;
|
|
389
|
+
this.selectedOperation = toolboxGateDictionary[type];
|
|
390
|
+
this.disableLeftAutoScroll = true;
|
|
391
|
+
this._createGhostElement(ev);
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Add events for gates in the toolbox
|
|
396
|
+
*/
|
|
397
|
+
_addToolboxElementsEvents() {
|
|
398
|
+
const elems = getToolboxElems(this.container);
|
|
399
|
+
elems.forEach((elem) => {
|
|
400
|
+
elem.addEventListener("mousedown", this.toolboxMousedownHandler);
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Remove events for gates in the toolbox
|
|
406
|
+
*/
|
|
407
|
+
_removeToolboxElementsEvents() {
|
|
408
|
+
const elems = getToolboxElems(this.container);
|
|
409
|
+
elems.forEach((elem) => {
|
|
410
|
+
elem.removeEventListener("mousedown", this.toolboxMousedownHandler);
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Add events for dropzone elements
|
|
416
|
+
*/
|
|
417
|
+
_addDropzoneElementsEvents() {
|
|
418
|
+
const dropzoneElems =
|
|
419
|
+
this.dropzoneLayer.querySelectorAll<SVGRectElement>(".dropzone");
|
|
420
|
+
dropzoneElems.forEach((dropzoneElem) => {
|
|
421
|
+
dropzoneElem.addEventListener("mouseup", async (ev: MouseEvent) => {
|
|
422
|
+
const copying = ev.ctrlKey;
|
|
423
|
+
const originalGrid = cloneDeep(this.componentGrid);
|
|
424
|
+
const targetLoc = dropzoneElem.getAttribute("data-dropzone-location");
|
|
425
|
+
const insertNewColumn =
|
|
426
|
+
dropzoneElem.getAttribute("data-dropzone-inter-column") == "true" ||
|
|
427
|
+
false;
|
|
428
|
+
const targetWireStr = dropzoneElem.getAttribute("data-dropzone-wire");
|
|
429
|
+
const targetWire =
|
|
430
|
+
targetWireStr != null ? parseInt(targetWireStr) : null;
|
|
431
|
+
|
|
432
|
+
if (
|
|
433
|
+
targetLoc == null ||
|
|
434
|
+
targetWire == null ||
|
|
435
|
+
this.selectedOperation == null
|
|
436
|
+
)
|
|
437
|
+
return;
|
|
438
|
+
const sourceLocation = getGateLocationString(this.selectedOperation);
|
|
439
|
+
|
|
440
|
+
if (sourceLocation == null) {
|
|
441
|
+
if (
|
|
442
|
+
this.selectedOperation.params != undefined &&
|
|
443
|
+
(this.selectedOperation.args === undefined ||
|
|
444
|
+
this.selectedOperation.args.length === 0)
|
|
445
|
+
) {
|
|
446
|
+
// Prompt for arguments and wait for user input
|
|
447
|
+
const args = await promptForArguments(
|
|
448
|
+
this.selectedOperation.params,
|
|
449
|
+
);
|
|
450
|
+
if (!args || args.length === 0) {
|
|
451
|
+
// User canceled the prompt, exit early
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Create a deep copy of the source operation
|
|
456
|
+
this.selectedOperation = JSON.parse(
|
|
457
|
+
JSON.stringify(this.selectedOperation),
|
|
458
|
+
);
|
|
459
|
+
if (this.selectedOperation == null) return;
|
|
460
|
+
|
|
461
|
+
// Assign the arguments to the selected operation
|
|
462
|
+
this.selectedOperation.args = args;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Add a new operation from the toolbox
|
|
466
|
+
addOperation(
|
|
467
|
+
this,
|
|
468
|
+
this.selectedOperation,
|
|
469
|
+
targetLoc,
|
|
470
|
+
targetWire,
|
|
471
|
+
insertNewColumn,
|
|
472
|
+
);
|
|
473
|
+
} else if (sourceLocation && this.selectedWire != null) {
|
|
474
|
+
if (copying) {
|
|
475
|
+
if (
|
|
476
|
+
this.movingControl &&
|
|
477
|
+
this.selectedOperation.kind === "unitary"
|
|
478
|
+
) {
|
|
479
|
+
addControl(this.selectedOperation, targetWire);
|
|
480
|
+
moveOperation(
|
|
481
|
+
this,
|
|
482
|
+
sourceLocation,
|
|
483
|
+
targetLoc,
|
|
484
|
+
this.selectedWire,
|
|
485
|
+
targetWire,
|
|
486
|
+
false,
|
|
487
|
+
insertNewColumn,
|
|
488
|
+
);
|
|
489
|
+
} else {
|
|
490
|
+
addOperation(
|
|
491
|
+
this,
|
|
492
|
+
this.selectedOperation,
|
|
493
|
+
targetLoc,
|
|
494
|
+
targetWire,
|
|
495
|
+
insertNewColumn,
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
} else {
|
|
499
|
+
moveOperation(
|
|
500
|
+
this,
|
|
501
|
+
sourceLocation,
|
|
502
|
+
targetLoc,
|
|
503
|
+
this.selectedWire,
|
|
504
|
+
targetWire,
|
|
505
|
+
this.movingControl,
|
|
506
|
+
insertNewColumn,
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
this.selectedWire = null;
|
|
512
|
+
this.selectedOperation = null;
|
|
513
|
+
this.movingControl = false;
|
|
514
|
+
|
|
515
|
+
if (isEqual(originalGrid, this.componentGrid) === false)
|
|
516
|
+
this.renderFn();
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Add event listeners for the buttons to add or remove qubit lines.
|
|
523
|
+
* The add button will append a new qubit line to the circuit.
|
|
524
|
+
* The remove button will remove the last qubit line from the circuit,
|
|
525
|
+
* along with any operations associated with it.
|
|
526
|
+
*/
|
|
527
|
+
_addQubitLineControlEvents() {
|
|
528
|
+
const addQubitLineButton = this.container.querySelector(".add-qubit-line");
|
|
529
|
+
const removeQubitLineButton =
|
|
530
|
+
this.container.querySelector(".remove-qubit-line");
|
|
531
|
+
|
|
532
|
+
if (
|
|
533
|
+
addQubitLineButton &&
|
|
534
|
+
!addQubitLineButton.hasAttribute("data-event-added")
|
|
535
|
+
) {
|
|
536
|
+
addQubitLineButton.addEventListener("click", () => {
|
|
537
|
+
this.qubits.push({ id: this.qubits.length });
|
|
538
|
+
this.renderFn();
|
|
539
|
+
});
|
|
540
|
+
addQubitLineButton.setAttribute("data-event-added", "true");
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (
|
|
544
|
+
removeQubitLineButton &&
|
|
545
|
+
!removeQubitLineButton.hasAttribute("data-event-added")
|
|
546
|
+
) {
|
|
547
|
+
removeQubitLineButton.addEventListener("click", () => {
|
|
548
|
+
// Determines if the operation is associated with the last qubit line
|
|
549
|
+
const check = (op: Operation) => {
|
|
550
|
+
const targets = op.kind === "measurement" ? op.results : op.targets;
|
|
551
|
+
if (targets.some((reg) => reg.qubit == this.qubits.length - 1)) {
|
|
552
|
+
return true;
|
|
553
|
+
}
|
|
554
|
+
const controls =
|
|
555
|
+
op.kind === "measurement"
|
|
556
|
+
? op.qubits
|
|
557
|
+
: op.kind === "ket"
|
|
558
|
+
? []
|
|
559
|
+
: op.controls;
|
|
560
|
+
if (
|
|
561
|
+
controls &&
|
|
562
|
+
controls.some((reg) => reg.qubit == this.qubits.length - 1)
|
|
563
|
+
) {
|
|
564
|
+
return true;
|
|
565
|
+
}
|
|
566
|
+
return false;
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
// Count number of operations associated with the last qubit line
|
|
570
|
+
const numOperations = this.componentGrid.reduce(
|
|
571
|
+
(acc, column) =>
|
|
572
|
+
acc + column.components.filter((op) => check(op)).length,
|
|
573
|
+
0,
|
|
574
|
+
);
|
|
575
|
+
if (numOperations === 0) {
|
|
576
|
+
this.qubits.pop();
|
|
577
|
+
this.renderFn();
|
|
578
|
+
} else {
|
|
579
|
+
const message =
|
|
580
|
+
numOperations === 1
|
|
581
|
+
? `There is ${numOperations} operation associated with the last qubit line. Do you want to remove it?`
|
|
582
|
+
: `There are ${numOperations} operations associated with the last qubit line. Do you want to remove them?`;
|
|
583
|
+
_createConfirmPrompt(message, (confirmed) => {
|
|
584
|
+
if (confirmed) {
|
|
585
|
+
// Remove all operations associated with the last qubit line
|
|
586
|
+
findAndRemoveOperations(this.componentGrid, check);
|
|
587
|
+
this.qubits.pop();
|
|
588
|
+
this.renderFn();
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
removeQubitLineButton.setAttribute("data-event-added", "true");
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/*****************
|
|
598
|
+
* Misc. *
|
|
599
|
+
*****************/
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Creates a ghost element for visual feedback during dragging.
|
|
603
|
+
* This function initializes the dragging state, enables auto-scrolling,
|
|
604
|
+
* and creates a visual representation of the selected operation.
|
|
605
|
+
*
|
|
606
|
+
* @param ev - The mouse event that triggered the creation of the ghost element.
|
|
607
|
+
*/
|
|
608
|
+
_createGhostElement(ev: MouseEvent) {
|
|
609
|
+
if (this.selectedOperation == null) return;
|
|
610
|
+
this.dragging = true;
|
|
611
|
+
this._enableAutoScroll();
|
|
612
|
+
createGhostElement(
|
|
613
|
+
ev,
|
|
614
|
+
this.container,
|
|
615
|
+
this.selectedOperation,
|
|
616
|
+
this.movingControl,
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Start the process of adding a control to the selected operation.
|
|
622
|
+
* This function creates dropzones for each wire that isn't already a target or control.
|
|
623
|
+
*
|
|
624
|
+
* @param selectedOperation - The unitary operation to which the control will be added.
|
|
625
|
+
* @param selectedLocation - The location string of the selected operation.
|
|
626
|
+
*/
|
|
627
|
+
_startAddingControl(selectedOperation: Unitary, selectedLocation: string) {
|
|
628
|
+
this.selectedOperation = selectedOperation;
|
|
629
|
+
this.container.classList.add("adding-control");
|
|
630
|
+
|
|
631
|
+
// Create dropzones for each wire that isn't already a target or control
|
|
632
|
+
for (let wireIndex = 0; wireIndex < this.wireData.length; wireIndex++) {
|
|
633
|
+
const isTarget = this.selectedOperation?.targets.some(
|
|
634
|
+
(target) => target.qubit === wireIndex,
|
|
635
|
+
);
|
|
636
|
+
const isControl = this.selectedOperation?.controls?.some(
|
|
637
|
+
(control) => control.qubit === wireIndex,
|
|
638
|
+
);
|
|
639
|
+
|
|
640
|
+
if (!isTarget && !isControl) {
|
|
641
|
+
const dropzone = createWireDropzone(
|
|
642
|
+
this.circuitSvg,
|
|
643
|
+
this.wireData,
|
|
644
|
+
wireIndex,
|
|
645
|
+
);
|
|
646
|
+
dropzone.addEventListener("mousedown", (ev: MouseEvent) =>
|
|
647
|
+
ev.stopPropagation(),
|
|
648
|
+
);
|
|
649
|
+
dropzone.addEventListener("click", () => {
|
|
650
|
+
if (
|
|
651
|
+
this.selectedOperation != null &&
|
|
652
|
+
this.selectedOperation.kind === "unitary"
|
|
653
|
+
) {
|
|
654
|
+
const successful = addControl(this.selectedOperation, wireIndex);
|
|
655
|
+
this.selectedOperation = null;
|
|
656
|
+
this.container.classList.remove("adding-control");
|
|
657
|
+
if (successful) {
|
|
658
|
+
const indexes = locationStringToIndexes(selectedLocation);
|
|
659
|
+
const [columnIndex, position] = indexes[indexes.length - 1];
|
|
660
|
+
const selectedOperationParent = findParentArray(
|
|
661
|
+
this.componentGrid,
|
|
662
|
+
selectedLocation,
|
|
663
|
+
);
|
|
664
|
+
if (!selectedOperationParent) return;
|
|
665
|
+
|
|
666
|
+
const [minTarget, maxTarget] = getMinMaxRegIdx(
|
|
667
|
+
selectedOperation,
|
|
668
|
+
this.wireData.length,
|
|
669
|
+
);
|
|
670
|
+
selectedOperationParent[columnIndex].components.forEach(
|
|
671
|
+
(op, opIndex) => {
|
|
672
|
+
if (opIndex === position) return; // Don't check the selected operation against itself
|
|
673
|
+
const [minOp, maxOp] = getMinMaxRegIdx(
|
|
674
|
+
op,
|
|
675
|
+
this.wireData.length,
|
|
676
|
+
);
|
|
677
|
+
// Check if selectedOperation's range overlaps with op's range
|
|
678
|
+
if (
|
|
679
|
+
(minOp >= minTarget && minOp <= maxTarget) ||
|
|
680
|
+
(maxOp >= minTarget && maxOp <= maxTarget) ||
|
|
681
|
+
(minTarget >= minOp && minTarget <= minOp) ||
|
|
682
|
+
(maxTarget >= maxOp && maxTarget <= maxOp)
|
|
683
|
+
) {
|
|
684
|
+
// If they overlap, move the operation
|
|
685
|
+
selectedOperationParent[columnIndex].components.splice(
|
|
686
|
+
position,
|
|
687
|
+
1,
|
|
688
|
+
);
|
|
689
|
+
// Not sure if this check is needed as we already know there
|
|
690
|
+
// should be other operations in this column.
|
|
691
|
+
if (
|
|
692
|
+
selectedOperationParent[columnIndex].components.length ===
|
|
693
|
+
0
|
|
694
|
+
) {
|
|
695
|
+
selectedOperationParent.splice(columnIndex, 1);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
selectedOperationParent.splice(columnIndex, 0, {
|
|
699
|
+
components: [selectedOperation],
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
},
|
|
703
|
+
);
|
|
704
|
+
|
|
705
|
+
this.renderFn();
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
this.circuitSvg.appendChild(dropzone);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Start the process of removing a control from the selected operation.
|
|
716
|
+
* This function creates dropzones only for wires that the selected operation has a control.
|
|
717
|
+
*
|
|
718
|
+
* @param selectedOperation - The unitary operation from which the control will be removed.
|
|
719
|
+
*/
|
|
720
|
+
_startRemovingControl(selectedOperation: Unitary) {
|
|
721
|
+
this.selectedOperation = selectedOperation;
|
|
722
|
+
this.container.classList.add("removing-control");
|
|
723
|
+
|
|
724
|
+
// Create dropzones only for wires that the selectedOperation has a control
|
|
725
|
+
this.selectedOperation.controls?.forEach((control) => {
|
|
726
|
+
const dropzone = createWireDropzone(
|
|
727
|
+
this.circuitSvg,
|
|
728
|
+
this.wireData,
|
|
729
|
+
control.qubit,
|
|
730
|
+
);
|
|
731
|
+
dropzone.addEventListener("mousedown", (ev: MouseEvent) =>
|
|
732
|
+
ev.stopPropagation(),
|
|
733
|
+
);
|
|
734
|
+
dropzone.addEventListener("click", () => {
|
|
735
|
+
if (
|
|
736
|
+
this.selectedOperation != null &&
|
|
737
|
+
this.selectedOperation.kind === "unitary"
|
|
738
|
+
) {
|
|
739
|
+
const successful = removeControl(
|
|
740
|
+
this.selectedOperation,
|
|
741
|
+
control.qubit,
|
|
742
|
+
);
|
|
743
|
+
this.selectedOperation = null;
|
|
744
|
+
this.container.classList.remove("removing-control");
|
|
745
|
+
if (successful) {
|
|
746
|
+
this.renderFn();
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
this.circuitSvg.appendChild(dropzone);
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Create a confirm dialog box
|
|
757
|
+
* @param message - The message to display in the confirm dialog
|
|
758
|
+
* @param callback - The callback function to handle the user's response (true for OK, false for Cancel)
|
|
759
|
+
*/
|
|
760
|
+
const _createConfirmPrompt = (
|
|
761
|
+
message: string,
|
|
762
|
+
callback: (confirmed: boolean) => void,
|
|
763
|
+
) => {
|
|
764
|
+
// Create the confirm overlay
|
|
765
|
+
const overlay = document.createElement("div");
|
|
766
|
+
overlay.classList.add("prompt-overlay");
|
|
767
|
+
overlay.addEventListener("contextmenu", (e) => {
|
|
768
|
+
e.preventDefault();
|
|
769
|
+
e.stopPropagation();
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
// Create the confirm container
|
|
773
|
+
const confirmContainer = document.createElement("div");
|
|
774
|
+
confirmContainer.classList.add("prompt-container");
|
|
775
|
+
|
|
776
|
+
// Create the message element
|
|
777
|
+
const messageElem = document.createElement("div");
|
|
778
|
+
messageElem.classList.add("prompt-message");
|
|
779
|
+
messageElem.textContent = message;
|
|
780
|
+
|
|
781
|
+
// Create the buttons container
|
|
782
|
+
const buttonsContainer = document.createElement("div");
|
|
783
|
+
buttonsContainer.classList.add("prompt-buttons");
|
|
784
|
+
|
|
785
|
+
// Create the OK button
|
|
786
|
+
const okButton = document.createElement("button");
|
|
787
|
+
okButton.classList.add("prompt-button");
|
|
788
|
+
okButton.textContent = "OK";
|
|
789
|
+
okButton.addEventListener("click", () => {
|
|
790
|
+
callback(true); // User confirmed
|
|
791
|
+
document.body.removeChild(overlay);
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
// Create the Cancel button
|
|
795
|
+
const cancelButton = document.createElement("button");
|
|
796
|
+
cancelButton.classList.add("prompt-button");
|
|
797
|
+
cancelButton.textContent = "Cancel";
|
|
798
|
+
cancelButton.addEventListener("click", () => {
|
|
799
|
+
callback(false); // User canceled
|
|
800
|
+
document.body.removeChild(overlay);
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
buttonsContainer.appendChild(okButton);
|
|
804
|
+
buttonsContainer.appendChild(cancelButton);
|
|
805
|
+
|
|
806
|
+
confirmContainer.appendChild(messageElem);
|
|
807
|
+
confirmContainer.appendChild(buttonsContainer);
|
|
808
|
+
|
|
809
|
+
overlay.appendChild(confirmContainer);
|
|
810
|
+
document.body.appendChild(overlay);
|
|
811
|
+
|
|
812
|
+
// Remove focus from any currently focused element
|
|
813
|
+
if (document.activeElement) {
|
|
814
|
+
(document.activeElement as HTMLElement).blur();
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
export { enableEvents, CircuitEvents };
|