qsharp-lang 1.25.4-dev → 1.25.7-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/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 +1 -1
- package/lib/nodejs/qsc_wasm_bg.wasm +0 -0
- package/lib/web/qsc_wasm.js +1 -1
- package/lib/web/qsc_wasm_bg.wasm +0 -0
- package/package.json +2 -1
- package/ux/circuit-vis/angleExpression.ts +133 -0
- package/ux/circuit-vis/contextMenu.ts +8 -73
- package/ux/circuit-vis/events.ts +41 -1
- package/ux/circuit-vis/formatters/inputFormatter.ts +14 -6
- package/ux/circuit-vis/index.ts +12 -4
- package/ux/circuit-vis/panel.ts +65 -28
- package/ux/circuit-vis/sqore.ts +30 -16
- package/ux/circuit-vis/state-viz/stateViz.ts +748 -0
- package/ux/circuit-vis/state-viz/stateVizController.ts +285 -0
- package/ux/circuit-vis/state-viz/worker/index.ts +18 -0
- package/ux/circuit-vis/state-viz/worker/stateCompute.ts +260 -0
- package/ux/circuit-vis/state-viz/worker/stateVizPrep.ts +152 -0
- package/ux/circuit.tsx +15 -26
- package/ux/data.ts +5 -3
- package/ux/index.ts +2 -0
- package/ux/qdk-theme.css +15 -0
- package/ux/qsharp-circuit.css +310 -1
|
@@ -0,0 +1,748 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT license.
|
|
3
|
+
|
|
4
|
+
// State visualization renderer.
|
|
5
|
+
// Defines the renderable column/types and updates the `.state-panel` DOM
|
|
6
|
+
// (SVG/HTML) to display probabilities/phases, given either an amp map or
|
|
7
|
+
// pre-prepared columns.
|
|
8
|
+
|
|
9
|
+
export type RenderOptions = {
|
|
10
|
+
maxColumns?: number;
|
|
11
|
+
phaseColorMap?: (phaseRad: number) => string;
|
|
12
|
+
// Fill color for the aggregated "Others" column.
|
|
13
|
+
// Default comes from VIZ.defaultOthersColor.
|
|
14
|
+
othersColor?: string;
|
|
15
|
+
minColumnWidth?: number; // minimum width per column to avoid label collisions
|
|
16
|
+
minPanelWidthPx?: number; // prescribed minimum panel width in pixels
|
|
17
|
+
maxPanelWidthPx?: number; // prescribed maximum panel width in pixels
|
|
18
|
+
animationMs?: number; // global animation duration in ms (default 200ms)
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Visualization config constants
|
|
22
|
+
const VIZ = {
|
|
23
|
+
defaultAnimationMs: 200,
|
|
24
|
+
baseHeight: 80,
|
|
25
|
+
marginLeft: 36,
|
|
26
|
+
marginRight: 36,
|
|
27
|
+
marginBottom: 62,
|
|
28
|
+
minPanelWidthPx: 80,
|
|
29
|
+
defaultMinPanelWidth: 190,
|
|
30
|
+
defaultOthersColor: "#a6a6a6",
|
|
31
|
+
columnSpacing: 4,
|
|
32
|
+
minColumnWidthFloor: 16,
|
|
33
|
+
defaultMinColumnWidth: 36,
|
|
34
|
+
defaultMaxColumns: 16,
|
|
35
|
+
labelLongThresholdChars: 4,
|
|
36
|
+
barHeaderPadding: 36,
|
|
37
|
+
phaseHeaderPadding: 26,
|
|
38
|
+
stateHeaderPadding: 26,
|
|
39
|
+
percentLabelPadding: 29,
|
|
40
|
+
phaseLabelPadding: 39,
|
|
41
|
+
marginBottomMinPx: 48,
|
|
42
|
+
extraBottomPaddingPx: 24,
|
|
43
|
+
barAreaHeight: 234,
|
|
44
|
+
minProbEpsilon: 1e-12,
|
|
45
|
+
headerLabelXOffset: -8,
|
|
46
|
+
headerLabelYOffset: 9,
|
|
47
|
+
percentLabelOffset: 8,
|
|
48
|
+
phaseRadiusBase: 12,
|
|
49
|
+
phaseRadiusThreshold: 7.5,
|
|
50
|
+
phaseCirclePaddingX: 2,
|
|
51
|
+
phaseCirclePaddingY: 10,
|
|
52
|
+
phaseDotFrac: 0.25,
|
|
53
|
+
phaseDotRadiusMinPx: 1.5,
|
|
54
|
+
phaseTextBottomPad: 6,
|
|
55
|
+
verticalLabelCharHeight: 9,
|
|
56
|
+
phaseLabelLineHeight: 14,
|
|
57
|
+
verticalLabelExtraBase: 12,
|
|
58
|
+
stateLabelVerticalOffset: 4,
|
|
59
|
+
stateLabelHorizontalOffset: 16,
|
|
60
|
+
contentHeightExtra: 10,
|
|
61
|
+
edgePad: 36,
|
|
62
|
+
emptyStateFlexBasisPx: 360,
|
|
63
|
+
rowLabelFallbackPx: 24,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// --- Entry Points ---
|
|
67
|
+
|
|
68
|
+
export const createStatePanel = (): HTMLElement => {
|
|
69
|
+
try {
|
|
70
|
+
// Allows host environments (e.g., VS Code webview) to react to panel creation
|
|
71
|
+
// without needing a direct import hook.
|
|
72
|
+
(globalThis as any).dispatchEvent?.(
|
|
73
|
+
new CustomEvent("qsharp:stateviz:create"),
|
|
74
|
+
);
|
|
75
|
+
} catch {
|
|
76
|
+
// Ignore environments without CustomEvent / dispatchEvent
|
|
77
|
+
}
|
|
78
|
+
const panel = document.createElement("div");
|
|
79
|
+
panel.className = "state-panel";
|
|
80
|
+
panel.classList.add("collapsed");
|
|
81
|
+
|
|
82
|
+
const edge = document.createElement("div");
|
|
83
|
+
edge.className = "state-edge";
|
|
84
|
+
edge.setAttribute("role", "button");
|
|
85
|
+
edge.setAttribute("tabindex", "0");
|
|
86
|
+
edge.setAttribute("aria-label", "Toggle state panel");
|
|
87
|
+
edge.setAttribute("aria-expanded", "false");
|
|
88
|
+
const edgeText = document.createElement("span");
|
|
89
|
+
edgeText.className = "state-edge-text";
|
|
90
|
+
edgeText.textContent = "State Visualization";
|
|
91
|
+
edge.appendChild(edgeText);
|
|
92
|
+
|
|
93
|
+
const mkEdgeIcon = (cls: string): SVGSVGElement => {
|
|
94
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
95
|
+
svg.setAttribute("viewBox", "0 0 14 14");
|
|
96
|
+
svg.setAttribute("aria-hidden", "true");
|
|
97
|
+
svg.classList.add("edge-icon", cls);
|
|
98
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
99
|
+
path.setAttribute("d", "M 4.25 11 L 11 7 L 4.25 3 Z");
|
|
100
|
+
svg.appendChild(path);
|
|
101
|
+
return svg as SVGSVGElement;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const iconTop = mkEdgeIcon("edge-icon-top");
|
|
105
|
+
const iconBottom = mkEdgeIcon("edge-icon-bottom");
|
|
106
|
+
edge.appendChild(iconTop);
|
|
107
|
+
edge.appendChild(iconBottom);
|
|
108
|
+
|
|
109
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
110
|
+
svg.classList.add("state-svg");
|
|
111
|
+
svg.setAttribute("width", "100%");
|
|
112
|
+
svg.setAttribute("height", "100%");
|
|
113
|
+
|
|
114
|
+
panel.appendChild(edge);
|
|
115
|
+
panel.appendChild(svg);
|
|
116
|
+
|
|
117
|
+
const toggleCollapsed = () => {
|
|
118
|
+
const collapsed = panel.classList.toggle("collapsed");
|
|
119
|
+
edge.setAttribute("aria-expanded", (!collapsed).toString());
|
|
120
|
+
};
|
|
121
|
+
edge.addEventListener("click", toggleCollapsed);
|
|
122
|
+
edge.addEventListener("keydown", (ev) => {
|
|
123
|
+
if (ev.key === "Enter" || ev.key === " ") {
|
|
124
|
+
ev.preventDefault();
|
|
125
|
+
toggleCollapsed();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
return panel;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const ensureLoadingOverlay = (panel: HTMLElement): HTMLElement => {
|
|
132
|
+
let overlay = panel.querySelector(
|
|
133
|
+
".state-loading-overlay",
|
|
134
|
+
) as HTMLElement | null;
|
|
135
|
+
if (overlay) return overlay;
|
|
136
|
+
|
|
137
|
+
overlay = document.createElement("div");
|
|
138
|
+
overlay.className = "state-loading-overlay";
|
|
139
|
+
overlay.setAttribute("aria-hidden", "true");
|
|
140
|
+
|
|
141
|
+
const spinner = document.createElement("div");
|
|
142
|
+
spinner.className = "state-loading-spinner";
|
|
143
|
+
overlay.appendChild(spinner);
|
|
144
|
+
|
|
145
|
+
panel.appendChild(overlay);
|
|
146
|
+
return overlay;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export const setStatePanelLoading = (panel: HTMLElement, loading: boolean) => {
|
|
150
|
+
if (!panel) return;
|
|
151
|
+
if (loading) {
|
|
152
|
+
ensureLoadingOverlay(panel);
|
|
153
|
+
panel.classList.add("loading");
|
|
154
|
+
} else {
|
|
155
|
+
panel.classList.remove("loading");
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Put the panel into a message state (e.g., empty circuit or unsupported).
|
|
160
|
+
export const renderMessageStatePanel = (
|
|
161
|
+
panel: HTMLElement,
|
|
162
|
+
message = "The circuit is empty.",
|
|
163
|
+
): void => {
|
|
164
|
+
const svg = panel.querySelector("svg.state-svg") as SVGSVGElement | null;
|
|
165
|
+
if (svg) {
|
|
166
|
+
while (svg.firstChild) svg.removeChild(svg.firstChild);
|
|
167
|
+
svg.removeAttribute("height");
|
|
168
|
+
}
|
|
169
|
+
panel.classList.add("message");
|
|
170
|
+
|
|
171
|
+
let msg = panel.querySelector(".state-panel-message") as HTMLElement | null;
|
|
172
|
+
if (!msg) {
|
|
173
|
+
msg = document.createElement("div");
|
|
174
|
+
msg.className = "state-panel-message";
|
|
175
|
+
panel.appendChild(msg);
|
|
176
|
+
}
|
|
177
|
+
msg.textContent = message;
|
|
178
|
+
panel.style.flexBasis = `${VIZ.emptyStateFlexBasisPx}px`;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// Put the panel into a blank (non-message) state.
|
|
182
|
+
// This is used when the circuit is non-empty but state data isn't available yet.
|
|
183
|
+
export const renderBlankStatePanel = (panel: HTMLElement): void => {
|
|
184
|
+
const svg = panel.querySelector("svg.state-svg") as SVGSVGElement | null;
|
|
185
|
+
if (svg) {
|
|
186
|
+
while (svg.firstChild) svg.removeChild(svg.firstChild);
|
|
187
|
+
}
|
|
188
|
+
panel.classList.remove("message");
|
|
189
|
+
const msg = panel.querySelector(".state-panel-message");
|
|
190
|
+
if (msg) msg.remove();
|
|
191
|
+
// If we were previously in message state, restore sizing control back to CSS
|
|
192
|
+
// (or subsequent renders) instead of keeping the message-state flex-basis.
|
|
193
|
+
panel.style.flexBasis = "";
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// Render from precomputed columns (e.g., prepared in a Web Worker).
|
|
197
|
+
export const updateStatePanelFromColumns = (
|
|
198
|
+
panel: HTMLElement,
|
|
199
|
+
columns: StateColumn[],
|
|
200
|
+
opts: RenderOptions = {},
|
|
201
|
+
): void => {
|
|
202
|
+
// Content visibility restored via CSS when not in empty mode
|
|
203
|
+
// Remove empty mode to reveal content via CSS
|
|
204
|
+
panel.classList.remove("message");
|
|
205
|
+
const msg = panel.querySelector(".state-panel-message");
|
|
206
|
+
if (msg) msg.remove();
|
|
207
|
+
panel.style.flexBasis = "";
|
|
208
|
+
|
|
209
|
+
renderStatePanel(panel, columns, opts);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// --- State Amplitude Preparation ---
|
|
213
|
+
|
|
214
|
+
export type AmpComplex = { re: number; im: number };
|
|
215
|
+
export type AmpPolar = { prob?: number; phase?: number };
|
|
216
|
+
export type AmpLike = AmpComplex | AmpPolar;
|
|
217
|
+
export type AmpMap = Record<string, AmpLike>;
|
|
218
|
+
|
|
219
|
+
// --- Layout Computation ---
|
|
220
|
+
|
|
221
|
+
// The data for a single column in the state visualization
|
|
222
|
+
export type StateColumn = {
|
|
223
|
+
label: string;
|
|
224
|
+
prob: number;
|
|
225
|
+
phase: number;
|
|
226
|
+
isOthers?: boolean;
|
|
227
|
+
othersCount?: number;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Layout metrics used to organize rendering logic
|
|
231
|
+
type LayoutMetrics = {
|
|
232
|
+
panelWidthPx: number;
|
|
233
|
+
contentWidthPx: number;
|
|
234
|
+
|
|
235
|
+
columnWidthPx: number;
|
|
236
|
+
|
|
237
|
+
maxProb: number;
|
|
238
|
+
|
|
239
|
+
phaseSectionTopY: number;
|
|
240
|
+
phaseCircleRadiusPx: number;
|
|
241
|
+
|
|
242
|
+
stateSectionTopY: number;
|
|
243
|
+
verticalLabels: boolean;
|
|
244
|
+
maxLabelLen: number;
|
|
245
|
+
|
|
246
|
+
animationMs: number;
|
|
247
|
+
othersColor: string;
|
|
248
|
+
phaseColor: (phi: number) => string;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// The animation speed for the state viz panel can be set via the passed in options
|
|
252
|
+
// argument, or via CSS custom property `--stateAnimMs` on the panel element.
|
|
253
|
+
// This function computes the effective animation duration in milliseconds from
|
|
254
|
+
// these sources, with the CSS value taking precedence over the options argument.
|
|
255
|
+
const getAnimationMs = (panel: HTMLElement, opts: RenderOptions): number => {
|
|
256
|
+
let animationMs = VIZ.defaultAnimationMs;
|
|
257
|
+
if (
|
|
258
|
+
typeof opts.animationMs === "number" &&
|
|
259
|
+
isFinite(opts.animationMs) &&
|
|
260
|
+
opts.animationMs >= 0
|
|
261
|
+
) {
|
|
262
|
+
animationMs = Math.round(opts.animationMs);
|
|
263
|
+
}
|
|
264
|
+
if (panel.isConnected) {
|
|
265
|
+
const cssDur = getComputedStyle(panel)
|
|
266
|
+
.getPropertyValue("--stateAnimMs")
|
|
267
|
+
.trim();
|
|
268
|
+
const parsed = parseDurationMs(cssDur);
|
|
269
|
+
if (!isNaN(parsed) && parsed >= 0) animationMs = parsed;
|
|
270
|
+
}
|
|
271
|
+
return animationMs;
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// Parse CSS duration strings (e.g., "200ms" or "0.2s") into milliseconds
|
|
275
|
+
const parseDurationMs = (val: string): number => {
|
|
276
|
+
const s = (val || "").trim();
|
|
277
|
+
if (!s) return NaN;
|
|
278
|
+
if (s.endsWith("ms")) {
|
|
279
|
+
const v = parseFloat(s.slice(0, -2));
|
|
280
|
+
return isFinite(v) ? v : NaN;
|
|
281
|
+
}
|
|
282
|
+
if (s.endsWith("s")) {
|
|
283
|
+
const v = parseFloat(s.slice(0, -1));
|
|
284
|
+
return isFinite(v) ? Math.round(v * 1000) : NaN;
|
|
285
|
+
}
|
|
286
|
+
const v = parseFloat(s);
|
|
287
|
+
return isFinite(v) ? v : NaN;
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// Combines layout information from option, column data, and VIZ constants to compute finalized layout metrics.
|
|
291
|
+
const computeLayoutMetrics = (
|
|
292
|
+
panel: HTMLElement,
|
|
293
|
+
columnsData: StateColumn[],
|
|
294
|
+
opts: RenderOptions,
|
|
295
|
+
): LayoutMetrics => {
|
|
296
|
+
const animationMs = getAnimationMs(panel, opts);
|
|
297
|
+
|
|
298
|
+
const columnCount = columnsData.length;
|
|
299
|
+
const minColumnWidthPx = Math.max(
|
|
300
|
+
VIZ.minColumnWidthFloor,
|
|
301
|
+
typeof opts.minColumnWidth === "number"
|
|
302
|
+
? Math.floor(opts.minColumnWidth)
|
|
303
|
+
: VIZ.defaultMinColumnWidth,
|
|
304
|
+
);
|
|
305
|
+
const maxColumns = opts.maxColumns ?? VIZ.defaultMaxColumns;
|
|
306
|
+
const defaultMinPanelWidthPx = VIZ.defaultMinPanelWidth;
|
|
307
|
+
const defaultMaxPanelWidthPx =
|
|
308
|
+
VIZ.marginLeft +
|
|
309
|
+
VIZ.marginRight +
|
|
310
|
+
maxColumns * (minColumnWidthPx + VIZ.columnSpacing);
|
|
311
|
+
|
|
312
|
+
const minWidthPx = Math.max(
|
|
313
|
+
VIZ.minPanelWidthPx,
|
|
314
|
+
opts.minPanelWidthPx ?? defaultMinPanelWidthPx,
|
|
315
|
+
);
|
|
316
|
+
const maxWidthPx = Math.max(
|
|
317
|
+
minWidthPx,
|
|
318
|
+
opts.maxPanelWidthPx ?? defaultMaxPanelWidthPx,
|
|
319
|
+
);
|
|
320
|
+
const growthFactor = Math.max(
|
|
321
|
+
0,
|
|
322
|
+
Math.min(1, (columnCount - 1) / (maxColumns - 1)),
|
|
323
|
+
);
|
|
324
|
+
const panelWidthPx = Math.round(
|
|
325
|
+
minWidthPx + growthFactor * (maxWidthPx - minWidthPx),
|
|
326
|
+
);
|
|
327
|
+
const contentWidthPx = panelWidthPx - VIZ.marginLeft - VIZ.marginRight;
|
|
328
|
+
const columnWidthPx = Math.max(
|
|
329
|
+
4,
|
|
330
|
+
Math.floor(contentWidthPx / Math.max(1, columnCount)) - VIZ.columnSpacing,
|
|
331
|
+
);
|
|
332
|
+
const phaseCircleRadiusPx = Math.max(
|
|
333
|
+
VIZ.phaseRadiusBase,
|
|
334
|
+
Math.floor(columnWidthPx / 2) - 1,
|
|
335
|
+
);
|
|
336
|
+
const maxLabelLen = columnsData.reduce(
|
|
337
|
+
(m, b) => Math.max(m, (displayLabel(b) || "").length),
|
|
338
|
+
0,
|
|
339
|
+
);
|
|
340
|
+
const verticalLabels = maxLabelLen > VIZ.labelLongThresholdChars;
|
|
341
|
+
|
|
342
|
+
const maxProb = Math.max(
|
|
343
|
+
VIZ.minProbEpsilon,
|
|
344
|
+
Math.max(...columnsData.map((b) => b.prob ?? 0)),
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
const phaseColor = opts.phaseColorMap ?? defaultPhaseColor;
|
|
348
|
+
const othersColor = opts.othersColor ?? VIZ.defaultOthersColor;
|
|
349
|
+
|
|
350
|
+
const phaseSectionTopY =
|
|
351
|
+
VIZ.barHeaderPadding + VIZ.barAreaHeight + VIZ.percentLabelPadding;
|
|
352
|
+
const stateSectionTopY =
|
|
353
|
+
phaseSectionTopY +
|
|
354
|
+
VIZ.phaseHeaderPadding +
|
|
355
|
+
2 * phaseCircleRadiusPx +
|
|
356
|
+
VIZ.phaseLabelPadding;
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
panelWidthPx,
|
|
360
|
+
contentWidthPx,
|
|
361
|
+
columnWidthPx,
|
|
362
|
+
maxProb,
|
|
363
|
+
phaseSectionTopY,
|
|
364
|
+
phaseCircleRadiusPx,
|
|
365
|
+
stateSectionTopY,
|
|
366
|
+
verticalLabels,
|
|
367
|
+
maxLabelLen,
|
|
368
|
+
animationMs,
|
|
369
|
+
phaseColor,
|
|
370
|
+
othersColor,
|
|
371
|
+
};
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
// --- Rendering functions ---
|
|
375
|
+
|
|
376
|
+
const renderStatePanel = (
|
|
377
|
+
panel: HTMLElement,
|
|
378
|
+
columnData: StateColumn[],
|
|
379
|
+
opts: RenderOptions = {},
|
|
380
|
+
): void => {
|
|
381
|
+
const svg = panel.querySelector("svg.state-svg") as SVGSVGElement | null;
|
|
382
|
+
if (!svg) return;
|
|
383
|
+
const prev: Record<string, { prob: number; phase: number }> =
|
|
384
|
+
(panel as any)._stateVizPrev ?? {};
|
|
385
|
+
|
|
386
|
+
while (svg.firstChild) svg.removeChild(svg.firstChild);
|
|
387
|
+
|
|
388
|
+
const layout = computeLayoutMetrics(panel, columnData, opts);
|
|
389
|
+
|
|
390
|
+
const g = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
391
|
+
g.setAttribute("transform", `translate(${VIZ.marginLeft},${0})`);
|
|
392
|
+
svg.appendChild(g);
|
|
393
|
+
|
|
394
|
+
renderSectionHeaders(g, layout);
|
|
395
|
+
|
|
396
|
+
columnData.forEach((col, i) => renderColumn(g, col, i, prev, layout));
|
|
397
|
+
|
|
398
|
+
finalizeSvgAndFlex(svg, panel, layout);
|
|
399
|
+
savePreviousValues(panel, columnData);
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
// Render the section headers and separators
|
|
403
|
+
const renderSectionHeaders = (g: SVGGElement, layout: LayoutMetrics) => {
|
|
404
|
+
const mkLabel = (text: string, y: number) => {
|
|
405
|
+
const t = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
406
|
+
t.setAttribute("x", `${VIZ.headerLabelXOffset}`);
|
|
407
|
+
t.setAttribute("y", `${y + VIZ.headerLabelYOffset}`);
|
|
408
|
+
t.setAttribute("class", "state-header");
|
|
409
|
+
t.textContent = text;
|
|
410
|
+
return t;
|
|
411
|
+
};
|
|
412
|
+
const mkSep = (y: number) => {
|
|
413
|
+
const line = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
414
|
+
line.setAttribute("x1", "0");
|
|
415
|
+
line.setAttribute("y1", `${y}`);
|
|
416
|
+
line.setAttribute("x2", `${layout.contentWidthPx}`);
|
|
417
|
+
line.setAttribute("y2", `${y}`);
|
|
418
|
+
line.setAttribute("class", "state-separator");
|
|
419
|
+
return line;
|
|
420
|
+
};
|
|
421
|
+
g.appendChild(mkLabel("Probability Density", 0));
|
|
422
|
+
g.appendChild(mkSep(layout.phaseSectionTopY));
|
|
423
|
+
g.appendChild(mkLabel("Phase", layout.phaseSectionTopY));
|
|
424
|
+
g.appendChild(mkSep(layout.stateSectionTopY));
|
|
425
|
+
g.appendChild(mkLabel("State", layout.stateSectionTopY));
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
// Render a full column (percentage bar + phase + label)
|
|
429
|
+
const renderColumn = (
|
|
430
|
+
g: SVGGElement,
|
|
431
|
+
column: StateColumn,
|
|
432
|
+
colIdx: number,
|
|
433
|
+
prev: Record<string, { prob: number; phase: number }>,
|
|
434
|
+
layout: LayoutMetrics,
|
|
435
|
+
) => {
|
|
436
|
+
const colX = colIdx * (layout.columnWidthPx + VIZ.columnSpacing);
|
|
437
|
+
|
|
438
|
+
const prevProb = prev[column.label]?.prob ?? 0;
|
|
439
|
+
const bar = renderProbSection(g, column, prevProb, colX, layout);
|
|
440
|
+
|
|
441
|
+
const prevPhase = prev[column.label]?.phase ?? 0;
|
|
442
|
+
renderPhaseSection(g, column, prevPhase, bar, colX, layout);
|
|
443
|
+
|
|
444
|
+
renderStateLabelSection(g, column, colX, layout);
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
const renderProbSection = (
|
|
448
|
+
g: SVGGElement,
|
|
449
|
+
column: StateColumn,
|
|
450
|
+
prevProb: number,
|
|
451
|
+
colX: number,
|
|
452
|
+
layout: LayoutMetrics,
|
|
453
|
+
): SVGRectElement => {
|
|
454
|
+
const { columnWidthPx, maxProb, animationMs, phaseColor, othersColor } =
|
|
455
|
+
layout;
|
|
456
|
+
const cx = colX + columnWidthPx / 2;
|
|
457
|
+
|
|
458
|
+
const scaleY = (p: number) =>
|
|
459
|
+
(Math.max(0, Math.min(p, maxProb)) / maxProb) * VIZ.barAreaHeight;
|
|
460
|
+
|
|
461
|
+
const bar = document.createElementNS(
|
|
462
|
+
"http://www.w3.org/2000/svg",
|
|
463
|
+
"rect",
|
|
464
|
+
) as unknown as SVGRectElement;
|
|
465
|
+
bar.setAttribute("x", `${colX}`);
|
|
466
|
+
bar.setAttribute("width", `${columnWidthPx}`);
|
|
467
|
+
bar.setAttribute(
|
|
468
|
+
"fill",
|
|
469
|
+
column.isOthers ? othersColor : phaseColor(column.phase),
|
|
470
|
+
);
|
|
471
|
+
bar.setAttribute("class", "state-bar");
|
|
472
|
+
const tip = document.createElementNS("http://www.w3.org/2000/svg", "title");
|
|
473
|
+
const pctTipTarget = (column.prob ?? 0) * 100;
|
|
474
|
+
tip.textContent = column.isOthers
|
|
475
|
+
? `${pctTipTarget.toFixed(1)}% • Others (${column.othersCount ?? 0} states)`
|
|
476
|
+
: `${pctTipTarget.toFixed(1)}% • φ=${formatPhasePiTip(column.phase)}`;
|
|
477
|
+
bar.appendChild(tip);
|
|
478
|
+
g.appendChild(bar);
|
|
479
|
+
|
|
480
|
+
const fromH = scaleY(prevProb);
|
|
481
|
+
const baseY = VIZ.barHeaderPadding + VIZ.barAreaHeight;
|
|
482
|
+
bar.setAttribute("y", `${baseY - fromH}`);
|
|
483
|
+
bar.setAttribute("height", `${fromH}`);
|
|
484
|
+
animate(prevProb, column.prob, animationMs, (pv) => {
|
|
485
|
+
const h = scaleY(pv);
|
|
486
|
+
bar.setAttribute("y", `${baseY - h}`);
|
|
487
|
+
bar.setAttribute("height", `${h}`);
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
const label = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
491
|
+
label.setAttribute("x", `${cx}`);
|
|
492
|
+
const labelY =
|
|
493
|
+
VIZ.barHeaderPadding + VIZ.barAreaHeight + VIZ.percentLabelOffset;
|
|
494
|
+
label.setAttribute("y", `${labelY}`);
|
|
495
|
+
label.setAttribute("class", "state-bar-label");
|
|
496
|
+
animate(prevProb, column.prob, animationMs, (pv) => {
|
|
497
|
+
const pct = (pv ?? 0) * 100;
|
|
498
|
+
label.textContent = pct >= 1 ? `${pct.toFixed(0)}%` : `${pct.toFixed(1)}%`;
|
|
499
|
+
});
|
|
500
|
+
g.appendChild(label);
|
|
501
|
+
|
|
502
|
+
return bar;
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
const renderPhaseSection = (
|
|
506
|
+
g: SVGGElement,
|
|
507
|
+
column: StateColumn,
|
|
508
|
+
prevPhase: number,
|
|
509
|
+
bar: SVGRectElement,
|
|
510
|
+
colX: number,
|
|
511
|
+
layout: LayoutMetrics,
|
|
512
|
+
): void => {
|
|
513
|
+
if (column.isOthers) return;
|
|
514
|
+
|
|
515
|
+
const {
|
|
516
|
+
columnWidthPx,
|
|
517
|
+
phaseSectionTopY,
|
|
518
|
+
phaseCircleRadiusPx,
|
|
519
|
+
stateSectionTopY,
|
|
520
|
+
animationMs,
|
|
521
|
+
phaseColor,
|
|
522
|
+
} = layout;
|
|
523
|
+
const cx = colX + columnWidthPx / 2;
|
|
524
|
+
|
|
525
|
+
let r = phaseCircleRadiusPx;
|
|
526
|
+
if (r >= VIZ.phaseRadiusThreshold) {
|
|
527
|
+
const maxR = Math.floor(
|
|
528
|
+
(columnWidthPx / 2 - VIZ.phaseCirclePaddingX) / (1 + VIZ.phaseDotFrac),
|
|
529
|
+
);
|
|
530
|
+
r = Math.min(r, Math.max(2, maxR));
|
|
531
|
+
} else {
|
|
532
|
+
const maxR = Math.floor(columnWidthPx / 2 - VIZ.phaseCirclePaddingX - 1.5);
|
|
533
|
+
r = Math.min(r, Math.max(2, maxR));
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const phaseContentYBase = phaseSectionTopY + VIZ.phaseHeaderPadding;
|
|
537
|
+
const cy = phaseContentYBase + r + VIZ.phaseCirclePaddingY;
|
|
538
|
+
const sx = cx + r;
|
|
539
|
+
const sy = cy;
|
|
540
|
+
const ex = cx + r * Math.cos(column.phase);
|
|
541
|
+
const ey = cy - r * Math.sin(column.phase);
|
|
542
|
+
const largeArc = Math.abs(column.phase) > Math.PI ? 1 : 0;
|
|
543
|
+
const sweep = column.phase < 0 ? 1 : 0;
|
|
544
|
+
|
|
545
|
+
const wedge = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
546
|
+
const dTarget = `M ${cx} ${cy} L ${sx} ${sy} A ${r} ${r} 0 ${largeArc} ${sweep} ${ex} ${ey} Z`;
|
|
547
|
+
wedge.setAttribute("d", dTarget);
|
|
548
|
+
wedge.setAttribute("class", "state-phase-wedge");
|
|
549
|
+
wedge.setAttribute("fill", phaseColor(column.phase));
|
|
550
|
+
g.appendChild(wedge);
|
|
551
|
+
|
|
552
|
+
const circle = document.createElementNS(
|
|
553
|
+
"http://www.w3.org/2000/svg",
|
|
554
|
+
"circle",
|
|
555
|
+
);
|
|
556
|
+
circle.setAttribute("cx", `${cx}`);
|
|
557
|
+
circle.setAttribute("cy", `${cy}`);
|
|
558
|
+
circle.setAttribute("r", `${r}`);
|
|
559
|
+
circle.setAttribute("class", "state-phase-circle");
|
|
560
|
+
const tipPhase = document.createElementNS(
|
|
561
|
+
"http://www.w3.org/2000/svg",
|
|
562
|
+
"title",
|
|
563
|
+
);
|
|
564
|
+
tipPhase.textContent = `φ=${formatPhasePiTip(column.phase)}`;
|
|
565
|
+
circle.appendChild(tipPhase);
|
|
566
|
+
g.appendChild(circle);
|
|
567
|
+
|
|
568
|
+
const phaseText = document.createElementNS(
|
|
569
|
+
"http://www.w3.org/2000/svg",
|
|
570
|
+
"text",
|
|
571
|
+
);
|
|
572
|
+
phaseText.setAttribute("x", `${cx}`);
|
|
573
|
+
const dotRadius = Math.max(VIZ.phaseDotRadiusMinPx, r * VIZ.phaseDotFrac);
|
|
574
|
+
const labelAreaTopY = cy + r + dotRadius;
|
|
575
|
+
const labelAreaBottomY = stateSectionTopY - VIZ.phaseTextBottomPad;
|
|
576
|
+
const availableH = Math.max(0, labelAreaBottomY - labelAreaTopY);
|
|
577
|
+
const textH = VIZ.phaseLabelLineHeight;
|
|
578
|
+
const yTextTop = Math.round(
|
|
579
|
+
labelAreaTopY + Math.max(0, (availableH - textH) / 2),
|
|
580
|
+
);
|
|
581
|
+
phaseText.setAttribute("y", `${yTextTop}`);
|
|
582
|
+
phaseText.setAttribute("class", "state-phase-text");
|
|
583
|
+
animate(prevPhase, column.phase, animationMs, (pv) => {
|
|
584
|
+
phaseText.textContent = formatPhasePi(pv);
|
|
585
|
+
});
|
|
586
|
+
g.appendChild(phaseText);
|
|
587
|
+
|
|
588
|
+
const prevDx = r * Math.cos(prevPhase);
|
|
589
|
+
const prevDy = r * Math.sin(prevPhase);
|
|
590
|
+
const dot = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
591
|
+
dot.setAttribute("cx", `${cx + prevDx}`);
|
|
592
|
+
dot.setAttribute("cy", `${cy - prevDy}`);
|
|
593
|
+
dot.setAttribute(
|
|
594
|
+
"r",
|
|
595
|
+
`${Math.max(VIZ.phaseDotRadiusMinPx, r * VIZ.phaseDotFrac)}`,
|
|
596
|
+
);
|
|
597
|
+
dot.setAttribute("fill", phaseColor(column.phase));
|
|
598
|
+
dot.setAttribute("class", "state-phase-dot");
|
|
599
|
+
g.appendChild(dot);
|
|
600
|
+
|
|
601
|
+
animate(prevPhase, column.phase, animationMs, (pv) => {
|
|
602
|
+
const dx = r * Math.cos(pv);
|
|
603
|
+
const dy = r * Math.sin(pv);
|
|
604
|
+
dot.setAttribute("cx", `${cx + dx}`);
|
|
605
|
+
dot.setAttribute("cy", `${cy - dy}`);
|
|
606
|
+
const fillColor = phaseColor(pv);
|
|
607
|
+
wedge.setAttribute("fill", fillColor);
|
|
608
|
+
dot.setAttribute("fill", fillColor);
|
|
609
|
+
bar.setAttribute("fill", fillColor);
|
|
610
|
+
const exA = cx + r * Math.cos(pv);
|
|
611
|
+
const eyA = cy - r * Math.sin(pv);
|
|
612
|
+
const largeArcA = Math.abs(pv) > Math.PI ? 1 : 0;
|
|
613
|
+
const sweepA = pv < 0 ? 1 : 0;
|
|
614
|
+
const dA = `M ${cx} ${cy} L ${sx} ${sy} A ${r} ${r} 0 ${largeArcA} ${sweepA} ${exA} ${eyA} Z`;
|
|
615
|
+
wedge.setAttribute("d", dA);
|
|
616
|
+
});
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
const renderStateLabelSection = (
|
|
620
|
+
g: SVGGElement,
|
|
621
|
+
column: StateColumn,
|
|
622
|
+
colX: number,
|
|
623
|
+
layout: LayoutMetrics,
|
|
624
|
+
): void => {
|
|
625
|
+
const { columnWidthPx, stateSectionTopY, verticalLabels } = layout;
|
|
626
|
+
const cx = colX + columnWidthPx / 2;
|
|
627
|
+
|
|
628
|
+
const stateContentYBase = stateSectionTopY + VIZ.stateHeaderPadding;
|
|
629
|
+
const labelY = verticalLabels
|
|
630
|
+
? stateContentYBase + VIZ.stateLabelVerticalOffset
|
|
631
|
+
: stateContentYBase + VIZ.stateLabelHorizontalOffset;
|
|
632
|
+
|
|
633
|
+
if (verticalLabels) {
|
|
634
|
+
const labelText = displayLabel(column);
|
|
635
|
+
const labelH =
|
|
636
|
+
VIZ.verticalLabelCharHeight * Math.max(1, (labelText || "").length);
|
|
637
|
+
const fo = document.createElementNS(
|
|
638
|
+
"http://www.w3.org/2000/svg",
|
|
639
|
+
"foreignObject",
|
|
640
|
+
);
|
|
641
|
+
fo.setAttribute("x", `${colX}`);
|
|
642
|
+
fo.setAttribute("y", `${labelY}`);
|
|
643
|
+
fo.setAttribute("width", `${columnWidthPx}`);
|
|
644
|
+
fo.setAttribute("height", `${labelH}`);
|
|
645
|
+
const div = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
|
|
646
|
+
div.setAttribute("class", "state-bitstring-fo");
|
|
647
|
+
div.textContent = labelText;
|
|
648
|
+
fo.appendChild(div);
|
|
649
|
+
g.appendChild(fo);
|
|
650
|
+
} else {
|
|
651
|
+
const t = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
652
|
+
t.setAttribute("x", `${cx}`);
|
|
653
|
+
t.setAttribute("y", `${labelY}`);
|
|
654
|
+
t.setAttribute("class", "state-bitstring");
|
|
655
|
+
t.textContent = displayLabel(column);
|
|
656
|
+
g.appendChild(t);
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
const finalizeSvgAndFlex = (
|
|
661
|
+
svg: SVGSVGElement,
|
|
662
|
+
panel: HTMLElement,
|
|
663
|
+
layout: LayoutMetrics,
|
|
664
|
+
) => {
|
|
665
|
+
const labelTextHeightPx = layout.verticalLabels
|
|
666
|
+
? VIZ.verticalLabelCharHeight * Math.max(1, layout.maxLabelLen)
|
|
667
|
+
: VIZ.phaseLabelLineHeight;
|
|
668
|
+
const labelBottomY =
|
|
669
|
+
layout.stateSectionTopY +
|
|
670
|
+
VIZ.stateHeaderPadding +
|
|
671
|
+
(layout.verticalLabels
|
|
672
|
+
? VIZ.stateLabelVerticalOffset
|
|
673
|
+
: VIZ.stateLabelHorizontalOffset) +
|
|
674
|
+
labelTextHeightPx;
|
|
675
|
+
|
|
676
|
+
const svgHeight = Math.max(
|
|
677
|
+
VIZ.baseHeight,
|
|
678
|
+
Math.ceil(labelBottomY + VIZ.extraBottomPaddingPx + VIZ.marginBottomMinPx),
|
|
679
|
+
);
|
|
680
|
+
|
|
681
|
+
svg.setAttribute("height", svgHeight.toString());
|
|
682
|
+
svg.setAttribute("width", layout.panelWidthPx.toString());
|
|
683
|
+
const edgePad = VIZ.edgePad;
|
|
684
|
+
panel.style.flexBasis = `${Math.ceil(layout.panelWidthPx + edgePad)}px`;
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
const savePreviousValues = (panel: HTMLElement, columnData: StateColumn[]) => {
|
|
688
|
+
const store: Record<string, { prob: number; phase: number }> = {};
|
|
689
|
+
for (const col of columnData)
|
|
690
|
+
store[col.label] = { prob: col.prob, phase: col.phase };
|
|
691
|
+
(panel as any)._stateVizPrev = store;
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
// Simple animation helper for numeric interpolation
|
|
695
|
+
const animate = (
|
|
696
|
+
from: number,
|
|
697
|
+
to: number,
|
|
698
|
+
durationMs: number,
|
|
699
|
+
onUpdate: (v: number) => void,
|
|
700
|
+
onDone?: () => void,
|
|
701
|
+
) => {
|
|
702
|
+
if (!isFinite(durationMs) || durationMs <= 0) {
|
|
703
|
+
try {
|
|
704
|
+
onUpdate(to);
|
|
705
|
+
} catch {
|
|
706
|
+
// Ignore update errors
|
|
707
|
+
}
|
|
708
|
+
if (onDone) onDone();
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
const start = performance.now();
|
|
712
|
+
const tick = (now: number) => {
|
|
713
|
+
const t = Math.min(1, (now - start) / durationMs);
|
|
714
|
+
const v = from + (to - from) * t;
|
|
715
|
+
try {
|
|
716
|
+
onUpdate(v);
|
|
717
|
+
} catch {
|
|
718
|
+
// Ignore update errors to keep the animation loop alive
|
|
719
|
+
}
|
|
720
|
+
if (t < 1) requestAnimationFrame(tick);
|
|
721
|
+
else if (onDone) onDone();
|
|
722
|
+
};
|
|
723
|
+
requestAnimationFrame(tick);
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
// The default phase color mapping: map phase (-π..π) to HSL hue (0..360)
|
|
727
|
+
const defaultPhaseColor = (phi: number) => {
|
|
728
|
+
const hue = ((phi + Math.PI) / (2 * Math.PI)) * 360;
|
|
729
|
+
return `hsl(${hue},70%,50%)`;
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
// Format phase in multiples of π, e.g., -0.5, +0.2
|
|
733
|
+
const formatPhasePi = (phi: number): string => {
|
|
734
|
+
const k = phi / Math.PI;
|
|
735
|
+
const sign = k >= 0 ? "+" : "";
|
|
736
|
+
return `${sign}${k.toFixed(1)}`;
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
// Format phase for tooltips, e.g., -0.50π, +0.25π
|
|
740
|
+
const formatPhasePiTip = (phi: number): string => {
|
|
741
|
+
const k = phi / Math.PI;
|
|
742
|
+
const sign = k >= 0 ? "+" : "";
|
|
743
|
+
return `${sign}${k.toFixed(2)}π`;
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
// Display label for a state column, handling "Others" case
|
|
747
|
+
const displayLabel = (b: StateColumn) =>
|
|
748
|
+
b.isOthers === true ? `Others (${b.othersCount ?? 0})` : b.label;
|