qsharp-lang 1.22.4-dev → 1.22.5-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/data-structures/circuit.d.ts +6 -1
- package/docs/Microsoft.Quantum.Core/IsRangeEmpty.md +1 -1
- package/docs/Microsoft.Quantum.Core/Length.md +1 -1
- package/docs/Microsoft.Quantum.Core/RangeEnd.md +1 -1
- package/docs/Microsoft.Quantum.Core/RangeStart.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/ApplyOperationPowerA.md +1 -1
- package/docs/Std.Canon/ApplyOperationPowerCA.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/ApplyQPE.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/MapPauliAxis.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/BigIntAsInt.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/Complex.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/ConfigureQubitLoss.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/SX.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/RoundHalfAwayFromZero.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/IsLossResult.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/MResetZChecked.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/EnableMemoryComputeArchitecture.md +1 -1
- package/docs/Std.ResourceEstimation/EndEstimateCaching.md +1 -1
- package/docs/Std.ResourceEstimation/EndRepeatEstimates.md +1 -1
- package/docs/Std.ResourceEstimation/LeastFrequentlyUsed.md +1 -1
- package/docs/Std.ResourceEstimation/LeastRecentlyUsed.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/nodejs/qsc_wasm.cjs +81 -81
- package/lib/nodejs/qsc_wasm.d.cts +2 -1
- package/lib/nodejs/qsc_wasm_bg.wasm +0 -0
- package/lib/web/qsc_wasm.d.ts +2 -1
- package/lib/web/qsc_wasm.js +74 -74
- package/lib/web/qsc_wasm_bg.wasm +0 -0
- package/package.json +1 -1
- package/ux/atoms/controls.ts +216 -0
- package/ux/atoms/index.css +226 -0
- package/ux/atoms/index.ts +192 -0
- package/ux/atoms/layout.ts +730 -0
- package/ux/atoms/utils.ts +32 -0
- package/ux/chem/index.tsx +191 -0
- package/ux/chem/style.css +83 -0
- package/ux/circuit-vis/events.ts +1 -5
- package/ux/circuit-vis/formatters/gateFormatter.ts +1 -1
- package/ux/circuit-vis/process.ts +13 -5
- package/ux/circuit-vis/sqore.ts +10 -8
- package/ux/index.ts +2 -0
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
import { appendChildren, createSvgElements, setAttributes } from "./utils.js";
|
|
5
|
+
|
|
6
|
+
// Zones will be rendered from top to bottom in array order
|
|
7
|
+
type ZoneData = {
|
|
8
|
+
title: string;
|
|
9
|
+
rows: number;
|
|
10
|
+
kind: "register" | "interaction" | "measurement";
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type ZoneLayout = {
|
|
14
|
+
cols: number;
|
|
15
|
+
zones: ZoneData[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type TraceData = {
|
|
19
|
+
metadata: any;
|
|
20
|
+
qubits: Array<[number, number]>;
|
|
21
|
+
steps: Array<{
|
|
22
|
+
id: string | number;
|
|
23
|
+
ops: Array<string>;
|
|
24
|
+
}>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// const exampleLayout: ZoneLayout = {
|
|
28
|
+
// "cols": 36,
|
|
29
|
+
// "zones": [
|
|
30
|
+
// { "title": "Register 1", "rows": 17, "kind": "register" },
|
|
31
|
+
// { "title": "Interaction Zone", "rows": 4, "kind": "interaction" },
|
|
32
|
+
// { "title": "Register 2", "rows": 17, "kind": "register" },
|
|
33
|
+
// { "title": "Measurement Zone", "rows": 4, "kind": "measurement" },
|
|
34
|
+
// ],
|
|
35
|
+
// };
|
|
36
|
+
|
|
37
|
+
type Location = [number, number, SVGElement?];
|
|
38
|
+
|
|
39
|
+
const qubitSize = 10;
|
|
40
|
+
const zoneSpacing = 8;
|
|
41
|
+
const colPadding = 20;
|
|
42
|
+
const initialScale = 1.5;
|
|
43
|
+
const scaleStep = 0.15;
|
|
44
|
+
const speedStep = 0.75;
|
|
45
|
+
const zoneBoxCornerRadius = 3;
|
|
46
|
+
const doublonCornerRadius = 5;
|
|
47
|
+
|
|
48
|
+
// Used when no trace data is provided to fill the qubit mappings, assuming all register
|
|
49
|
+
// zones are populated with sequentially numbered qubit ids from the top left to the bottom right.
|
|
50
|
+
export function fillQubitLocations(
|
|
51
|
+
layout: ZoneLayout,
|
|
52
|
+
): Array<[number, number]> {
|
|
53
|
+
const qubits: Array<[number, number]> = [];
|
|
54
|
+
let currRow = 0;
|
|
55
|
+
layout.zones.forEach((zone) => {
|
|
56
|
+
for (let row = 0; row < zone.rows; ++row) {
|
|
57
|
+
if (zone.kind === "register") {
|
|
58
|
+
for (let col = 0; col < layout.cols; ++col) {
|
|
59
|
+
qubits.push([currRow, col]);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
++currRow;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return qubits;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function parseMove(op: string): { qubit: number; to: Location } | undefined {
|
|
70
|
+
const match = op.match(/move\((\d+), (\d+)\) (\d+)/);
|
|
71
|
+
if (match) {
|
|
72
|
+
const to: Location = [parseInt(match[1]), parseInt(match[2])];
|
|
73
|
+
return { qubit: parseInt(match[3]), to };
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function parseGate(
|
|
79
|
+
op: string,
|
|
80
|
+
): { gate: string; qubit: number; arg?: string } | undefined {
|
|
81
|
+
const match = op.match(/(\w+)\s*(\(.*\))? (\d+)/);
|
|
82
|
+
if (match) {
|
|
83
|
+
const gate = match[1];
|
|
84
|
+
const qubit = parseInt(match[3]);
|
|
85
|
+
const arg = match[2]
|
|
86
|
+
? match[2].substring(1, match[2].length - 2)
|
|
87
|
+
: undefined;
|
|
88
|
+
return { gate, qubit, arg };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/*
|
|
93
|
+
We want to build up a cache of the qubit location at each 'n' steps so that scrubbing is fast.
|
|
94
|
+
Storing for each step is too large for the number of steps we want to handle. Also, the building
|
|
95
|
+
of the cache can take a long time, so we want to chunk it up to avoid blocking the UI thread.
|
|
96
|
+
*/
|
|
97
|
+
function TraceToGetLayoutFn(trace: TraceData) {
|
|
98
|
+
const STEP_SIZE = 100; // How many steps between each cache entry
|
|
99
|
+
|
|
100
|
+
const cacheEntries = Math.ceil(trace.steps.length / STEP_SIZE);
|
|
101
|
+
const entrySize = trace.qubits.length * 2; // row and col for each qubit
|
|
102
|
+
const cache = new Uint16Array(cacheEntries * entrySize);
|
|
103
|
+
|
|
104
|
+
// Fill initial locations
|
|
105
|
+
trace.qubits.forEach((loc, idx) => {
|
|
106
|
+
cache[idx * 2] = loc[0];
|
|
107
|
+
cache[idx * 2 + 1] = loc[1];
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
let lastIndexProcessed = 0;
|
|
111
|
+
|
|
112
|
+
// Update the layout (which should be the prior step layout)
|
|
113
|
+
function getNextStepLayout(stepIndex: number, layout: Uint16Array) {
|
|
114
|
+
if (stepIndex <= 0 || stepIndex >= trace.steps.length) {
|
|
115
|
+
throw "Step out of range";
|
|
116
|
+
}
|
|
117
|
+
// Extract the move operations in the prior step, to apply to the prior layout
|
|
118
|
+
const moves = trace.steps[stepIndex - 1].ops
|
|
119
|
+
.map(parseMove)
|
|
120
|
+
.filter((x) => x != undefined);
|
|
121
|
+
|
|
122
|
+
// Then apply them to the layout
|
|
123
|
+
moves.forEach((move) => {
|
|
124
|
+
layout[move.qubit * 2] = move.to[0];
|
|
125
|
+
layout[move.qubit * 2 + 1] = move.to[1];
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// syncRunToIndex is used to force processing up to a certain index synchronously, such as
|
|
130
|
+
// when the user is scrubbing to a point not yet processed asynchronously.
|
|
131
|
+
function processChunk(syncRunToIndex = 0) {
|
|
132
|
+
if (lastIndexProcessed >= cacheEntries - 1) {
|
|
133
|
+
return; // Done
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const startPriorIndex = lastIndexProcessed * entrySize;
|
|
137
|
+
const startIndex = (lastIndexProcessed + 1) * entrySize;
|
|
138
|
+
|
|
139
|
+
// Copy to the next entry as the starting point
|
|
140
|
+
cache.copyWithin(startIndex, startPriorIndex, startPriorIndex + entrySize);
|
|
141
|
+
const targetSlice = cache.subarray(startIndex, startIndex + entrySize);
|
|
142
|
+
|
|
143
|
+
// Run each step in the chunk and apply the moves to the cache
|
|
144
|
+
for (let stepOffset = 1; stepOffset <= STEP_SIZE; ++stepOffset) {
|
|
145
|
+
const stepIndex = lastIndexProcessed * STEP_SIZE + stepOffset;
|
|
146
|
+
if (stepIndex >= trace.steps.length) break;
|
|
147
|
+
getNextStepLayout(stepIndex, targetSlice);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Queue up the next chunk
|
|
151
|
+
++lastIndexProcessed;
|
|
152
|
+
if (syncRunToIndex > 0) {
|
|
153
|
+
// Process synchronously up to the requested index if not done yet
|
|
154
|
+
if (lastIndexProcessed < syncRunToIndex) processChunk(syncRunToIndex);
|
|
155
|
+
} else {
|
|
156
|
+
// Process the next chunk asynchronously
|
|
157
|
+
setTimeout(processChunk, 0);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Kick off the async processing
|
|
161
|
+
processChunk();
|
|
162
|
+
|
|
163
|
+
// When a layout is requested for a step, cache the response. Most of the time the following
|
|
164
|
+
// step will be requested next, so we can easily just apply one set of moves to the prior layout.
|
|
165
|
+
let lastRequestedStep = -1;
|
|
166
|
+
const lastLayout = new Uint16Array(entrySize);
|
|
167
|
+
|
|
168
|
+
function getLayoutAtStep(step: number): Uint16Array {
|
|
169
|
+
if (step < 0 || step >= trace.steps.length) {
|
|
170
|
+
throw "Step out of range";
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// If the cache hasn't processed up to the required step, do so now
|
|
174
|
+
if (step >= (lastIndexProcessed + 1) * STEP_SIZE) {
|
|
175
|
+
const entryIndex = Math.floor(step / STEP_SIZE);
|
|
176
|
+
processChunk(entryIndex);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// If the step exactly matches a cache entry, return that
|
|
180
|
+
if (step % STEP_SIZE === 0) {
|
|
181
|
+
const entryIndex = step / STEP_SIZE;
|
|
182
|
+
const startIndex = entryIndex * entrySize;
|
|
183
|
+
lastLayout.set(cache.subarray(startIndex, startIndex + entrySize));
|
|
184
|
+
lastRequestedStep = step;
|
|
185
|
+
return lastLayout;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// If the same as the last requested step, just return the cached layout
|
|
189
|
+
if (step === lastRequestedStep) {
|
|
190
|
+
return lastLayout;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Otherwise, if the last requested step was the prior step, just apply the moves
|
|
194
|
+
if (step === lastRequestedStep + 1) {
|
|
195
|
+
getNextStepLayout(step, lastLayout);
|
|
196
|
+
++lastRequestedStep;
|
|
197
|
+
return lastLayout;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Otherwise, find the nearest prior cache entry and apply moves from there
|
|
201
|
+
const entryIndex = Math.floor(step / STEP_SIZE);
|
|
202
|
+
const startIndex = entryIndex * entrySize;
|
|
203
|
+
lastLayout.set(cache.subarray(startIndex, startIndex + entrySize));
|
|
204
|
+
for (
|
|
205
|
+
let stepIndex = entryIndex * STEP_SIZE + 1;
|
|
206
|
+
stepIndex <= step;
|
|
207
|
+
++stepIndex
|
|
208
|
+
) {
|
|
209
|
+
getNextStepLayout(stepIndex, lastLayout);
|
|
210
|
+
}
|
|
211
|
+
lastRequestedStep = step;
|
|
212
|
+
return lastLayout;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return getLayoutAtStep;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export class Layout {
|
|
219
|
+
container: SVGSVGElement;
|
|
220
|
+
width: number;
|
|
221
|
+
height: number;
|
|
222
|
+
scale: number = initialScale;
|
|
223
|
+
qubits: Location[];
|
|
224
|
+
rowOffset: number[];
|
|
225
|
+
currentStep = 0;
|
|
226
|
+
trackParent: SVGGElement;
|
|
227
|
+
activeGates: SVGElement[] = [];
|
|
228
|
+
trace: TraceData;
|
|
229
|
+
getStepLayout: (step: number) => Uint16Array;
|
|
230
|
+
showTracks = true;
|
|
231
|
+
showDottedPath = true;
|
|
232
|
+
stepInterval = 500; // Used for playing and animations
|
|
233
|
+
|
|
234
|
+
constructor(
|
|
235
|
+
public layout: ZoneLayout,
|
|
236
|
+
trace: TraceData,
|
|
237
|
+
) {
|
|
238
|
+
if (!trace.qubits?.length) {
|
|
239
|
+
trace.qubits = fillQubitLocations(layout);
|
|
240
|
+
}
|
|
241
|
+
this.trace = trace;
|
|
242
|
+
this.getStepLayout = TraceToGetLayoutFn(trace);
|
|
243
|
+
|
|
244
|
+
this.qubits = structuredClone(trace.qubits);
|
|
245
|
+
|
|
246
|
+
this.container = document.createElementNS(
|
|
247
|
+
"http://www.w3.org/2000/svg",
|
|
248
|
+
"svg",
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const totalRows = layout.zones.reduce((prev, curr) => prev + curr.rows, 0);
|
|
252
|
+
|
|
253
|
+
this.height =
|
|
254
|
+
totalRows * qubitSize + zoneSpacing * (layout.zones.length + 1);
|
|
255
|
+
this.width = layout.cols * qubitSize + colPadding;
|
|
256
|
+
|
|
257
|
+
setAttributes(this.container, {
|
|
258
|
+
viewBox: `-5 0 ${this.width} ${this.height}`,
|
|
259
|
+
width: `${this.width * this.scale}px`,
|
|
260
|
+
height: `${this.height * this.scale}px`,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// Loop through the zones, calculating the row offsets, and rendering the zones
|
|
264
|
+
this.rowOffset = [];
|
|
265
|
+
let nextOffset = zoneSpacing;
|
|
266
|
+
let nextRowNum = 0;
|
|
267
|
+
layout.zones.forEach((zone, index) => {
|
|
268
|
+
this.renderZone(index, nextOffset, nextRowNum);
|
|
269
|
+
for (let i = 0; i < zone.rows; ++i) {
|
|
270
|
+
this.rowOffset.push(nextOffset);
|
|
271
|
+
nextOffset += qubitSize;
|
|
272
|
+
++nextRowNum;
|
|
273
|
+
}
|
|
274
|
+
nextOffset += zoneSpacing; // Add spacing after each zone
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
const colNumOffset = nextOffset - 8;
|
|
278
|
+
this.renderColNums(layout.cols, colNumOffset);
|
|
279
|
+
|
|
280
|
+
// Put the track parent before the qubits, so the qubits render on top
|
|
281
|
+
this.trackParent = createSvgElements("g")[0] as SVGGElement;
|
|
282
|
+
|
|
283
|
+
this.trackParent.addEventListener("mouseover", (e) => {
|
|
284
|
+
const t = e.target as SVGElement;
|
|
285
|
+
if (t && t.dataset.qubitid) {
|
|
286
|
+
const qubitId = parseInt(t.dataset.qubitid);
|
|
287
|
+
this.highlightQubit(qubitId);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
this.trackParent.addEventListener("mouseout", () => {
|
|
291
|
+
this.highlightQubit(null);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
appendChildren(this.container, [this.trackParent]);
|
|
295
|
+
|
|
296
|
+
this.renderQubits();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
private highlightQubit(qubit: number | null) {
|
|
300
|
+
if (qubit === null || qubit < 0 || qubit >= this.qubits.length) {
|
|
301
|
+
this.container
|
|
302
|
+
.querySelectorAll(".qs-atoms-qubit-highlight")
|
|
303
|
+
.forEach((elem) => {
|
|
304
|
+
elem.classList.remove("qs-atoms-qubit-highlight");
|
|
305
|
+
});
|
|
306
|
+
} else {
|
|
307
|
+
this.container
|
|
308
|
+
.querySelectorAll(`[data-qubitId="${qubit}"]`)
|
|
309
|
+
.forEach((elem) => {
|
|
310
|
+
elem.classList.add("qs-atoms-qubit-highlight");
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
private getOpsAtStep(step: number) {
|
|
316
|
+
if (step < 0 || step >= this.trace.steps.length) {
|
|
317
|
+
throw "Step out of range";
|
|
318
|
+
}
|
|
319
|
+
return this.trace.steps[step].ops;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private renderZone(zoneIndex: number, offset: number, firstRowNum = 0) {
|
|
323
|
+
const zoneData = this.layout.zones[zoneIndex];
|
|
324
|
+
const g = createSvgElements("g")[0];
|
|
325
|
+
setAttributes(g, {
|
|
326
|
+
transform: `translate(0 ${offset})`,
|
|
327
|
+
class: "qs-atoms-zonebox",
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
if (zoneData.kind !== "interaction") {
|
|
331
|
+
// For non-interaction zones we draw one big rounded rectangle with lines between qubit rows & cols
|
|
332
|
+
const rect = createSvgElements("rect")[0];
|
|
333
|
+
setAttributes(rect, {
|
|
334
|
+
x: "0",
|
|
335
|
+
y: "0",
|
|
336
|
+
width: `${this.layout.cols * qubitSize}`,
|
|
337
|
+
height: `${zoneData.rows * qubitSize}`,
|
|
338
|
+
rx: `${zoneBoxCornerRadius}`,
|
|
339
|
+
});
|
|
340
|
+
appendChildren(g, [rect]);
|
|
341
|
+
|
|
342
|
+
// Draw the lines between the rows
|
|
343
|
+
for (let i = 1; i < zoneData.rows; i++) {
|
|
344
|
+
const path = createSvgElements("path")[0];
|
|
345
|
+
setAttributes(path, {
|
|
346
|
+
d: `M 0,${i * qubitSize} h${this.layout.cols * qubitSize}`,
|
|
347
|
+
});
|
|
348
|
+
appendChildren(g, [path]);
|
|
349
|
+
}
|
|
350
|
+
// Draw the lines between the columns
|
|
351
|
+
for (let i = 1; i < this.layout.cols; i++) {
|
|
352
|
+
const path = createSvgElements("path")[0];
|
|
353
|
+
setAttributes(path, {
|
|
354
|
+
d: `M ${i * qubitSize},0 v${zoneData.rows * qubitSize}`,
|
|
355
|
+
});
|
|
356
|
+
appendChildren(g, [path]);
|
|
357
|
+
}
|
|
358
|
+
} else {
|
|
359
|
+
// For the interaction zone draw each doublon
|
|
360
|
+
for (let row = 0; row < zoneData.rows; ++row) {
|
|
361
|
+
for (let i = 0; i < this.layout.cols; i += 2) {
|
|
362
|
+
const rect = createSvgElements("rect")[0];
|
|
363
|
+
setAttributes(rect, {
|
|
364
|
+
x: `${i * qubitSize}`,
|
|
365
|
+
y: `${row * qubitSize}`,
|
|
366
|
+
width: `${qubitSize * 2}`,
|
|
367
|
+
height: `${qubitSize}`,
|
|
368
|
+
rx: `${doublonCornerRadius}`,
|
|
369
|
+
});
|
|
370
|
+
const path = createSvgElements("path")[0];
|
|
371
|
+
setAttributes(path, {
|
|
372
|
+
d: `M ${(i + 1) * qubitSize},${row * qubitSize} v${qubitSize}`,
|
|
373
|
+
});
|
|
374
|
+
appendChildren(g, [rect, path]);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Number the rows
|
|
380
|
+
for (let i = 0; i < zoneData.rows; ++i) {
|
|
381
|
+
const rowNum = firstRowNum + i;
|
|
382
|
+
const label = createSvgElements("text")[0];
|
|
383
|
+
setAttributes(label, {
|
|
384
|
+
x: `${this.layout.cols * qubitSize + 5}`,
|
|
385
|
+
y: `${i * qubitSize + 5}`,
|
|
386
|
+
class: "qs-atoms-label",
|
|
387
|
+
});
|
|
388
|
+
label.textContent = `${rowNum}`;
|
|
389
|
+
appendChildren(g, [label]);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Draw the title
|
|
393
|
+
const text = createSvgElements("text")[0];
|
|
394
|
+
setAttributes(text, {
|
|
395
|
+
x: "1",
|
|
396
|
+
y: "-1",
|
|
397
|
+
class: "qs-atoms-zone-text",
|
|
398
|
+
});
|
|
399
|
+
text.textContent = zoneData.title;
|
|
400
|
+
|
|
401
|
+
appendChildren(g, [text]);
|
|
402
|
+
appendChildren(this.container, [g]);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
private renderQubits() {
|
|
406
|
+
const elems = this.qubits.map((location, index) => {
|
|
407
|
+
const [x, y] = this.getQubitCenter(index);
|
|
408
|
+
|
|
409
|
+
// Safari has an issue animating multiple attributes concurrently, which we need
|
|
410
|
+
// to do to move the qubit (animate 'cx' and 'cy'), so instead set cx and cy to 0
|
|
411
|
+
// and position the qubit with a transform (see https://stackoverflow.com/a/72022385/1674945)
|
|
412
|
+
|
|
413
|
+
const circle = createSvgElements("circle")[0];
|
|
414
|
+
setAttributes(circle, {
|
|
415
|
+
cx: `0`,
|
|
416
|
+
cy: `0`,
|
|
417
|
+
r: `2`,
|
|
418
|
+
class: "qs-atoms-qubit",
|
|
419
|
+
"data-qubitid": `${index}`,
|
|
420
|
+
});
|
|
421
|
+
circle.addEventListener("mouseover", () => this.highlightQubit(index));
|
|
422
|
+
circle.addEventListener("mouseout", () => this.highlightQubit(null));
|
|
423
|
+
// Animation sets the transform as a style attribute, not an element attribute.
|
|
424
|
+
// Also note, when animating the CSS it requires the 'px' length type (unlike the attribute).
|
|
425
|
+
circle.style.transform = `translate(${x}px, ${y}px)`;
|
|
426
|
+
location[2] = circle;
|
|
427
|
+
return circle;
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
appendChildren(this.container, elems);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
private renderColNums(cols: number, offset: number) {
|
|
434
|
+
const g = createSvgElements("g")[0];
|
|
435
|
+
setAttributes(g, {
|
|
436
|
+
transform: `translate(0 ${offset})`,
|
|
437
|
+
});
|
|
438
|
+
// Number the columns
|
|
439
|
+
for (let i = 0; i < cols; ++i) {
|
|
440
|
+
const label = createSvgElements("text")[0];
|
|
441
|
+
setAttributes(label, {
|
|
442
|
+
x: `${i * qubitSize + 5}`,
|
|
443
|
+
y: `5`,
|
|
444
|
+
class: "qs-atoms-label",
|
|
445
|
+
});
|
|
446
|
+
label.textContent = `${i}`;
|
|
447
|
+
appendChildren(g, [label]);
|
|
448
|
+
}
|
|
449
|
+
appendChildren(this.container, [g]);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
renderGateOnQubit(qubit: number, gate: string, arg?: string) {
|
|
453
|
+
if (gate == "RESET") gate = "R";
|
|
454
|
+
const [x, y] = this.getQubitCenter(qubit);
|
|
455
|
+
|
|
456
|
+
const gateClass =
|
|
457
|
+
gate === "MZ"
|
|
458
|
+
? "qs-atoms-gate qs-atoms-gate-mz"
|
|
459
|
+
: gate === "R"
|
|
460
|
+
? "qs-atoms-gate qs-atoms-gate-reset"
|
|
461
|
+
: "qs-atoms-gate";
|
|
462
|
+
|
|
463
|
+
const g = createSvgElements("g")[0];
|
|
464
|
+
setAttributes(g, {
|
|
465
|
+
transform: `translate(${x - qubitSize / 2} ${y - qubitSize / 2})`,
|
|
466
|
+
class: "qs-atoms-gate",
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
if (gate === "CZ") {
|
|
470
|
+
// Render the rounded doublon box in a bright color and x--x inside
|
|
471
|
+
const [rect, path, leftDot, rightDot] = createSvgElements(
|
|
472
|
+
"rect",
|
|
473
|
+
"path",
|
|
474
|
+
"circle",
|
|
475
|
+
"circle",
|
|
476
|
+
);
|
|
477
|
+
setAttributes(rect, {
|
|
478
|
+
x: `0`,
|
|
479
|
+
y: "0",
|
|
480
|
+
width: `${qubitSize * 2}`,
|
|
481
|
+
height: `${qubitSize}`,
|
|
482
|
+
rx: `${doublonCornerRadius}`,
|
|
483
|
+
class: "qs-atoms-zonebox qs-atoms-gate-cz",
|
|
484
|
+
});
|
|
485
|
+
// <path d= "M45,5 h10" stroke-width="1.5" stroke="black"/>
|
|
486
|
+
// <circle cx="45" cy="5" r="2" stroke-width="0" fill="#123" />
|
|
487
|
+
// <circle cx="55" cy="5" r="2" stroke-width="0" fill="#123" />
|
|
488
|
+
setAttributes(path, {
|
|
489
|
+
fill: "none",
|
|
490
|
+
stroke: "black",
|
|
491
|
+
"stroke-width": "1.5",
|
|
492
|
+
d: "M5,5 h10",
|
|
493
|
+
});
|
|
494
|
+
setAttributes(leftDot, {
|
|
495
|
+
cx: "5",
|
|
496
|
+
cy: "5",
|
|
497
|
+
r: "2",
|
|
498
|
+
"stroke-width": "0",
|
|
499
|
+
fill: "#123",
|
|
500
|
+
});
|
|
501
|
+
setAttributes(rightDot, {
|
|
502
|
+
cx: "15",
|
|
503
|
+
cy: "5",
|
|
504
|
+
r: "2",
|
|
505
|
+
"stroke-width": "0",
|
|
506
|
+
fill: "#123",
|
|
507
|
+
});
|
|
508
|
+
appendChildren(g, [rect, path, leftDot, rightDot]);
|
|
509
|
+
} else {
|
|
510
|
+
const [rect, text] = createSvgElements("rect", "text");
|
|
511
|
+
setAttributes(rect, {
|
|
512
|
+
x: "0.5",
|
|
513
|
+
y: "0.5",
|
|
514
|
+
width: `${qubitSize - 1}`,
|
|
515
|
+
height: `${qubitSize - 1}`,
|
|
516
|
+
class: gateClass,
|
|
517
|
+
});
|
|
518
|
+
setAttributes(text, {
|
|
519
|
+
x: "5",
|
|
520
|
+
y: arg ? "2.75" : "5",
|
|
521
|
+
class: "qs-atoms-gate-text",
|
|
522
|
+
});
|
|
523
|
+
text.textContent = gate;
|
|
524
|
+
|
|
525
|
+
appendChildren(g, [rect, text]);
|
|
526
|
+
|
|
527
|
+
if (arg) {
|
|
528
|
+
const argText = createSvgElements("text")[0];
|
|
529
|
+
setAttributes(argText, {
|
|
530
|
+
x: "5",
|
|
531
|
+
y: "7",
|
|
532
|
+
class: "qs-atoms-gate-text qs-atoms-gate-text-small",
|
|
533
|
+
textLength: "8",
|
|
534
|
+
});
|
|
535
|
+
text.classList.add("qs-atoms-gate-text-small");
|
|
536
|
+
argText.textContent = arg;
|
|
537
|
+
appendChildren(g, [argText]);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
appendChildren(this.container, [g]);
|
|
542
|
+
this.activeGates.push(g);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
clearGates() {
|
|
546
|
+
this.activeGates.forEach((gate) => {
|
|
547
|
+
gate.parentElement?.removeChild(gate);
|
|
548
|
+
});
|
|
549
|
+
// TODO: Clear doublons too
|
|
550
|
+
this.activeGates = [];
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
zoomIn() {
|
|
554
|
+
this.scale += scaleStep * this.scale;
|
|
555
|
+
setAttributes(this.container, {
|
|
556
|
+
width: `${this.width * this.scale}px`,
|
|
557
|
+
height: `${this.height * this.scale}px`,
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
zoomOut() {
|
|
562
|
+
this.scale -= scaleStep * this.scale;
|
|
563
|
+
setAttributes(this.container, {
|
|
564
|
+
width: `${this.width * this.scale}px`,
|
|
565
|
+
height: `${this.height * this.scale}px`,
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
faster() {
|
|
570
|
+
this.stepInterval = this.stepInterval * speedStep;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
slower() {
|
|
574
|
+
this.stepInterval = this.stepInterval / speedStep;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
cycleAnimation() {
|
|
578
|
+
if (!this.showTracks) {
|
|
579
|
+
this.showTracks = true;
|
|
580
|
+
this.showDottedPath = true;
|
|
581
|
+
} else if (this.showTracks && this.showDottedPath) {
|
|
582
|
+
this.showDottedPath = false;
|
|
583
|
+
} else {
|
|
584
|
+
this.showTracks = false;
|
|
585
|
+
this.showDottedPath = false;
|
|
586
|
+
}
|
|
587
|
+
this.gotoStep(this.currentStep);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
getQubitRowOffset(row: number) {
|
|
591
|
+
return this.rowOffset[row];
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
getLocationCenter(row: number, col: number): [number, number] {
|
|
595
|
+
const x = col * qubitSize + qubitSize / 2;
|
|
596
|
+
const y = this.getQubitRowOffset(row) + qubitSize / 2;
|
|
597
|
+
return [x, y];
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
getQubitCenter(qubit: number): [number, number] {
|
|
601
|
+
if (this.qubits[qubit] == undefined) {
|
|
602
|
+
throw "Qubit not found";
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const [row, col] = this.qubits[qubit];
|
|
606
|
+
return this.getLocationCenter(row, col);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
gotoStep(step: number) {
|
|
610
|
+
// Remove prior rendering's gates, trails, or remaining animations
|
|
611
|
+
this.clearGates();
|
|
612
|
+
this.trackParent.replaceChildren();
|
|
613
|
+
this.container.getAnimations({ subtree: true }).forEach((anim) => {
|
|
614
|
+
anim.cancel();
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
const forwards = step > this.currentStep;
|
|
618
|
+
this.currentStep = step;
|
|
619
|
+
|
|
620
|
+
// When on step 0, just layout the qubits per index 0
|
|
621
|
+
// When on step 1, layout per index 0 then apply the gates/moves per index 0
|
|
622
|
+
// When on step 2, layout per index 1 then apply the gates/moves per index 1
|
|
623
|
+
// etc. until when on step n + 1, layout per index n and apply per index n
|
|
624
|
+
const qubitLocationIndex = step === 0 ? 0 : step - 1;
|
|
625
|
+
|
|
626
|
+
// Update all qubit locations
|
|
627
|
+
const qubitLayout = this.getStepLayout(qubitLocationIndex);
|
|
628
|
+
const qubitCount = qubitLayout.length / 2;
|
|
629
|
+
for (let idx = 0; idx < qubitCount; ++idx) {
|
|
630
|
+
const elem = this.qubits[idx][2];
|
|
631
|
+
if (elem === undefined) {
|
|
632
|
+
throw "Invalid qubit index in step";
|
|
633
|
+
}
|
|
634
|
+
const loc: Location = [qubitLayout[idx * 2], qubitLayout[idx * 2 + 1]];
|
|
635
|
+
this.qubits[idx] = [loc[0], loc[1], elem]; // Update the location
|
|
636
|
+
|
|
637
|
+
// Get the offset for the location and move it there
|
|
638
|
+
const [x, y] = this.getQubitCenter(idx);
|
|
639
|
+
elem.style.transform = `translate(${x}px, ${y}px)`;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// Now apply the ops
|
|
643
|
+
if (step > 0) {
|
|
644
|
+
const duration = forwards ? this.stepInterval / 2 : 0;
|
|
645
|
+
const ops = this.getOpsAtStep(qubitLocationIndex);
|
|
646
|
+
let trailId = 0;
|
|
647
|
+
ops.forEach((op) => {
|
|
648
|
+
const move = parseMove(op);
|
|
649
|
+
if (move) {
|
|
650
|
+
// Apply the move animation
|
|
651
|
+
const [oldX, oldY] = this.getQubitCenter(move.qubit);
|
|
652
|
+
const [newX, newY] = this.getLocationCenter(move.to[0], move.to[1]);
|
|
653
|
+
const qubit = this.qubits[move.qubit][2];
|
|
654
|
+
if (!qubit) throw "Invalid qubit index";
|
|
655
|
+
if (this.showTracks) {
|
|
656
|
+
if (this.showDottedPath) {
|
|
657
|
+
// Render a hollow circle at the start position
|
|
658
|
+
const [startCircle, trail] = createSvgElements("circle", "line");
|
|
659
|
+
setAttributes(startCircle, {
|
|
660
|
+
cx: `${oldX}`,
|
|
661
|
+
cy: `${oldY}`,
|
|
662
|
+
class: `qs-atoms-qubit-trail-start`,
|
|
663
|
+
"data-qubitid": `${move.qubit}`,
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
const id = `dotted-trail-${trailId++}`;
|
|
667
|
+
setAttributes(trail, {
|
|
668
|
+
id,
|
|
669
|
+
x1: `${oldX}`,
|
|
670
|
+
y1: `${oldY}`,
|
|
671
|
+
x2: `${newX}`,
|
|
672
|
+
y2: `${newY}`,
|
|
673
|
+
class: "qs-atoms-qubit-trail",
|
|
674
|
+
"data-qubitid": `${move.qubit}`,
|
|
675
|
+
});
|
|
676
|
+
appendChildren(this.trackParent, [trail, startCircle]);
|
|
677
|
+
} else {
|
|
678
|
+
const id = `gradient-${trailId++}`;
|
|
679
|
+
// Draw the path of any qubit movements
|
|
680
|
+
const [gradient, trail] = createSvgElements(
|
|
681
|
+
"linearGradient",
|
|
682
|
+
"line",
|
|
683
|
+
);
|
|
684
|
+
setAttributes(gradient, {
|
|
685
|
+
id,
|
|
686
|
+
gradientUnits: "userSpaceOnUse",
|
|
687
|
+
x1: `${oldX}`,
|
|
688
|
+
y1: `${oldY}`,
|
|
689
|
+
x2: `${newX}`,
|
|
690
|
+
y2: `${newY}`,
|
|
691
|
+
});
|
|
692
|
+
gradient.innerHTML = `<stop offset="0%" stop-color="gray" stop-opacity="0.2"/><stop offset="100%" stop-color="gray" stop-opacity="0.8"/>`;
|
|
693
|
+
setAttributes(trail, {
|
|
694
|
+
x1: `${oldX}`,
|
|
695
|
+
y1: `${oldY}`,
|
|
696
|
+
x2: `${newX}`,
|
|
697
|
+
y2: `${newY}`,
|
|
698
|
+
style: `stroke-width: 2px; stroke: url(#${id})`,
|
|
699
|
+
});
|
|
700
|
+
appendChildren(this.trackParent, [gradient, trail]);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
qubit
|
|
704
|
+
.animate(
|
|
705
|
+
[
|
|
706
|
+
{ transform: `translate(${oldX}px, ${oldY}px)` },
|
|
707
|
+
{ transform: `translate(${newX}px, ${newY}px)` },
|
|
708
|
+
],
|
|
709
|
+
{
|
|
710
|
+
duration: this.showDottedPath ? 50 : duration,
|
|
711
|
+
fill: "forwards",
|
|
712
|
+
easing: "ease",
|
|
713
|
+
},
|
|
714
|
+
)
|
|
715
|
+
.finished.then((anim) => {
|
|
716
|
+
anim.commitStyles();
|
|
717
|
+
anim.cancel();
|
|
718
|
+
});
|
|
719
|
+
// TODO: Check if you can/should cancel when scrubbing
|
|
720
|
+
} else {
|
|
721
|
+
// Wasn't a move, so render the gate
|
|
722
|
+
const gate = parseGate(op);
|
|
723
|
+
if (!gate) throw `Invalid gate: ${op}`;
|
|
724
|
+
const arg = gate.arg ? gate.arg.substring(0, 4) : undefined;
|
|
725
|
+
this.renderGateOnQubit(gate.qubit, gate.gate.toUpperCase(), arg);
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|