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.
Files changed (335) hide show
  1. package/dist/data-structures/circuit.d.ts +6 -1
  2. package/docs/Microsoft.Quantum.Core/IsRangeEmpty.md +1 -1
  3. package/docs/Microsoft.Quantum.Core/Length.md +1 -1
  4. package/docs/Microsoft.Quantum.Core/RangeEnd.md +1 -1
  5. package/docs/Microsoft.Quantum.Core/RangeStart.md +1 -1
  6. package/docs/Microsoft.Quantum.Core/Repeated.md +1 -1
  7. package/docs/Microsoft.Quantum.Core/index.md +1 -1
  8. package/docs/Std.Arithmetic/AddLE.md +1 -1
  9. package/docs/Std.Arithmetic/ApplyIfEqualL.md +1 -1
  10. package/docs/Std.Arithmetic/ApplyIfEqualLE.md +1 -1
  11. package/docs/Std.Arithmetic/ApplyIfGreaterL.md +1 -1
  12. package/docs/Std.Arithmetic/ApplyIfGreaterLE.md +1 -1
  13. package/docs/Std.Arithmetic/ApplyIfGreaterOrEqualL.md +1 -1
  14. package/docs/Std.Arithmetic/ApplyIfGreaterOrEqualLE.md +1 -1
  15. package/docs/Std.Arithmetic/ApplyIfLessL.md +1 -1
  16. package/docs/Std.Arithmetic/ApplyIfLessLE.md +1 -1
  17. package/docs/Std.Arithmetic/ApplyIfLessOrEqualL.md +1 -1
  18. package/docs/Std.Arithmetic/ApplyIfLessOrEqualLE.md +1 -1
  19. package/docs/Std.Arithmetic/FourierTDIncByLE.md +1 -1
  20. package/docs/Std.Arithmetic/IncByI.md +1 -1
  21. package/docs/Std.Arithmetic/IncByIUsingIncByLE.md +1 -1
  22. package/docs/Std.Arithmetic/IncByL.md +1 -1
  23. package/docs/Std.Arithmetic/IncByLE.md +1 -1
  24. package/docs/Std.Arithmetic/IncByLEUsingAddLE.md +1 -1
  25. package/docs/Std.Arithmetic/IncByLUsingIncByLE.md +1 -1
  26. package/docs/Std.Arithmetic/LookAheadDKRSAddLE.md +1 -1
  27. package/docs/Std.Arithmetic/MAJ.md +1 -1
  28. package/docs/Std.Arithmetic/ReflectAboutInteger.md +1 -1
  29. package/docs/Std.Arithmetic/RippleCarryCGAddLE.md +1 -1
  30. package/docs/Std.Arithmetic/RippleCarryCGIncByLE.md +1 -1
  31. package/docs/Std.Arithmetic/RippleCarryTTKIncByLE.md +1 -1
  32. package/docs/Std.Arithmetic/index.md +1 -1
  33. package/docs/Std.Arrays/All.md +1 -1
  34. package/docs/Std.Arrays/Any.md +1 -1
  35. package/docs/Std.Arrays/Chunks.md +1 -1
  36. package/docs/Std.Arrays/CircularlyShifted.md +1 -1
  37. package/docs/Std.Arrays/ColumnAt.md +1 -1
  38. package/docs/Std.Arrays/Count.md +1 -1
  39. package/docs/Std.Arrays/Diagonal.md +1 -1
  40. package/docs/Std.Arrays/DrawMany.md +1 -1
  41. package/docs/Std.Arrays/Enumerated.md +1 -1
  42. package/docs/Std.Arrays/Excluding.md +1 -1
  43. package/docs/Std.Arrays/Filtered.md +1 -1
  44. package/docs/Std.Arrays/FlatMapped.md +1 -1
  45. package/docs/Std.Arrays/Flattened.md +1 -1
  46. package/docs/Std.Arrays/Fold.md +1 -1
  47. package/docs/Std.Arrays/ForEach.md +1 -1
  48. package/docs/Std.Arrays/Head.md +1 -1
  49. package/docs/Std.Arrays/HeadAndRest.md +1 -1
  50. package/docs/Std.Arrays/IndexOf.md +1 -1
  51. package/docs/Std.Arrays/IndexRange.md +1 -1
  52. package/docs/Std.Arrays/Interleaved.md +1 -1
  53. package/docs/Std.Arrays/IsEmpty.md +1 -1
  54. package/docs/Std.Arrays/IsRectangularArray.md +1 -1
  55. package/docs/Std.Arrays/IsSorted.md +1 -1
  56. package/docs/Std.Arrays/IsSquareArray.md +1 -1
  57. package/docs/Std.Arrays/Mapped.md +1 -1
  58. package/docs/Std.Arrays/MappedByIndex.md +1 -1
  59. package/docs/Std.Arrays/MappedOverRange.md +1 -1
  60. package/docs/Std.Arrays/Most.md +1 -1
  61. package/docs/Std.Arrays/MostAndTail.md +1 -1
  62. package/docs/Std.Arrays/Padded.md +1 -1
  63. package/docs/Std.Arrays/Partitioned.md +1 -1
  64. package/docs/Std.Arrays/Rest.md +1 -1
  65. package/docs/Std.Arrays/Reversed.md +1 -1
  66. package/docs/Std.Arrays/SequenceI.md +1 -1
  67. package/docs/Std.Arrays/SequenceL.md +1 -1
  68. package/docs/Std.Arrays/Sorted.md +1 -1
  69. package/docs/Std.Arrays/Subarray.md +1 -1
  70. package/docs/Std.Arrays/Swapped.md +1 -1
  71. package/docs/Std.Arrays/Tail.md +1 -1
  72. package/docs/Std.Arrays/Transposed.md +1 -1
  73. package/docs/Std.Arrays/Unzipped.md +1 -1
  74. package/docs/Std.Arrays/Where.md +1 -1
  75. package/docs/Std.Arrays/Windows.md +1 -1
  76. package/docs/Std.Arrays/Zipped.md +1 -1
  77. package/docs/Std.Arrays/index.md +1 -1
  78. package/docs/Std.Canon/ApplyCNOTChain.md +1 -1
  79. package/docs/Std.Canon/ApplyControlledOnBitString.md +1 -1
  80. package/docs/Std.Canon/ApplyControlledOnInt.md +1 -1
  81. package/docs/Std.Canon/ApplyOperationPowerA.md +1 -1
  82. package/docs/Std.Canon/ApplyOperationPowerCA.md +1 -1
  83. package/docs/Std.Canon/ApplyP.md +1 -1
  84. package/docs/Std.Canon/ApplyPauli.md +1 -1
  85. package/docs/Std.Canon/ApplyPauliFromBitString.md +1 -1
  86. package/docs/Std.Canon/ApplyPauliFromInt.md +1 -1
  87. package/docs/Std.Canon/ApplyQFT.md +1 -1
  88. package/docs/Std.Canon/ApplyQPE.md +1 -1
  89. package/docs/Std.Canon/ApplyToEach.md +1 -1
  90. package/docs/Std.Canon/ApplyToEachA.md +1 -1
  91. package/docs/Std.Canon/ApplyToEachC.md +1 -1
  92. package/docs/Std.Canon/ApplyToEachCA.md +1 -1
  93. package/docs/Std.Canon/ApplyXorInPlace.md +1 -1
  94. package/docs/Std.Canon/ApplyXorInPlaceL.md +1 -1
  95. package/docs/Std.Canon/CX.md +1 -1
  96. package/docs/Std.Canon/CY.md +1 -1
  97. package/docs/Std.Canon/CZ.md +1 -1
  98. package/docs/Std.Canon/Fst.md +1 -1
  99. package/docs/Std.Canon/MapPauliAxis.md +1 -1
  100. package/docs/Std.Canon/Relabel.md +1 -1
  101. package/docs/Std.Canon/Snd.md +1 -1
  102. package/docs/Std.Canon/SwapReverseRegister.md +1 -1
  103. package/docs/Std.Canon/index.md +1 -1
  104. package/docs/Std.Convert/BigIntAsBoolArray.md +1 -1
  105. package/docs/Std.Convert/BigIntAsInt.md +1 -1
  106. package/docs/Std.Convert/BoolArrayAsBigInt.md +1 -1
  107. package/docs/Std.Convert/BoolArrayAsInt.md +1 -1
  108. package/docs/Std.Convert/BoolArrayAsResultArray.md +1 -1
  109. package/docs/Std.Convert/BoolAsResult.md +1 -1
  110. package/docs/Std.Convert/ComplexAsComplexPolar.md +1 -1
  111. package/docs/Std.Convert/ComplexPolarAsComplex.md +1 -1
  112. package/docs/Std.Convert/DoubleAsStringWithPrecision.md +1 -1
  113. package/docs/Std.Convert/IntAsBigInt.md +1 -1
  114. package/docs/Std.Convert/IntAsBoolArray.md +1 -1
  115. package/docs/Std.Convert/IntAsDouble.md +1 -1
  116. package/docs/Std.Convert/ResultArrayAsBoolArray.md +1 -1
  117. package/docs/Std.Convert/ResultArrayAsInt.md +1 -1
  118. package/docs/Std.Convert/ResultAsBool.md +1 -1
  119. package/docs/Std.Convert/index.md +1 -1
  120. package/docs/Std.Core/Complex.md +1 -1
  121. package/docs/Std.Core/Length.md +1 -1
  122. package/docs/Std.Core/Repeated.md +1 -1
  123. package/docs/Std.Core/index.md +1 -1
  124. package/docs/Std.Diagnostics/ApplyIdleNoise.md +1 -1
  125. package/docs/Std.Diagnostics/BitFlipNoise.md +1 -1
  126. package/docs/Std.Diagnostics/CheckAllZero.md +1 -1
  127. package/docs/Std.Diagnostics/CheckOperationsAreEqual.md +1 -1
  128. package/docs/Std.Diagnostics/CheckZero.md +1 -1
  129. package/docs/Std.Diagnostics/ConfigurePauliNoise.md +1 -1
  130. package/docs/Std.Diagnostics/ConfigureQubitLoss.md +1 -1
  131. package/docs/Std.Diagnostics/DepolarizingNoise.md +1 -1
  132. package/docs/Std.Diagnostics/DumpMachine.md +1 -1
  133. package/docs/Std.Diagnostics/DumpOperation.md +1 -1
  134. package/docs/Std.Diagnostics/DumpRegister.md +1 -1
  135. package/docs/Std.Diagnostics/Fact.md +1 -1
  136. package/docs/Std.Diagnostics/NoNoise.md +1 -1
  137. package/docs/Std.Diagnostics/PhaseFlipNoise.md +1 -1
  138. package/docs/Std.Diagnostics/StartCountingFunction.md +1 -1
  139. package/docs/Std.Diagnostics/StartCountingOperation.md +1 -1
  140. package/docs/Std.Diagnostics/StartCountingQubits.md +1 -1
  141. package/docs/Std.Diagnostics/StopCountingFunction.md +1 -1
  142. package/docs/Std.Diagnostics/StopCountingOperation.md +1 -1
  143. package/docs/Std.Diagnostics/StopCountingQubits.md +1 -1
  144. package/docs/Std.Diagnostics/index.md +1 -1
  145. package/docs/Std.Intrinsic/AND.md +1 -1
  146. package/docs/Std.Intrinsic/ApplyUnitary.md +1 -1
  147. package/docs/Std.Intrinsic/CCNOT.md +1 -1
  148. package/docs/Std.Intrinsic/CNOT.md +1 -1
  149. package/docs/Std.Intrinsic/Exp.md +1 -1
  150. package/docs/Std.Intrinsic/H.md +1 -1
  151. package/docs/Std.Intrinsic/I.md +1 -1
  152. package/docs/Std.Intrinsic/M.md +1 -1
  153. package/docs/Std.Intrinsic/Measure.md +1 -1
  154. package/docs/Std.Intrinsic/Message.md +1 -1
  155. package/docs/Std.Intrinsic/R.md +1 -1
  156. package/docs/Std.Intrinsic/R1.md +1 -1
  157. package/docs/Std.Intrinsic/R1Frac.md +1 -1
  158. package/docs/Std.Intrinsic/RFrac.md +1 -1
  159. package/docs/Std.Intrinsic/Reset.md +1 -1
  160. package/docs/Std.Intrinsic/ResetAll.md +1 -1
  161. package/docs/Std.Intrinsic/Rx.md +1 -1
  162. package/docs/Std.Intrinsic/Rxx.md +1 -1
  163. package/docs/Std.Intrinsic/Ry.md +1 -1
  164. package/docs/Std.Intrinsic/Ryy.md +1 -1
  165. package/docs/Std.Intrinsic/Rz.md +1 -1
  166. package/docs/Std.Intrinsic/Rzz.md +1 -1
  167. package/docs/Std.Intrinsic/S.md +1 -1
  168. package/docs/Std.Intrinsic/SWAP.md +1 -1
  169. package/docs/Std.Intrinsic/SX.md +1 -1
  170. package/docs/Std.Intrinsic/T.md +1 -1
  171. package/docs/Std.Intrinsic/X.md +1 -1
  172. package/docs/Std.Intrinsic/Y.md +1 -1
  173. package/docs/Std.Intrinsic/Z.md +1 -1
  174. package/docs/Std.Intrinsic/index.md +1 -1
  175. package/docs/Std.Logical/Xor.md +1 -1
  176. package/docs/Std.Logical/index.md +1 -1
  177. package/docs/Std.Math/AbsComplex.md +1 -1
  178. package/docs/Std.Math/AbsComplexPolar.md +1 -1
  179. package/docs/Std.Math/AbsD.md +1 -1
  180. package/docs/Std.Math/AbsI.md +1 -1
  181. package/docs/Std.Math/AbsL.md +1 -1
  182. package/docs/Std.Math/AbsSquaredComplex.md +1 -1
  183. package/docs/Std.Math/AbsSquaredComplexPolar.md +1 -1
  184. package/docs/Std.Math/ApproximateFactorial.md +1 -1
  185. package/docs/Std.Math/ArcCos.md +1 -1
  186. package/docs/Std.Math/ArcCosh.md +1 -1
  187. package/docs/Std.Math/ArcSin.md +1 -1
  188. package/docs/Std.Math/ArcSinh.md +1 -1
  189. package/docs/Std.Math/ArcTan.md +1 -1
  190. package/docs/Std.Math/ArcTan2.md +1 -1
  191. package/docs/Std.Math/ArcTanh.md +1 -1
  192. package/docs/Std.Math/ArgComplex.md +1 -1
  193. package/docs/Std.Math/ArgComplexPolar.md +1 -1
  194. package/docs/Std.Math/Binom.md +1 -1
  195. package/docs/Std.Math/BitSizeI.md +1 -1
  196. package/docs/Std.Math/BitSizeL.md +1 -1
  197. package/docs/Std.Math/Ceiling.md +1 -1
  198. package/docs/Std.Math/Complex.md +1 -1
  199. package/docs/Std.Math/ComplexPolar.md +1 -1
  200. package/docs/Std.Math/ContinuedFractionConvergentI.md +1 -1
  201. package/docs/Std.Math/ContinuedFractionConvergentL.md +1 -1
  202. package/docs/Std.Math/Cos.md +1 -1
  203. package/docs/Std.Math/Cosh.md +1 -1
  204. package/docs/Std.Math/DivRemI.md +1 -1
  205. package/docs/Std.Math/DivRemL.md +1 -1
  206. package/docs/Std.Math/DividedByC.md +1 -1
  207. package/docs/Std.Math/DividedByCP.md +1 -1
  208. package/docs/Std.Math/E.md +1 -1
  209. package/docs/Std.Math/ExpModI.md +1 -1
  210. package/docs/Std.Math/ExpModL.md +1 -1
  211. package/docs/Std.Math/ExtendedGreatestCommonDivisorI.md +1 -1
  212. package/docs/Std.Math/ExtendedGreatestCommonDivisorL.md +1 -1
  213. package/docs/Std.Math/FactorialI.md +1 -1
  214. package/docs/Std.Math/FactorialL.md +1 -1
  215. package/docs/Std.Math/Floor.md +1 -1
  216. package/docs/Std.Math/GreatestCommonDivisorI.md +1 -1
  217. package/docs/Std.Math/GreatestCommonDivisorL.md +1 -1
  218. package/docs/Std.Math/HammingWeightI.md +1 -1
  219. package/docs/Std.Math/InverseModI.md +1 -1
  220. package/docs/Std.Math/InverseModL.md +1 -1
  221. package/docs/Std.Math/IsCoprimeI.md +1 -1
  222. package/docs/Std.Math/IsCoprimeL.md +1 -1
  223. package/docs/Std.Math/IsInfinite.md +1 -1
  224. package/docs/Std.Math/IsNaN.md +1 -1
  225. package/docs/Std.Math/LargestFixedPoint.md +1 -1
  226. package/docs/Std.Math/Lg.md +1 -1
  227. package/docs/Std.Math/Log.md +1 -1
  228. package/docs/Std.Math/Log10.md +1 -1
  229. package/docs/Std.Math/LogFactorialD.md +1 -1
  230. package/docs/Std.Math/LogGammaD.md +1 -1
  231. package/docs/Std.Math/LogOf2.md +1 -1
  232. package/docs/Std.Math/Max.md +1 -1
  233. package/docs/Std.Math/MaxD.md +1 -1
  234. package/docs/Std.Math/MaxI.md +1 -1
  235. package/docs/Std.Math/MaxL.md +1 -1
  236. package/docs/Std.Math/Min.md +1 -1
  237. package/docs/Std.Math/MinD.md +1 -1
  238. package/docs/Std.Math/MinI.md +1 -1
  239. package/docs/Std.Math/MinL.md +1 -1
  240. package/docs/Std.Math/MinusC.md +1 -1
  241. package/docs/Std.Math/MinusCP.md +1 -1
  242. package/docs/Std.Math/ModulusI.md +1 -1
  243. package/docs/Std.Math/ModulusL.md +1 -1
  244. package/docs/Std.Math/NegationC.md +1 -1
  245. package/docs/Std.Math/NegationCP.md +1 -1
  246. package/docs/Std.Math/PI.md +1 -1
  247. package/docs/Std.Math/PNorm.md +1 -1
  248. package/docs/Std.Math/PNormalized.md +1 -1
  249. package/docs/Std.Math/PlusC.md +1 -1
  250. package/docs/Std.Math/PlusCP.md +1 -1
  251. package/docs/Std.Math/PowC.md +1 -1
  252. package/docs/Std.Math/PowCP.md +1 -1
  253. package/docs/Std.Math/RealMod.md +1 -1
  254. package/docs/Std.Math/Round.md +1 -1
  255. package/docs/Std.Math/RoundHalfAwayFromZero.md +1 -1
  256. package/docs/Std.Math/SignD.md +1 -1
  257. package/docs/Std.Math/SignI.md +1 -1
  258. package/docs/Std.Math/SignL.md +1 -1
  259. package/docs/Std.Math/Sin.md +1 -1
  260. package/docs/Std.Math/Sinh.md +1 -1
  261. package/docs/Std.Math/SmallestFixedPoint.md +1 -1
  262. package/docs/Std.Math/Sqrt.md +1 -1
  263. package/docs/Std.Math/SquaredNorm.md +1 -1
  264. package/docs/Std.Math/Tan.md +1 -1
  265. package/docs/Std.Math/Tanh.md +1 -1
  266. package/docs/Std.Math/TimesC.md +1 -1
  267. package/docs/Std.Math/TimesCP.md +1 -1
  268. package/docs/Std.Math/TrailingZeroCountI.md +1 -1
  269. package/docs/Std.Math/TrailingZeroCountL.md +1 -1
  270. package/docs/Std.Math/Truncate.md +1 -1
  271. package/docs/Std.Math/index.md +1 -1
  272. package/docs/Std.Measurement/IsLossResult.md +1 -1
  273. package/docs/Std.Measurement/MResetEachZ.md +1 -1
  274. package/docs/Std.Measurement/MResetX.md +1 -1
  275. package/docs/Std.Measurement/MResetY.md +1 -1
  276. package/docs/Std.Measurement/MResetZ.md +1 -1
  277. package/docs/Std.Measurement/MResetZChecked.md +1 -1
  278. package/docs/Std.Measurement/MeasureAllZ.md +1 -1
  279. package/docs/Std.Measurement/MeasureEachZ.md +1 -1
  280. package/docs/Std.Measurement/MeasureInteger.md +1 -1
  281. package/docs/Std.Measurement/index.md +1 -1
  282. package/docs/Std.Random/DrawRandomBool.md +1 -1
  283. package/docs/Std.Random/DrawRandomDouble.md +1 -1
  284. package/docs/Std.Random/DrawRandomInt.md +1 -1
  285. package/docs/Std.Random/index.md +1 -1
  286. package/docs/Std.Range/IsRangeEmpty.md +1 -1
  287. package/docs/Std.Range/RangeEnd.md +1 -1
  288. package/docs/Std.Range/RangeReverse.md +1 -1
  289. package/docs/Std.Range/RangeStart.md +1 -1
  290. package/docs/Std.Range/RangeStep.md +1 -1
  291. package/docs/Std.Range/index.md +1 -1
  292. package/docs/Std.ResourceEstimation/AccountForEstimates.md +1 -1
  293. package/docs/Std.ResourceEstimation/AuxQubitCount.md +1 -1
  294. package/docs/Std.ResourceEstimation/BeginEstimateCaching.md +1 -1
  295. package/docs/Std.ResourceEstimation/BeginRepeatEstimates.md +1 -1
  296. package/docs/Std.ResourceEstimation/CczCount.md +1 -1
  297. package/docs/Std.ResourceEstimation/EnableMemoryComputeArchitecture.md +1 -1
  298. package/docs/Std.ResourceEstimation/EndEstimateCaching.md +1 -1
  299. package/docs/Std.ResourceEstimation/EndRepeatEstimates.md +1 -1
  300. package/docs/Std.ResourceEstimation/LeastFrequentlyUsed.md +1 -1
  301. package/docs/Std.ResourceEstimation/LeastRecentlyUsed.md +1 -1
  302. package/docs/Std.ResourceEstimation/MeasurementCount.md +1 -1
  303. package/docs/Std.ResourceEstimation/PSSPCLayout.md +1 -1
  304. package/docs/Std.ResourceEstimation/RepeatEstimates.md +1 -1
  305. package/docs/Std.ResourceEstimation/RotationCount.md +1 -1
  306. package/docs/Std.ResourceEstimation/RotationDepth.md +1 -1
  307. package/docs/Std.ResourceEstimation/SingleVariant.md +1 -1
  308. package/docs/Std.ResourceEstimation/TCount.md +1 -1
  309. package/docs/Std.ResourceEstimation/index.md +1 -1
  310. package/docs/Std.StatePreparation/ApproximatelyPreparePureStateCP.md +1 -1
  311. package/docs/Std.StatePreparation/PreparePureStateD.md +1 -1
  312. package/docs/Std.StatePreparation/PrepareUniformSuperposition.md +1 -1
  313. package/docs/Std.StatePreparation/index.md +1 -1
  314. package/docs/Std.TableLookup/Select.md +1 -1
  315. package/docs/Std.TableLookup/index.md +1 -1
  316. package/docs/index.md +1 -1
  317. package/lib/nodejs/qsc_wasm.cjs +81 -81
  318. package/lib/nodejs/qsc_wasm.d.cts +2 -1
  319. package/lib/nodejs/qsc_wasm_bg.wasm +0 -0
  320. package/lib/web/qsc_wasm.d.ts +2 -1
  321. package/lib/web/qsc_wasm.js +74 -74
  322. package/lib/web/qsc_wasm_bg.wasm +0 -0
  323. package/package.json +1 -1
  324. package/ux/atoms/controls.ts +216 -0
  325. package/ux/atoms/index.css +226 -0
  326. package/ux/atoms/index.ts +192 -0
  327. package/ux/atoms/layout.ts +730 -0
  328. package/ux/atoms/utils.ts +32 -0
  329. package/ux/chem/index.tsx +191 -0
  330. package/ux/chem/style.css +83 -0
  331. package/ux/circuit-vis/events.ts +1 -5
  332. package/ux/circuit-vis/formatters/gateFormatter.ts +1 -1
  333. package/ux/circuit-vis/process.ts +13 -5
  334. package/ux/circuit-vis/sqore.ts +10 -8
  335. 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
+ }