diff options
author | Norbert Preining <norbert@preining.info> | 2020-06-14 03:02:26 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2020-06-14 03:02:26 +0000 |
commit | 893b65e5d4c0b7cb8ebbfca9ee6b090b9a4a182c (patch) | |
tree | f6b0cff2cf2f8e30ef3edbfa6c7205e588e81515 /graphics/pgf/contrib | |
parent | 2d0067edb74f15b431d7a1e3a42b4f525986cef0 (diff) |
CTAN sync 202006140302
Diffstat (limited to 'graphics/pgf/contrib')
32 files changed, 3233 insertions, 666 deletions
diff --git a/graphics/pgf/contrib/yquant/README.md b/graphics/pgf/contrib/yquant/README.md index 56a8428524..d8d8e1afaa 100644 --- a/graphics/pgf/contrib/yquant/README.md +++ b/graphics/pgf/contrib/yquant/README.md @@ -7,8 +7,10 @@ It builds on and interacts with TiKZ, which brings an enourmous flexibility for A detailed reference with lots of examples is provided in the PDF version of this Readme. We will sketch some basic usage. +Now yquant also understands circuits written in the qasm language! + ## License -This material is subject to the LaTeX Project Public License 1.3. +This material is subject to the LaTeX Project Public License 1.3c. ## Examples Many more examples and explanations can be found in the [PDF version](https://github.com/projekter/yquant/raw/master/doc/latex/yquant/yquant-doc.pdf) of this Readme. diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test1.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test1.qasm new file mode 100644 index 0000000000..0f8dc1d4fc --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test1.qasm @@ -0,0 +1,12 @@ +# +# File: test1.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - EPR creation +# + qubit q0 + qubit q1 + + h q0 # create EPR pair + cnot q0,q1 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test10.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test10.qasm new file mode 100644 index 0000000000..4f788eb36c --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test10.qasm @@ -0,0 +1,16 @@ +# +# File: test10.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - multi-qubit gates +# also demonstrates use of classical bits + + qubit q0 + cbit c1 + qubit q2 + + h q0 + Utwo q0,c1 + S q2 + Utwo c1,q2 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test11.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test11.qasm new file mode 100644 index 0000000000..e668be717f --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test11.qasm @@ -0,0 +1,20 @@ +# +# File: test11.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - user-defined +# multi-qubit ops + + defbox fx,2,0,'U_{f(x)}' + defbox fxy,3,0,'U_{f(x,y)}' + + qubit q0 + qubit q1 + qubit q2 + + h q0 + fx q0,q1 + h q1 + fxy q0,q1,q2 + diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test12.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test12.qasm new file mode 100644 index 0000000000..d9a6a7caed --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test12.qasm @@ -0,0 +1,20 @@ +# +# File: test12.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - multi-qubit controlled +# multi-qubit operations + + defbox CU2,3,1,'U' + defbox CV2,3,1,'V' + + qubit q0 + qubit q1 + qubit q2 + + h q0 + CU2 q0,q1,q2 + h q0 + CV2 q2,q0,q1 +
\ No newline at end of file diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test13.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test13.qasm new file mode 100644 index 0000000000..a8def4239c --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test13.qasm @@ -0,0 +1,42 @@ +# +# File: test13.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - three-qubit phase +# estimation circuit with QFT and controlled-U + + defbox CU,3,1,'U' + defbox CU2,3,1,'U^2' + defbox CU4,3,1,'U^4' + def c-S,1,'S' + def c-T,1,'T' + + qubit j0,0 # QFT qubits + qubit j1,0 + qubit j2,0 + qubit s0 # U qubits + qubit s1 + + h j0 # equal superposition + h j1 + h j2 + + CU4 j0,s0,s1 # controlled-U + CU2 j1,s0,s1 + CU j2,s0,s1 + + h j0 # QFT + c-S j0,j1 + h j1 + nop j0 + c-T j0,j2 + c-S j1,j2 + h j2 + nop j0 + nop j0 + nop j1 + + measure j0 # final measurement + measure j1 + measure j2 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test14.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test14.qasm new file mode 100644 index 0000000000..ee83a46a4d --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test14.qasm @@ -0,0 +1,49 @@ +# +# File: test14.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - three-qubit FT QEC +# circuit with syndrome measurement + + defbox synd,4,0,'\txt{Process\\Syndrome}' + defbox rop,7,4,'{\symcal R}' + + qubit q0 # code data qubits + qubit q1 + qubit q2 + qubit s0,0 # syndrome measurement qubits + qubit s1,0 + cbit c0,0 # classical bits to store syndromes + cbit c1,0 + + h s0 # create EPR pair for FT meas + cnot s0,s1 + cnot q0,s0 # measure parity of q0,q1 + nop s1 # prevent cnot's from colliding + cnot q1,s1 + cnot s0,s1 # uncreate EPR + h s0 + measure s0 # measure syndrome qubits + nop s1 + measure s1 + cnot s0,c0 # copy to classical bits + nop s1 + cnot s1,c1 + space s0 + + zero s0 + zero s1 + h s0 # create EPR pair for FT meas + cnot s0,s1 + cnot q1,s0 # measure parity of q1,q2 + nop s1 # prevent cnot's from colliding + cnot q2,s1 + cnot s0,s1 # uncreate EPR + h s0 + measure s0 # measure syndrome qubits + nop s1 + measure s1 + + synd s0,s1,c0,c1 + rop s0,s1,c0,c1,q0,q1,q2 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test15.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test15.qasm new file mode 100644 index 0000000000..0d7ed35ea5 --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test15.qasm @@ -0,0 +1,17 @@ +# +# File: test15.qasm +# Date: 24-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - "D-type" measurement +# requested by Nielsen + + def MeasZ,0,'\dmeterwide{HZ_\theta}{18pt}' + + qubit q0,\psi + qubit q1,+ + + nop q0 + ZZ q0,q1 + nop q0 + MeasZ q0 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test16.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test16.qasm new file mode 100644 index 0000000000..1aa78ddfbf --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test16.qasm @@ -0,0 +1,22 @@ +# +# File: test16.qasm +# Date: 24-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - example from Nielsen +# paper on cluster states + + qubit q0,\psi + qubit q1,\psi + qubit q2,\phi + qubit q3,0 + + nop q0 + nop q0 + slash q0 + nop q1 + ZZ q1,q2 + cnot q2,q3 + nop q2 + discard q2 + dmeter q3 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test17.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test17.qasm new file mode 100644 index 0000000000..e1eefac730 --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test17.qasm @@ -0,0 +1,22 @@ +# +# File: test17.qasm +# Date: 24-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - example from Nielsen +# paper on cluster states + + def MeasH,0,'\dmeter{H}' + + qubit q0,\psi + qubit q1,+ + qubit q2,+ + qubit q3,\phi + + nop q0 + nop q2 + ZZ q0,q1 + ZZ q2,q3 + ZZ q1,q2 + MeasH q1 + MeasH q2 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test18.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test18.qasm new file mode 100644 index 0000000000..04576ece23 --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test18.qasm @@ -0,0 +1,20 @@ +# +# File: test18.qasm +# Date: 25-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - multiple-control bullet op + + def MeasH,0,'\dmeter{H}' + def Z4,3,'bullet' # handled specially + + qubit q0,\psi + qubit q1,+ + qubit q2,+ + qubit q3,\phi + + nop q0 + nop q2 + Z4 q0,q1,q2,q3 + MeasH q1 + MeasH q2 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test2.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test2.qasm new file mode 100644 index 0000000000..9b8ae9af10 --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test2.qasm @@ -0,0 +1,20 @@ +# +# File: test2.qasm +# Date: 29-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - simple teleportation circuit +# + qubit q0 + qubit q1 + qubit q2 + + h q1 # create EPR pair + cnot q1,q2 + cnot q0,q1 # Bell basis measurement + h q0 + nop q1 + measure q0 + measure q1 + c-x q1,q2 # correction step + c-z q0,q2 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test3.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test3.qasm new file mode 100644 index 0000000000..01c8247741 --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test3.qasm @@ -0,0 +1,13 @@ +# +# File: test3.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - swap circuit +# + qubit q0 + qubit q1 + + cnot q0,q1 + cnot q1,q0 + cnot q0,q1 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test4.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test4.qasm new file mode 100644 index 0000000000..c4dc61ef21 --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test4.qasm @@ -0,0 +1,23 @@ +# +# File: test4.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - quantum +# fourier transform on three qubits + + def c-S,1,'S' + def c-T,1,'T' + + qubit j0 + qubit j1 + qubit j2 + + h j0 + c-S j1,j0 + c-T j2,j0 + nop j1 + h j1 + c-S j2,j1 + h j2 + swap j0,j2 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test5.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test5.qasm new file mode 100644 index 0000000000..0a1a7e511b --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test5.qasm @@ -0,0 +1,15 @@ +# +# File: test5.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - demonstrate arbitray qubit matrix ops + + def c-P,1,'\m{e^{i\alpha} & 0 \cr 0 & e^{-i\alpha}}' + def Ryt,0,'\m{\cos{\theta}&-\sin{\theta}\cr\sin{\theta}&\cos{\theta}}' + + qubit j0 + qubit j1 + + c-P j0,j1 + Ryt j0
\ No newline at end of file diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test6.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test6.qasm new file mode 100644 index 0000000000..88d48c87ab --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test6.qasm @@ -0,0 +1,20 @@ +# +# File: test6.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - demonstrate +# multiple-qubit controlled single-q-gates + + def c-U,3,'U' + + qubit j0 + qubit j1 + qubit j2 + qubit j3 + + toffoli j0,j1,j2 + X j0 + c-U j2,j3,j0,j1 + H j2 + measure j3 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test7.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test7.qasm new file mode 100644 index 0000000000..ffc7227b20 --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test7.qasm @@ -0,0 +1,21 @@ +# +# File: test7.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - measurement +# of operator with correction + + def c-U,1,'U' + def c-V,1,'V' + + qubit q0 + qubit q1 + + H q0 + c-U q0,q1 + H q0 + measure q0 + c-V q0,q1 + nop q0 + nop q1 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test8.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test8.qasm new file mode 100644 index 0000000000..ba88ef68b4 --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test8.qasm @@ -0,0 +1,23 @@ +# +# File: test8.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - stage in +# simplification of quantum teleportation + + def c-Z,1,'Z' + + qubit q0,\psi + qubit q1,0 + qubit q2,0 + + H q1 + cnot q0,q1 + cnot q1,q2 + cnot q0,q1 + cnot q1,q2 + H q0 + c-Z q2,q0 + H q0 + H q0 diff --git a/graphics/pgf/contrib/yquant/doc/qasm/test9.qasm b/graphics/pgf/contrib/yquant/doc/qasm/test9.qasm new file mode 100644 index 0000000000..fc1486be8d --- /dev/null +++ b/graphics/pgf/contrib/yquant/doc/qasm/test9.qasm @@ -0,0 +1,20 @@ +# +# File: test9.qasm +# Date: 22-Mar-04 +# Author: I. Chuang <ichuang@mit.edu> +# +# Sample qasm input file - two-qubit gate circuit +# implementation of Toffoli + + def c-X,1,'\sqrt{X}' + def c-Xd,1,'{\sqrt{X}}^\dagger' + + qubit q0 + qubit q1 + qubit q2 + + c-X q1,q2 + cnot q0,q1 + c-Xd q1,q2 + cnot q0,q1 + c-X q0,q2 diff --git a/graphics/pgf/contrib/yquant/doc/yquant-doc.pdf b/graphics/pgf/contrib/yquant/doc/yquant-doc.pdf Binary files differindex 16dca0f393..fb714890d7 100644 --- a/graphics/pgf/contrib/yquant/doc/yquant-doc.pdf +++ b/graphics/pgf/contrib/yquant/doc/yquant-doc.pdf diff --git a/graphics/pgf/contrib/yquant/doc/yquant-doc.tex b/graphics/pgf/contrib/yquant/doc/yquant-doc.tex index 6455278430..cf32f913e6 100644 --- a/graphics/pgf/contrib/yquant/doc/yquant-doc.tex +++ b/graphics/pgf/contrib/yquant/doc/yquant-doc.tex @@ -14,8 +14,9 @@ \definecolor{darkblue}{RGB}{5, 10, 122} \usepackage[english]{babel} \usepackage[colorlinks, linkcolor=darkblue, bookmarksdepth=paragraph]{hyperref} -\usepackage{yquant,braket,hyphenat,microtype,hologo,minted} +\usepackage{yquant,braket,hyphenat,microtype,hologo,minted,import} \usetikzlibrary{quotes,fit,shapes.symbols,backgrounds,quantikz} +\useyquantlanguage{qasm} \usepackage{amsmath,adjustbox,cleveref} \usepackage[framemethod=tikz]{mdframed} % END_FOLD @@ -52,16 +53,17 @@ \endgroup\vskip-\parskip% \noindent\ignorespaces% } -\newenvironment{option}[1]{\vskip5mm% +\newenvironment{option*}[2]{\vskip5mm% \noindent\begin{minipage}[t]{\linewidth}% \begingroup% \let\minted@inline@iii=\patched@minted@inline@iii% \raggedleft% \hspace*{-1cm}% - \phantomsection\label{style:/yquant/#1}% - \texttt{\textcolor{gray}{/yquant/}\textcolor{mintgreen}{#1}}\hfill default: % + \phantomsection\label{style:/#1/#2}% + \texttt{\textcolor{gray}{/#1/}\textcolor{mintgreen}{#2}}\hfill default: % \tex}{% \end{minipage}} +\newenvironment{option}{\csname option*\endcsname{yquant}}{\csname endoption*\endcsname} \newsavebox\codeexamplebox \newenvironment{codeexample}{% @@ -196,8 +198,8 @@ \section{Introduction} This document outlines the scope and usage of the \Yquant{} package. It contains both a reference and a huge number of examples. - \Yquant{} is a package that makes typesetting quantum circuits easy; the package is not yet available on CTAN. - This alpha version~0.1.2 \emph{should} be stable and interfaces are not very likely to change in an incompatible way in the future. + \Yquant{} is a package that makes typesetting quantum circuits easy; the package is available on CTAN. + This alpha version~0.3 \emph{should} be stable and interfaces are not very likely to change in an incompatible way in the future. Please do report all issues and desirable additions. \subsection{How to read the manual} @@ -209,7 +211,9 @@ Then, have a look at \cref{sec:tikz} (or \cref{sec:alt}). \subsection{Installation} - At the moment, clone this repository or download a copy and extract the files to a path visible to your \TeX{} compiler. + The recommended way of installation is through CTAN. + A direct installation from this Git repository to obtain the latest additions and features is be possible by just cloning it to a path visible to your \TeX{} compiler. + While the repository may contain new additions, they are not thoroughly tested until they end up on CTAN; features that are not documented in this manual are entirely unreliable. For example, you may put them in the same directory as your document (if you just want to give a try), or you may extract them to \texttt{tex/latex/yquant} in your local \texttt{texmf} (followed by an update of the file name database). \subsection{Purpose of \Yquant, alternatives}\label{sec:alt} @@ -229,6 +233,8 @@ Changes to the output, while possible, will be overwritten if \texttt{qasm2circ} is run again. \pkg{qasm} output often looks sub\hyp optimal do to the fact that, e.g., rectangles are made up of four lines that do not properly connect and give a crumbly general feeling. + Note that since version~0.3, \Yquant{} understands \pkg{qasm} syntax, see \cref{sec:foreign:qasm}. + Maintenance status: last update of \pkg{qasm} in 2005. Also, \pkg{xy} was last updated in 2013, and the script is not compatible out\hyp of\hyp the\hyp box with Python~3, though an automatic conversion should work. \item \pkg{qcircuit} is probably the most\hyp widely used package. It provides commands that make it much easier to create quantum circuits using the \pkg{xy} package. @@ -243,7 +249,7 @@ It also reduces burdens of the \pkg{xy} syntax. However, the disadvantages of the grid\hyp based syntax still remain. - Maintenance status: last update in 2019; the underlying \TikZ{} is actively maintained again by now. + Maintenance status: last update in 2020; the underlying \TikZ{} is actively maintained again by now. \item \pkg{qpic} follows the approach of \pkg{qasm}: It makes use of an external Python program that reads the quantum circuits in an own language and converts them into \TikZ{} commands. The language \pkg{qpic} follows is much more powerful than \pkg{qasm}'s. The disadvantage that modifications in the output code will not remain after running the Python script again is mitigated by the possibility to define own \TeX{} macros. @@ -292,7 +298,7 @@ The optional arguments for the \tex!yquant! environment have to appear \emph{on the same line} as the environment itself. If you want to put the arguments into a new line, it is crucial to mask the line break by putting a comment symbol after the environment: \tex!\begin{yquant}%!. Without this comment, \Yquant{} will detect your line break (this is one of the few places in \TeX{} where line breaks and spaces are different) and assume that the expression in square brackets instead provides arguments for the following operation! \\ - Finally note that in (non\hyp fragile) \texttt{beamer} frames, this discrimination between spaces and new lines does not work; the optional arguments will always be counted for the environment, not for the gate. + Finally note that in (non\hyp fragile) \pkg{beamer} frames, this discrimination between spaces and new lines does not work; the optional arguments will always be counted for the environment, not for the gate. In this case, you can either declare the frame as fragile or (recommended) introduce a blank line between the environment and the options for the first gate. \end{warning} @@ -302,6 +308,7 @@ The starred form additionally supports the use of undeclared registers: it basically declares a registers upon its first usage. This will always be a \texttt{qubit} register; but if you use the corresponding option and the first usage is an \gate{init} command, you may overwrite this. + Subcircuits always use the unstarred form. Additionally, if you refer to the index $i$ of a vector register of length $L < i$, this register will automatically be enlarged to $i \coloneq L$. It is also possible to convert a scalar register into a vector register in this manner. @@ -435,6 +442,8 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] ); It will draw a \emph{main} part of the gate at the first contiguous slice of registers in the target list---you may select another register for this part by preceding the name or index with a star (which, contrary to the simplified grammar, may only occur \emph{once} in a target specification). All other contiguous slices of target registers will be drawn in a \emph{subordinate style} for this gate. Finally, all slices will be connected by a single vertical line with the style \style{/yquant/every multi line}. + Subcircuits, supported as of version~0.2, will always span the full region from the first to the last register specified in a multi\hyp qubit gate. + This is due to the fact that they may contain arbitrary ancilla registers which may be positioned somewhere in between the parts that actually constitute the subcircuit---so this whole region must not have wires of other registers crossing. \begin{warning}[Discontiguous targets and control lines] A control line extends from the very first to the very last affected register in an operation. A sub\hyp gate line that is used for discontiguous registers will only span the range of a multi\hyp register. @@ -477,6 +486,97 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] ); If there are no positive controls, the list may be empty or, together with the pipe, omitted. Preceded by a tilde (``\yquant!~!''), the list of negative controls then follows; this mimics the syntax of many programming languages that denote logical negation by a tilde. If there are no negative controls, the list may be empty or, together with the pipe, omitted. + + \clearpage + \subsection{Importing circuits from files}\label{sec:import} + Since version~0.2, \Yquant{} provides a simple way to import circuits that are stored in external files. + The macro \tex!\yquantimport! can be used in three different contexts: + \begin{itemize} + \item Outside of a \TikZ{} picture environment. \\ + In this case, \tex!\yquantimport[<options>]{<filename>}! will be equivalent to + \begin{minted}{tex} +\begin{tikzpicture} + \begin{yquant}[<options>] + % the content of <filename> goes here + \end{yquant} +\end{tikzpicture} + \end{minted} + The starred form, \tex!\yquantimport*[<options>]{<filename>}!, instead inserts the starred \Yquant{} environment. + Note that the options are always \Yquant{} options; if you want to pass \TikZ{} options, you will have to create the picture environment by yourself or change the option path to the correct one (\texttt{/tikz/.cd}). + \item Inside a \TikZ{} picture environment, but outside of a \Yquant{} environment. \\ + This is the same as before, just that no extra picture environment will be added. + \item Inside both a \TikZ{} picture environment and a \Yquant{} environment. \\ + The file will be inserted directly into the environment. + \Yquant's parser is automatically restarted after this. + The content will always be put in a \TeX{} group; if additional options are provided, \Yquant{} also inserts a \TikZ{} \tex!scope! and executes \tex!\yquantset{<options>}! directly after the scope. + If \tex!\yquantimport! is used, the content will be read as if the containing environment was an unstarred one; if \tex!\yquantimport*! is used, the content will be read as if the containing environment was a starred one. + \end{itemize} + Note that \Yquant{} internally uses plain \TeX's \tex!\import! command (i.e., \tex!\@@import! in \LaTeX). + However, when the \pkg{import} package is loaded, it uses \\ \tex!\subimport{\yquantimportpath}{<filename>}!, where \tex!\yquantimportpath! defaults to \texttt{./}---so by changing this, files from other folders may be imported which by themselves again include other files, and the relative path resolution will work. + + Note that you may in particular import the content of a \gate{subcircuit}. + + \subsection{Defining own gates} + \begin{warning}[Scope] + All gate declarations are always global. + \end{warning} + + Since version~0.2.1, if you want to define a gate that corresponds to a single \gate{box} gate with a certain pre\hyp defined content, you may use the macro\\ + \tex!\yquantdefinebox{<name>}[<style>]{<content>}!, which is far more efficient than the much more general \tex!\yquantdefinegate! introduced below. + It works in the following way: + \begin{itemize} + \item It creates a new gate with name \texttt{<name>} that can be accessed as all the other build\hyp in gates. + Note that \texttt{<name>} is case\hyp insensitive and may not contain spaces. + Special characters are allowed if \TeX{} can cope with them (i.e., no comment signs, no unbalanced braces, no backslashes...). + \item It creates a style \style{/yquant/operators/every <name>} and assigns the optional \texttt{<style>} to it. + If no style is provided, the default style will inherit from \style{/yquant/operators/every box}. + \item It defines \texttt{<content>} to be the value that is written into the box. + This \texttt{<content>} is expanded in a protected manner at the time of gate declaration. + You may need to prefix fragile macros by \tex!\protect!. + \end{itemize} + + Sometimes, you may wish to define gates that are more than just a single box---perhaps a succession of multiple gates or even multi\hyp register gates with individual operations on the input registers. \\ + Since version~0.2, \Yquant{} provides a simple macro that allows this. + The macro \tex!\yquantdefinegate{<name>}[<style>]{<content>}! works in the following way: + \begin{itemize} + \item It creates a new gate with name \texttt{<name>} that can be accessed as all the other built\hyp in gates. + Note that \texttt{<name>} is case\hyp insensitive and may not contain spaces. + Special characters are allowed if \TeX{} can cope with them (i.e., no comment signs, no unbalanced braces, no backslashes...). + \item It creates a style \style{/yquant/operators/every <name>} and assigns the optional \texttt{<style>} to it. + If no style is provided, the default style will inherit from \style{/yquant/operators/every custom gate}. + This will make the gate ``seamless,'' i.e., avoid highlighting the fact that this is a custom gate. + \item It defines a macro that contains \texttt{<content>} (expanded in a protected manner) and that will be inserted as a subcircuit whenever this gate is invoked. + This in particular means that if you use \hyperref[sec:import]{\tex!\yquantimport!} within the gate, the file will only be loaded once at the time of declaration. + \end{itemize} + When the gate is later drawn, the styles are invoked in the following order---remember custom gates are implemented by means of subcircuits---: + \begin{enumerate} + \item \style{/yquant/every operator} + \item \style{/yquant/operators/every <name>} + \item \style{/yquant/operators/every subcircuit box} + \item \style{/yquant/this operator} + \item \style{/yquant/operators/this subcircuit box} + \end{enumerate} + Gates defined in this way can only make use of the default gates or other custom gates. + They do not accept custom arguments, and it is not possible to declare own, custom shapes in this way (though other predefined shapes may be used). + If they are used in a multi\hyp qubit manner, they will never be split into contiguous slices (but their content will be, so if you use the default style that turns off the box, the only way to notice this is that intermediate unaffected gates will not be allowed to place gates within the custom gate). + + \begin{warning}[Redefining existing gates] + The above macros will issue an error if the gate already exists. + You can use \tex!\yquantredefinebox! or \tex!\yquantredefinegate! to overwrite existing gate definitions. + Note that this will overwrite \emph{any} gate, even the built\hyp in ones. + + Generally, it is discouraged to make use of this possibility. + For custom gates, if you redefine a gate as a box which was previously a general subcircuit\hyp based gate, the macro that contains the subcircuit will still be held in memory. + Overwriting built\hyp in gates will not clear the attributes associated to this gate (though required attributes will no longer be required afterwards). + Again, this is not a problem but prevents \Yquant{} from issuing potentially helpful error message if such a---now meaningless---attribute is used. + + Finally, once a built\hyp in gate is overwritten, it cannot be restored. + In particular, the register creation pseudo\hyp gates \gate{qubit}, \gate{cbit}, \gate{qubits}, and \gate{nobit} perform some magic that cannot be mimicked with custom gates. + \end{warning} + + More advanced declaration of custom gates requires the use of backend macros. + Refer to \texttt{yquant-lang.tex} for this. + For the declaration of custom shapes, see \texttt{yquant-shapes.tex} for examples. \section{Configuration}\label{sec:config} \Yquant{} uses \pkg{pgfkeys} to control its options, which are located in the path \texttt{/yquant}. @@ -560,6 +660,10 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] ); The decoration \texttt{gapped brace} allows to additionally specify the regions in which a line should be drawn by using the \texttt{/tikz/decoration/from to} key, which expects a comma\hyp separated list of dimension ranges, and which is automatically populated by \Yquant. Since it may happen that the arch of the brace needs to be shifted from the value specified in \texttt{/tikz/decoration/aspect} (else, it would be drawn into a gap), the special key \texttt{/yquant/gapped brace/apply shift} is installed, which transforms the \texttt{pos=-1} specification into a position that corresponds to the actual \texttt{aspect} value. \end{option} + + \begin{option}{every input label}!! + This style is installed for every register name label in a \gate{subcircuit} when the register is an input (or input and output) register. + \end{option} \subsection{Register outputs}\unskipOpt \begin{option}{every output}!shape=yquant-text, anchor=west, align=left! @@ -671,6 +775,12 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] ); This style is installed for every \gate{box} operator. \end{option} + \begin{option}{operators/every custom gate}!/yquant/operators/this subcircuit box/.append style={draw=none, inner sep=0pt}, /yquant/register/default name=! + This style is by default installed for every user\hyp defined gate (since version~0.2). + User\hyp defined gates are implemented via subcircuits; this style suppresses the box that surrounds the subcircuit and by default suppresses all register names. + This allows a seamless integration of the gate/subcircuit into the main circuit, without putting particular emphasis to the fact that what was defined as the custom gate indeed belongs together. + \end{option} + \begin{option}{operators/every dmeter}!shape=yquant-dmeter, x radius=2mm, y radius=2mm, fill=white, draw! This style is installed for every \gate{dmeter} gate. The \texttt{yquant-dmeter} shape consists of a rectangle whose right side is replaced by a circle, resembling the letter ``D.'' @@ -708,6 +818,28 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] ); This style is installed for every \gate{slash} pseudo\hyp gate, i.e., the one that is used to indicate that a single register line actually denotes multiple registers. \end{option} + \begin{option}{operators/every subcircuit}!! + This style is installed for every \gate{subcircuit}. + \end{option} + + \begin{option}{operators/every subcircuit box}!/yquant/operators/every box! + This style is installed for every \gate{subcircuit}. + Note that in contrast to all other styles such as \style{/yquant/operators/every subcircuit} or \style{/yquant/this operator}, this style is only applied to the ``container'' node of the subcircuit, but not to the elements in the subcircuit themselves. + \end{option} + + \begin{option}{subcircuit box style}!/yquant/operators/every subcircuit box/.append style={#1}! + This is a shorthand to apply styles to the subcircuit box only. + \end{option} + + \begin{option}{operators/this subcircuit box}!! + This style is appended to the current style installed for the \gate{subcircuit}, but will not apply to its contents. + Additionally, this style will be reset to an empty style at the beginning of each subcircuit, so that it really only applies to exactly the subcircuit box it is explicitly specified on, not to nested subcircuit boxes. + \end{option} + + \begin{option}{this subcircuit box style}!/yquant/operators/this subcircuit box/.append style={#1}! + This is a shorthand to apply styles to the current subcircuit box only. + \end{option} + \begin{option}{operators/every swap}!shape=yquant-swap, radius=.75mm, draw! This style is installed for every \gate{swap} gate that interchanges two qubits. The \texttt{yquant-swap} shape consists of a single cross. @@ -755,6 +887,9 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] ); Multiple slices in a discontiguous multi\hyp register are additionally suffixed by \texttt{-s\textit{<slice index>}}. All controls are also named, suffixed by \tex!-p\idx! or \tex!-n\idx! for positive and negative controls (i.e., the topmost positive control of the previous operator will be available as \texttt{op-p0}). Counters for target registers, positive, and negative controls are all independent. + Finally, you can even access names within a subcircuit, provided you give a name to the subcircuit. + All nodes in the subcircuit will then have the name \texttt{\textit{<subcircuit name>}-\textit{<name specified in the subcircuits>}}. + For nested subcircuits, you will get multiple prefixes. All \Yquant{} shapes have the anchors available you would typically expect from a \TikZ{} shape of the given outline. Before version~0.1.2, \Yquant{} shapes needed to provide a \texttt{circuit} anchor and projection anchors. @@ -786,9 +921,6 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] ); \item Remove the clipping paths stored so far on this register, apart from the clipping on the last gate (which will be needed again if this was not the end of the circuit). \end{itemize} \end{itemize} - -% The current version of \Yquant{} does not implement subcircuits yet. -% However, this is planned in a future version; by naming a subcircuit, all named operations inside should then also become available (prefixed by the subcircuit's name). \section{Reference: Gates and operations}\label{sec:gates} This section lists all operations \Yquant{} currently understands. @@ -943,7 +1075,12 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] ); Names are case\hyp insensitive. The register can be made into a vector register by specifying \texttt{<len>} (default \tex!1!). - \emph{Possible attributes:} none + \clearpage + \emph{Possible attributes:} + \begin{itemize} + \item \yquant![out]! or \yquant![ancilla]! (required in subcircuits) \\ + \emph{see \gate{qubit}} + \end{itemize} \subsection{\texorpdfstring{\yquant!not!}{not}}\label{gate:not} Syntax: \yquant!not <target> | <pcontrol> ~ <ncontrol>;! \\ @@ -994,6 +1131,21 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] ); \begin{itemize} \item \yquant![after=<regname>]! \\ If given, the register will start not at the left of the circuit but instead at the position at which the last gate in the register \texttt{<regname>} ended. + + This attribute may not be given in combination with \yquant![in]! or \yquant![inout]!. + \item \yquant![in]!, \yquant![out]!, \yquant![inout]!, or \yquant![ancilla]! \\ + Default: \yquant![ancilla]! for top\hyp level circuits (do not change there); \yquant![inout]! for subcircuits. + + Determines how a subcircuit interacts with its parent circuit. + + Registers declared with the \yquant![ancilla]! attribute are available only to the subcircuit; they cannot be connected to an outside wire. + + Registers declared with the \yquant![in]! or \yquant![inout]! attribute will expect an outer wire of the same type to be present and will then be identical with this outer wire. + Any changes applied to the wire within the subcircuit automatically also happen on the associated outer wire. + If the attribute is \yquant![in]!, the wire will automatically be discarded at the end of the subcircuit (and hence also in the outer circuit, where it may be re\hyp initialized). + This is different from applying the \gate{discard} gate in that the wire will still extend until the end of the subcircuit and may thus receive proper \gate{output}s. + + Registers declared with the \yquant![out]! attribute will expect a discarded outer wire to be present, which will be initialized to a \texttt{qubit} at the beginning of the subcircuit, and from then on be identical with the outer wire. \item \yquant![value=<value>]! \\ Denotes the label that is printed to the left of the wire. If the value is omitted, the default is used (\style{/yquant/register/default name}, preinitialized to \tex!\regidx!). @@ -1044,6 +1196,36 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] ); \emph{Possible attributes:} none + \subsection{\texorpdfstring{\yquant!subcircuit!}{subcircuit}}\label{gate:subcircuit} + Syntax: \yquant!subcircuit <target>;! \\ + This is a subcircuit gate which inserts independent quantum circuits at the current position within the circuit. + It may span multiple registers, but is never split into contiguous slices. + It allows for controls and may change the type of any target involved, depending on the particular subcircuit. + The style \style{/yquant/operators/every subcircuit} is installed. + + \emph{Possible attributes:} + \begin{itemize} + \item \yquant!value=<subcircuit>! (required) \\ + Denotes the content of the subcircuit. + It is specified in the usual syntax of \Yquant. + Note that, regardless of the outer environment, a subcircuit always implicitly uses the unstarred form, i.e., you must declare every register explicitly before its first usage. + This is to make sure that the interface of the circuit, i.e., which registers are taken as input and/or output parameters and in which order, is not accidentally mistaken. + + The mapping between input and output registers is trivial for single\hyp qubit uses. + For multi\hyp qubit uses, it works in the following way---in short, it matches in visual order. + You declare input and output registers by using the appropriate attributes on the \gate{qubit}, \gate{cbit}, \gate{qubits} (or even \gate{nobit}) gates. + The list of all non\hyp ancillas, from the topmost to the bottom\hyp most, forms the list of parameter registers of the subcircuit. + This is exactly the number of registers that must be supplied within one multi\hyp qubit target. + Also within the multi\hyp qubit target, we sort all registers from the topmost to the bottom\hyp most (in the order as they visually appear, not the order in which they are entered). + Those two lists of equal length are then mapped $1:1$ to each other. + Intermixing with ancillas is possible at every position and will lead to a vertical shift of the wires, until all registers, inner and outer, can be displayed flawlessly. + + As subcircuits follow the same rules as ordinary circuits, it is possible to mix them with arbitrary \TeX{} code, and also to access named gates within the subcircuit---but note that named gates in the outer circuit cannot be accessed (at least unless you play with the \texttt{name prefix} key in \TikZ). + In order to access inner nodes from the outer circuit, the subcircuit itself must be named; the inner nodes are then prefixed by the name of the subcircuit and a dash. + + It is possible to nest subcircuits arbitrarily. + \end{itemize} + \subsection{\texorpdfstring{\yquant!swap!}{swap}}\label{gate:swap} Syntax: \yquant!swap <targets> | <pcontrol> ~ <ncontrol>;! \\ This is the two\hyp qubit \textsc{swap} gate $\ketbra{00}{00} + \ketbra{01}{10} + \ketbra{10}{01} + \ketbra{11}{11}$ that exchanges two qubits. @@ -1120,6 +1302,8 @@ qubit {$\ket{<name>_{\idx}}$} <name>[<len>]; \end{minted} in the preamble, as is done here. + Note that since version~0.3, \Yquant{} supports the \pkg{qasm} syntax, see \cref{sec:foreign:qasm} + \begin{example}[test1 (create an EPR pair)] \begin{codeexample} \begin{tikzpicture} @@ -2201,7 +2385,7 @@ $=$ \node[inner, anchor=east] at (a-3 -| u.east) {\smash{$y \oplus f(x)$}}; \end{tikzpicture} \end{codeexample*} - There is no simple way to draw \emph{within} a gate, though this is probably something that will be easier using subcircuits (planned feature). + There is no simple way to draw \emph{within} a gate, unless this gate is a proper quantum circuit itself. Instead, here the intricate parts were reproduced using \TikZ: first, we make sure we assign a name to every relevant coordinate. Then we use some \TikZ{} styles to draw the braces and nodes at the intersection of these coordinates. Here, we also make use of the \texttt{moveto} decoration transformation that comes with \Yquant{} and that allows to enlarge the braces slightly for a good overall appearance. @@ -2481,7 +2665,7 @@ $=$ \end{yquant} \end{tikzpicture} \end{codeexample*} - While here, we opted for the most logical choice to name the declaration of the register, a name put to any operation on the desired register would also serve the purpose. + While here, we opted for the most logical choice to name the declaration of the register, a name put to any operation on the desired register would also serve the purpose (as long as this operation is vertically symmetrical, which subcircuits may not be). \end{example} \clearpage @@ -2646,32 +2830,51 @@ $=$ draw, inner sep=6pt, "reversed c-\textsc{not}"] {}; \end{tikzpicture} \end{codeexample*} + In this case, since version~0.2, a subcircuit may provide a similar experience: + \begin{codeexample*} +% \usetikzlibrary{quotes} +\begin{tikzpicture} + \begin{yquant*} + h a; + cnot b | a; + [this subcircuit box style={inner sep=6pt, "reversed c-\textsc{not}"}] + subcircuit { + qubit {} x; + qubit {} y; + h -; + cnot y | x; + h -; + } (-); + cnot b | a; + h b; + \end{yquant*} +\end{tikzpicture} + \end{codeexample*} + Here, we used the key \style{/yquant/this subcircuit box style} to influence only the style of the subcircuit box itself instead of providing global options that apply to every object in the subcircuit (you wouldn't want the label be assigned to every single gate). \end{example} \clearpage \begin{example} \begin{codeexample*} -% \usetikzlibrary{quotes, backgrounds} +% \usetikzlibrary{quotes} \begin{tikzpicture} \begin{yquant*} h a; - [name=left] - cnot b | a; - cnot a | b; - [name=right] - cnot b | a; + [this subcircuit box style={draw, dashed, rounded corners, fill=blue!20, inner xsep=6pt, inner ysep=10pt, "\textsc{swap}" below}, register/default name=] + subcircuit { + qubit a; + qubit b; + cnot b | a; + cnot a | b; + cnot b | a; + } (a-b); h b; \end{yquant*} - \scoped[on background layer] - \node[fit=(left-0) (left-p0) (right-0) (right-p0), - draw, dashed, rounded corners, fill=blue!20, - inner xsep=6pt, inner ysep=10pt, - "\textsc{swap}" below] {}; \end{tikzpicture} \end{codeexample*} - In this example, we need to refer to names, but want to fill the background before those nodes are actually available. - Hence, we use the layering mechanism of \TikZ{} and put the node on the background layer. - Alternatively, we could have drawn on top and used opacity to still make visible what is behind; but in general, whenever you can avoid to use opacities, do avoid it; it adds overhead at the renderer and may give sub\hyp optimal result when printing since the viewer has to reduce all elements to non\hyp overlapping parts. + Since version~0.2, fully enclosing a bunch of operations (with no controls extending to some inner component) is possible by means of \gate{subcircuit}s. + Before, this had to be done using named operations and layers. + Note that here we used the style \style{/yquant/this subcircuit box style} to assign a styling that only applies to the box containing the subcircuit, but not to the inner gates---which would have happened had we just given the arguments to the subcircuit directly. \end{example} \Yquant{} does not support the fancy nearest\hyp neighbor swap gate that \pkg{quantikz} has. @@ -2726,30 +2929,97 @@ $=$ \end{example} \endgroup + \section{Foreign language support} + \Yquant{} is built in various modules, so that it is not hard to use the quantum circuit rendering backend, but expose a different language frontend. + Since version~0.3, \Yquant{} not only understands its own language, but also others. + + \subsection{qasm} + By saying \tex!\useyquantlanguage{qasm}! in the preamble after loading \Yquant{} itself, the parser for \pkg{qasm} (not OpenQASM) is loaded. + It provides the environment \tex!qasm! as well as the macro \tex!\qasmimport!, which works similarly to \tex!\yquantimport! (but does not accept additional options). + + \subsubsection{Language specification} + The \pkg{qasm} language is not formally defined, but an overview is provided at \href{https://web.archive.org/web/20050410022847/https://www.media.mit.edu/quanta/qasm2circ/#spec}{the archived website of \texttt{qasm2circ}}. + The \Yquant{} implementation is designed to be compatible with the original parser, with the following exceptions: + \begin{itemize} + \item In \pkg{qasm}, lines could begin in an arbitrary manner; the first whitespace followed by the first valid command were then the instruction. + Contrary to this, \Yquant's parser always expects a line to start with a valid gate (preceded by arbitrary whitespaces), a comment, or to be empty. + \item In \pkg{qasm}, user\hyp defined gates will be drawn in a box unless they contain the text \texttt{\textbackslash dmeter}, and they will be recognized as measurement gates if they contain \texttt{\textbackslash meter} or \texttt{\textbackslash dmeter}. + Contrary to this, \Yquant's parser expect the gates to \emph{start} with one of the \emph{macros} \tex!\meter!, \tex!\dmeter!, or \tex!\dmeterwide!. + Using these macros \emph{within} the content of a gate does not make sense from the point of view that in \Yquant, gates are nodes with shapes, so either the full gate has a particular shape or it does not, but not only parts of it. + \item The \texttt{space} gate is supposed to produce a horizontal whitespace without a gate. + In \Yquant's implementation, you have to discard the wire if you want to reproduce this behavior; \texttt{space} and \texttt{nop} are equivalent. + \end{itemize} + + The default \pkg{qasm} style defines several macros that can be used in gates. + \Yquant{} makes \tex!\m! (matrix; requires \pkg{amsmath}) and \tex!\txt! (switch to text mode) available within the \pkg{qasm} environment. + + Do not expect \Yquant's output to match the one of \pkg{qasm} exactly. + \Yquant{} is not grid based, so that commands such as \texttt{nop} don't even make sense. + They are implemented for compatibility reasons and will produce a fixed horizontal space of the operator minimum width plus one separation, which might or might not be accurate. + + Note that whatever you write between \tex!\begin{qasm}! and \tex!\end{qasm}! is essentially treated as verbatim; only where the specification says so (in the definition of a new gate and in the optional third command to the register definition), it is interpreted as \TeX{} markup. + Consequently, in \pkg{beamer}, any frame containing these environments must be given the \texttt{verbatim} option. + + \subsubsection{Configuration} + Loading the \pkg{qasm} language interpreter will define several new configuration keys. + For all the gates, it will use the keys defined in \cref{sec:config}, and it additionally provides the following: + + \begin{option}{operators/every s}!/yquant/operators/every box! + This style is installed for every \texttt{s} operator. + \end{option} + + \begin{option}{operators/every t}!/yquant/operators/every box! + This style is installed for every \texttt{t} operator. + \end{option} + + \begin{option}{operators/every utwo}!/yquant/operators/every box! + This style is installed for every \texttt{Utwo} operator. + \end{option} + + \begin{option*}{qasm}{zero}!\qasm@ket0! + The content of this macro is used as the initialization content whenever the \texttt{zero} gate is invoked. + \end{option*} + + \begin{option*}{qasm}{register/default qubit name}!\qasm@ket{#1}! + This macro is invoked with a single parameter (the name of a qubit register) and gives back what is printed as the name of the register (will be in math mode automatically). + \end{option*} + + \begin{option*}{qasm}{register/default qubit name value}!\qasm@ket{#1} = \qasm@ket{#2}! + This macro is invoked with two parameters (the name of a qubit register and its initial value) and gives back what is printed as the name of the register (will be in math mode automatically). + \end{option*} + + \subsubsection{Examples} + The unaltered\footnote{Only in \texttt{test14.qasm}, \tex!\cal! was replaced by \tex!\symcal!---and this is only necessary as this manual was set with \pkg{unicode-math}. In traditional mode, even this would not be necessary.} \texttt{.qasm} files provided from \href{https://www.media.mit.edu/quanta/qasm2circ/}{the \texttt{qasm2circ} page} were stored in the subfolder \texttt{qasm} relative to this manual's \TeX{} file. + The following command is then used to print all of them: + \begin{minted}{tex} +% preamble: +% \usepackage{yquant,import} +% \useyquantlanguage{qasm} +\def\yquantimportpath{qasm/} +\foreach \circuitno in {1, ..., 18} { + \paragraph{Circuit \#\circuitno} + \begin{center} + \qasmimport{test\circuitno.qasm} + \end{center} +} + \end{minted} + + \def\yquantimportpath{qasm/} + \foreach \circuitno in {1, ..., 18} { + \paragraph{Circuit \#\circuitno}\leavevmode\nopagebreak\par\nopagebreak + \begin{adjustbox}{center} + \qasmimport{test\circuitno.qasm} + \end{adjustbox} + } + \section{Wishlist} This section contains some thoughts on future improvements and features. \begin{itemize} - \item Subcircuit support. \\ - A subcircuit is a quantum circuit on its own that is put into a box within other circuits. - It has input, output, and also internal wires. - Subcircuits may be declared on\hyp the\hyp fly if they are used only once, but there should also be the option to globally declare subcircuits and use them at any time. - As with ordinary quantum circuits, everything in a subcircuit should be allowed to have a name. - If the subcircuit itself is then also named, those inner names should be made available (prefixed with the subcircuit's name), to the outer circuit. - Subcircuits may also contain subcircuits. - While the number of input registers should match, a subcircuit may have more, less or different output registers. - The language needs to be extended to somehow allow for this. - Subcircuits will typically be multi\hyp qubit elements that, at least if internal wires are used, may significantly increase the required height for an individual register. - Hence, the internal height calculations must be adapted. - This will be particularly problematic if the subcircuit targets non\hyp adjacent wires. - \item Support for other languages. \\ - It would be particularly nice to introduce a language mode. - While the \Yquant{} language will always provide the set of everything \Yquant{} can do at the moment, it would be nice if \Yquant{} can automatically detect \texttt{OpenQASM} and parse its content correctly. - \texttt{OpenQASM} is much more limited than \Yquant{} and, being a language designed for actual execution of the circuits, does not provide means to change visual appearance. - Probably some \Yquant{} additions to \texttt{OpenQASM} would be ok, as long as they only complement the original language? - Also, \texttt{OpenQASM} support would probably require subcircuits. - - Another nice feature would be to support \pkg{qasm}. - Also here, the feature set is much more limited and it would probably be hard to implement an automatic detection, the user would have to specify the language by hand. + \item Support for more other languages. \\ + Since version~0.3, \Yquant{} understands \pkg{qasm}. + It would be nice if \Yquant{} could also understand \texttt{OpenQASM} correctly. + The way \texttt{OpenQASM} treats operations is a bit different from \Yquant{} and also \pkg{qasm}. + Some machinery would be required to automatically carry out transversal gates; apart from that everything should be available in \Yquant. \item Vertical layout. \\ Sometimes, long quantum circuits on a portrait page can be better represented in a vertical layout. Also if lots of explanations are to be added, this becomes problematic in the horizontal version. @@ -2773,5 +3043,15 @@ $=$ \Yquant{} now also properly draws non\hyp contiguous multi\hyp qubit operations. \\ New gate: \gate{correlate}. Various bug fixes. + + \subsection{2020-06-02: Version 0.2} + Introduce \gate{subcircuit}; required rewriting how \Yquant{} internally positions vertically. + Provide simple macros to load circuits (or parts) from a file and to declare own custom gates. + + \subsection{2020-06-07: Version 0.2.1} + Introduce a macro to declare a lightweight custom gate, which is only a single box with custom content. + + \subsection{2020-06-13: Version 0.3} + Introduce support for the \pkg{qasm} language. %END_FOLD \end{document}
\ No newline at end of file diff --git a/graphics/pgf/contrib/yquant/tex/yquant-circuit.tex b/graphics/pgf/contrib/yquant/tex/yquant-circuit.tex index 2117e7f440..2c9e114bdc 100644 --- a/graphics/pgf/contrib/yquant/tex/yquant-circuit.tex +++ b/graphics/pgf/contrib/yquant/tex/yquant-circuit.tex @@ -1,19 +1,13 @@ % BEGIN_FOLD Drawing wires -% a bit faster than nested \@firstoftwo/\@secondoftwo -% note \@thirdofthree is defined in the latex kernel already. -\long\def\@firstofthree#1#2#3{#1}% -\long\def\@secondofthree#1#2#3{#2}% -\long\def\@firstoffour#1#2#3#4{#1}% -\long\def\@secondoffour#1#2#3#4{#2}% -\long\def\@thirdoffour#1#2#3#4{#3}% -\long\def\@fourthoffour#1#2#3#4{#4}% -\long\def\@thirdandfourthoffour#1#2#3#4{#3#4}% - % extends the wire of register #1. Assumes a node called yquantbox is set up, and the \pgfshapeclippathhorzresult was set up appropriately for this node. -\protected\def\yquant@circuit@extendwire#1{% +\protected\def\yquant@circuit@extendwire#1#2{% \begingroup% - \pgfpointanchor{yquantbox}{center}% - \edef\wirexpos{\the\pgf@x}% + \ifx*#2% + \edef\wirexpos{\the\dimen0}% + \else% + \pgfpointanchor{yquantbox}{#2}% + \edef\wirexpos{\the\pgf@x}% + \fi% \yquant@register@get@typeywire{#1}\wiretype\wireypos\wirelast% \edef\wirexprevpos{\expandafter\@firstoffour\wirelast}% \ifnum\wiretype=\yquant@register@type@none% @@ -29,23 +23,46 @@ {\unexpanded\expandafter\expandafter\expandafter{% \expandafter\@thirdandfourthoffour\wirelast% }% - } + }% {\unexpanded\expandafter{\pgfshapeclippathhorzresult}}% }% \fi% \endgroup% } -% finishes the wire of registers 1 to #1 until x position \yquant@env@end@xpos +% finishes the wires of all registers until x position #1 \protected\def\yquant@circuit@endwires#1{% - \yquant@for \yquant@circuit@endwires@i := 1 to #1 { - \yquant@draw@wire\yquant@circuit@endwires@i\yquant@env@end@xpos% + \ifcsname\yquant@prefix xshift\endcsname% + \dimdef\yquant@env@end@xpos{#1+\csname\yquant@prefix xshift\endcsname}% + \else% + \def\yquant@env@end@xpos{#1}% + \fi% + \yquant@for \yquant@circuit@endwires@i := 1 to \csname\yquant@prefix registers\endcsname {% + % we only extend the wire if it does not come from the outer circuit - this one would be responsible for the extension. + \ifcsname\yquant@prefix registermap@\yquant@circuit@endwires@i\endcsname% + \xifinlistcs\yquant@circuit@endwires@i{\yquant@prefix inonly}{% + % however, the wire is to be discarded after this circuit + \edef\storedleft{\the\pgf@picminx}% + \yquant@draw@wire\yquant@circuit@endwires@i1% + \global\pgf@picminx=\storedleft% + \yquant@register@set@type\yquant@circuit@endwires@i\yquant@register@type@none% + }\relax% + \else% + \yquant@draw@wire\yquant@circuit@endwires@i1% + \fi% }% } % outputs the wire according to its previous instructions and prepares for a change in the wire style \protected\def\yquant@circuit@flushwire#1{% - \yquant@draw@wire{#1}{}% + \ifcsname\yquant@prefix registermap@#1\endcsname% + % make sure drawing the wire does not affect our left bounding box position + \edef\storedleft{\the\pgf@picminx}% + \yquant@draw@wire{#1}0% + \global\pgf@picminx=\storedleft% + \else% + \yquant@draw@wire{#1}0% + \fi% \begingroup% \yquant@register@get@lastwire{#1}\wirelast% \yquant@register@set@lastwire{#1}{% @@ -156,6 +173,8 @@ \let\yquant@circuit@operator@mintarget=\yquant@register@get@ids@min% \let\yquant@circuit@operator@maxtarget=\yquant@register@get@ids@max% \let\yquant@circuit@operator@numtarget=\yquant@register@get@ids@count% + % make sure to reset this for subcircuits + \yquant@circuit@operator@hasControlsfalse% % For the targets, multi-qubit registers might have been allowed, but certainly not for % the controls! \yquant@register@get@allowmultifalse% @@ -198,92 +217,64 @@ }% } -% BEGIN_FOLD Subcircuit-related -% Does all necessary calculations for inserting a sub-circuit -% #1: subcircuit code (should start with \begin{yquant}) -%\newbox\yquant@circuit@subcircuit@box -%\protected\long\def\yquant@circuit@subcircuit#1{% -% % We need to place the inner circuit at the correct position; but for this, we need -% % its extent. For this, we first place it within a box. But this box is then -% % integrated seamlessly, in particular, named nodes must be re-placed. We use a lot of -% % inspiration from pgf's matrix capabilities. -% % First, we anticipate the macro that is used by our subcircuit to store the node -% % names. -% \edef\yquant@circuit@subcircuit@nodelist{yquant@env\the\numexpr\yquant@env+1\relax @circuit@subcircuit@nodelist}% -% \global\cslet\yquant@circuit@subcircuit@nodelist\empty% -% \pgfinterruptboundingbox% -% % we make sure there are no conflicts by prefixing any named nodes in any case. -% \ifx\yquant@lang@attr@name\empty% -% \pgfkeys{/tikz/name prefix/.expanded={sub\yquant@prefix-}}% -% \else% -% \pgfkeys{/tikz/name prefix/.expanded={\pgfkeysvalueof{/tikz/name prefix}\yquant@lang@attr@name-}}% -% \fi% -% \let\pgf@nodecallback=\yquant@circuit@subcircuit@nodecallback% -% \pgftransformreset% -% \global\setbox\yquant@circuit@subcircuit@box=\hbox{{% -% % bypass 'overlay' option -% \pgf@relevantforpicturesizetrue% -% \pgfsys@beginpicture% -% #1% -% \pgfsys@endpicture% -% \ifdim\pgf@picmaxx=-16000pt % -% \global\pgf@picmaxx=0pt % -% \global\pgf@picminx=0pt % -% \global\pgf@picmaxy=0pt % -% \global\pgf@picminy=0pt % -% \fi% -% }}% -% \wd\yquant@circuit@subcircuit@box=0pt % -% \global\setbox\yquant@circuit@subcircuit@box=\hbox{{% -% \hskip-\pgf@picminx% -% \unhbox\yquant@circuit@subcircuit@box% -% \hskip\pgf@picmaxx% -% }}% -% \ht\yquant@circuit@subcircuit@box=\pgf@picmaxy% -% \dp\yquant@circuit@subcircuit@box=-\pgf@picminy% -% % We need to remember the offset for the coordinate shifts -% \dimgdef\yquant@circuit@subcircuit@shiftx{-\pgf@picminx}% -% \endpgfinterruptboundingbox% -% \ifx\yquant@lang@attr@name\empty% -% % However, if the outer node was not named, no access to the inner nodes is desired, -% % so we delete all nodes again. -% \def\do##1{% -% \csgundef{pgf@sh@ns@##1}% -% \csgundef{pgf@sh@np@##1}% -% \csgundef{pgf@sh@nt@##1}% -% \csgundef{pgf@sh@pi@##1}% -% \csgundef{pgf@sh@ma@##1}% -% }% -% \dolistcsloop\yquant@circuit@subcircuit@nodelist% -% \global\cslet\yquant@circuit@subcircuit@nodelist\empty% -% \else% -% % But now access is desired, and probably we are deeply nested. Append the sublist to ours, so that our parent can re-map them again. -% \ifx\pgf@nodecallback\yquant@circuit@subcircuit@nodecallback% -% \csxappto{\yquant@prefix circuit@subcircuit@nodelist}% -% {\csname\yquant@circuit@subcircuit@nodelist\endcsname}% -% \fi% -% \fi% -%} -% -%\def\yquant@circuit@subcircuit@nodecallback#1{% -% \listcsxadd{\yquant@prefix circuit@subcircuit@nodelist}{#1}% -%} - -%\protected\def\yquant@circuit@subcircuit@shiftnodes#1{% -% \expandafter\unless\expandafter\ifx\csname\yquant@circuit@subcircuit@nodelist\endcsname\empty{% -% \pgftransformreset% -% \pgf@process{\pgfpointanchor{#1}{text}}% -% \edef\yquant@circuit@subcircuit@offset{% -% \noexpand\pgfqpoint{\the\dimexpr\pgf@x+\yquant@circuit@subcircuit@shiftx\relax}% -% {\the\dimexpr\pgf@y\relax}% -% }% -% \def\do##1{% -% \pgf@shift@node{##1}\yquant@circuit@subcircuit@offset% -% }% -% \dolistcsloop\yquant@circuit@subcircuit@nodelist% -% }\fi% -%} -% END_FOLD +% creates a subcircuit. Parameter registers must be filled in \yquant@circuit@subcircuit@params. +\protected\def\yquant@circuit@subcircuit#1{% + \numdef\yquant@circuit@subcircuit@id{\yquant@env+1}% + \listcsxadd{\yquant@prefix subcircuits}{\yquant@circuit@subcircuit@id}% + \begingroup% + \tikzset{/yquant/every operator, #1,% + /yquant/this operator, /yquant/operators/this subcircuit box/.style={}}% + % execute the subcircuit + \expandafter% + \yquant@env@begin@noarg% + \yquant@lang@attr@value% this contains the subcircuit's content + \expandafter\unless\expandafter\ifx\csname\yquant@prefix parameters\endcsname\empty% + \PackageError{yquant.sty}{Invalid subcircuit parameters count}% + {Too many parameters given.}% + \fi% + \global\cslet{\yquant@prefix parameters}\yquant@circuit@subcircuit@param% + \dimen0=\yquant@config@register@sep% + % the first input must count all its height plus everything that is above it in the subcircuit as the height of the outer wire it is attached to + \edef\firstinput{% + \expandafter\expandafter\expandafter% + \@firstoftwo\csname\yquant@prefix firstinput\endcsname% + }% + \edef\outerfirst{% + \expandafter\expandafter\expandafter% + \@secondoftwo\csname\yquant@prefix firstinput\endcsname% + }% + \dimen2=\yquant@register@get@height\firstinput\relax% + \ifnum\firstinput>1 % + \yquant@fordown \i := \the\numexpr\firstinput-1\relax downto 1 {% + \advance\dimen2 by \dimexpr\yquant@register@get@height\i+% + \yquant@register@get@depth\i+\dimen0\relax% + }% + \fi% + % the last input must count all its depth plus everything that is below it in the subcircuit as the depth of the outer wire it is attached to + \edef\lastinput{% + \expandafter\expandafter\expandafter% + \@firstoftwo\csname\yquant@prefix lastinput\endcsname% + }% + \edef\outerlast{% + \expandafter\expandafter\expandafter% + \@secondoftwo\csname\yquant@prefix lastinput\endcsname% + }% + \dimen4=\yquant@register@get@depth\lastinput\relax% + \ifnum\lastinput<\csname\yquant@prefix registers\endcsname% + \yquant@for \i := \the\numexpr\lastinput+1\relax to \csname\yquant@prefix registers\endcsname {% + \advance\dimen4 by \dimexpr\yquant@register@get@height\i+% + \yquant@register@get@depth\i+\dimen0\relax% + }% + \fi% + \begingroup% + \let\yquant@prefix=\yquant@parent% + \yquant@register@update@height\outerfirst{\the\dimen2}% + \yquant@register@update@depth\outerlast{\the\dimen4}% + \endgroup% + % we cannot make more precise statements about the inputs in between - for example, if input 1 is mapped to outer wire 1 and input 2 to outer wire 5, how to split the heights/depth appropriately between the outer wires 1-5? + \yquant@env@end% + \endgroup% +} % BEGIN_FOLD Helpers for operator callbacks % turn a wire into a different type @@ -358,67 +349,42 @@ } \protected\long\def\yquant@circuit@output@do#1#2#3{% - % this must only be called at the end of an environment, where \yquant@env@end@xpos is - % set up properly! + % this must only be called at the end of an environment, where \yquant@env@end@xpos is set up properly! It not only has to provide the appropriate drawing commands for later, but also has to measure the actual width of the outputs, which is required for proper subcircuit positioning. \def\do##1{% - \ifyquant@firsttoken\yquant@register@multi{##1}{% - \csxappto{\yquant@prefix draw}% - {\noexpand\yquant@circuit@output@do@multi% - \yquant@circuit@output@do@multi@@extract##1{\unexpanded{#3}}}% - }{% - \csgappto{\yquant@prefix draw}% - {\yquant@circuit@output@do@single{##1}{#3}}% - }% - }% - \csgappto{\yquant@prefix draw}{% - \yquant@circuit@output@group{#2}% - } - % \dolistloop will carry out one \expandafter on the argument; but this expansion step - % is already done. If #1 starts with \yquant@register@multi, this will be expanded once - % despite \protected, so insert some expand-to-nothing token first. - \dolistloop{\empty#1}% - \csgappto{\yquant@prefix draw}{% - \yquant@circuit@output@endgroup% + \pgfinterruptboundingbox% + \yquant@env@virtualize@path% + \ifyquant@firsttoken\yquant@register@multi{##1}{% + \csxappto{\yquant@prefix draw}% + {\yquant@draw@output@multi% + \yquant@circuit@output@do@multi@@extract##1{\unexpanded{#3}}}% + \yquant@draw@@output@multi{#3}% + }{% + \csgappto{\yquant@prefix draw}% + {\yquant@draw@output@single{##1}{#3}}% + \yquant@draw@@output@single{##1}{#3}% + \yquant@register@update@height{##1}{\the\pgf@picmaxy}% + \yquant@register@update@depth{##1}{\the\dimexpr-\pgf@picminy\relax}% + }% + \ifdim\pgf@picmaxx>\csname\yquant@prefix xmax\endcsname% + \csxdef{\yquant@prefix xmax}{\the\pgf@picmaxx}% + \fi% + \endpgfinterruptboundingbox% }% + \yquant@draw@output@group{#2}% + \csgappto{\yquant@prefix draw}{% + \yquant@draw@output@group{#2}% + }% + % \dolistloop will carry out one \expandafter on the argument; but this expansion step + % is already done. If #1 starts with \yquant@register@multi, this will be expanded once + % despite \protected, so insert some expand-to-nothing token first. + \dolistloop{\empty#1}% + \csgappto{\yquant@prefix draw}{% + \yquant@draw@output@endgroup% + }% + \yquant@draw@output@endgroup% } \def\yquant@circuit@output@do@multi@@extract#1#2#3#4#5{% {#2}{#3}{#5}% } - -\protected\long\def\yquant@circuit@output@group#1{% - \begingroup% - \def\idx{0}% - \yquant@set{#1}% -} - -\let\yquant@circuit@output@endgroup=\endgroup% - -\long\def\yquant@circuit@output@do@single#1#2{% - \path - (\yquant@env@end@xpos, \yquant@register@get@y{#1}) - node[/yquant/every output, - /yquant/every \ifcase\yquant@register@get@type{#1} nobit\or qubit\or cbit\or qubits\fi\space output] {#2}; - \numdef\idx{\idx+1}% -} - -\long\def\yquant@circuit@output@do@multi#1#2#3#4{% - % extremely similar to \yquant@draw@multiinit - \@tempdima=-.5\dimexpr\yquant@config@register@sep\relax% - \dimdef\yquant@draw@multiinit@@min{\yquant@register@get@y{#1}-\@tempdima}% - \dimdef\yquant@draw@multiinit@@max{\yquant@register@get@y{#2}+\@tempdima}% - \dimdef\yquant@draw@multiinit@@total{% - \yquant@draw@multiinit@@max-\yquant@draw@multiinit@@min% - }% - \def\pgfdecorationsegmentaspect{0}% - \let\yquant@register@multi@contiguous=\yquant@draw@multiinit@contiguous% - \let\pgfdecorationsegmentfromto=\empty% - #3% - \edef\pgfdecorationsegmentfromto{\expandafter\@gobble\pgfdecorationsegmentfromto}% - \path[/yquant/every multi output] - (\yquant@env@end@xpos, \yquant@draw@multiinit@@min) -- - (\yquant@env@end@xpos, \yquant@draw@multiinit@@max) - node {#4};% - \numdef\idx{\idx+1}% -} % END_FOLD
\ No newline at end of file diff --git a/graphics/pgf/contrib/yquant/tex/yquant-config.tex b/graphics/pgf/contrib/yquant/tex/yquant-config.tex index c1a74fecb4..a6765d1485 100644 --- a/graphics/pgf/contrib/yquant/tex/yquant-config.tex +++ b/graphics/pgf/contrib/yquant/tex/yquant-config.tex @@ -1,145 +1,151 @@ -\pgfdeclaremetadecoration{tikz@internal}{pre}{ - \state{pre}[width=\pgfkeysvalueof{/pgf/decoration/pre length}+\pgfkeysvalueof{/pgf/decoration/post length}, next state=main]{ - \appto\tikz@dec@shift{\pgftransformxshift{-\pgfkeysvalueof{/pgf/decoration/post length}}} - \tikz@dec@trans - \decoration{\pgfkeysvalueof{/pgf/decoration/pre}} - } - \state{main}[width=\pgfmetadecoratedremainingdistance, next state=final]{ - \tikz@dec@trans - \decoration{\tikz@decoration@name} - } - \state{final}{ - \tikz@dec@trans - \decoration{\pgfkeysvalueof{/pgf/decoration/post}} - } +\pgfdeclaremetadecoration{tikz@internal}{pre}{% + \state{pre}[width=\pgfkeysvalueof{/pgf/decoration/pre length}+\pgfkeysvalueof{/pgf/decoration/post length}, next state=main]{% + \appto\tikz@dec@shift{\pgftransformxshift{-\pgfkeysvalueof{/pgf/decoration/post length}}}% + \tikz@dec@trans% + \decoration{\pgfkeysvalueof{/pgf/decoration/pre}}% + }% + \state{main}[width=\pgfmetadecoratedremainingdistance, next state=final]{% + \tikz@dec@trans% + \decoration{\tikz@decoration@name}% + }% + \state{final}{% + \tikz@dec@trans% + \decoration{\pgfkeysvalueof{/pgf/decoration/post}}% + }% } -\pgfqkeys{/yquant}{ +\pgfqkeys{/yquant}{% every circuit/.style={% every node/.prefix style={transform shape},% every label/.prefix style={transform shape=false}% TODO: no, we don't really want this, but pgf bug #843 requires this if we still want to have `label position` available - }, + },% % register settings register/default name/.store in=% - \yquant@config@register@default@name, + \yquant@config@register@default@name,% register/minimum height/.code=% - {\dimdef\yquant@config@register@minimum@height{#1}}, + {\dimdef\yquant@config@register@minimum@height{#1}},% register/separation/.code=% - {\dimdef\yquant@config@register@sep{#1}}, + {\dimdef\yquant@config@register@sep{#1}},% % register label style every label/.style=% - {shape=yquant-text, anchor=center, align=right}, + {shape=yquant-text, anchor=center, align=right},% every initial label/.style=% - {anchor=east}, + {anchor=east},% every qubit label/.style=% - {}, + {},% every cbit label/.style=% - {}, + {},% every qubits label/.style=% - {}, + {},% every multi label/.style=% - {shift={(-.075, 0)}, draw, decoration={gapped brace, mirror}, decorate, /yquant/gapped brace/apply shift, - every node/.append style={shape=yquant-text, anchor=east, align=right, shift={(-.05, 0)}, pos=-1}}, + {shift={(-.075, 0)}, draw, decoration={gapped brace, mirror}, decorate, /yquant/gapped brace/apply shift,% + every node/.append style={shape=yquant-text, anchor=east, align=right, shift={(-.05, 0)}, pos=-1}},% + every input label/.style=% + {},% % output label styles every output/.style=% - {shape=yquant-text, anchor=west, align=left}, + {shape=yquant-text, anchor=west, align=left},% every qubit output/.style=% - {}, + {},% every cbit output/.style=% - {}, + {},% every qubits output/.style=% - {}, + {},% every multi output/.style=% - {shift={(.075, 0)}, draw, decoration={gapped brace}, decorate, /yquant/gapped brace/apply shift, - every node/.append style={shape=yquant-text, anchor=west, align=left, shift={(.05, 0)}, pos=-1}}, + {shift={(.075, 0)}, draw, decoration={gapped brace}, decorate, /yquant/gapped brace/apply shift,% + every node/.append style={shape=yquant-text, anchor=west, align=left, shift={(.05, 0)}, pos=-1}},% % wire style every wire/.style=% - {draw}, + {draw},% every qubit wire/.style=% - {}, + {},% every cbit wire/.style=% - {}, + {},% every qubits wire/.style=% - {}, + {},% % operator settings operator/separation/.code=% - {\dimdef\yquant@config@operator@sep{#1}}, + {\dimdef\yquant@config@operator@sep{#1}},% operator/minimum width/.code=% - {\dimdef\yquant@config@operator@minimum@width{#1}}, + {\dimdef\yquant@config@operator@minimum@width{#1}},% operator/multi warning/.is if=% - yquant@config@operator@multi@warn, + yquant@config@operator@multi@warn,% % operator style: control every control line/.style=% - {draw}, + {draw},% every control/.style=% - {shape=yquant-circle, anchor=center, radius=.5mm}, + {shape=yquant-circle, anchor=center, radius=.5mm},% every positive control/.style=% - {fill=black}, + {fill=black},% every negative control/.style=% - {draw}, + {draw},% % operator style: main part every operator/.style=% - {anchor=center}, + {anchor=center},% operator/multi main/.is if=% - yquant@config@operator@multi@main, + yquant@config@operator@multi@main,% operator/multi as single/.style=% - {/yquant/every multi line/.style=/yquant/every control line}, + {/yquant/every multi line/.style=/yquant/every control line},% every multi line/.style=% - {draw, decoration={snake, amplitude=.25mm, segment length=5pt}, decorate}, + {draw, decoration={snake, amplitude=.25mm, segment length=5pt}, decorate},% % overwriting all styles this operator/.style=% - {}, + {},% this control/.style=% - {}, + {},% operator style/.style=% - {/yquant/this operator/.append style={#1}}, + {/yquant/this operator/.append style={#1}},% control style/.style=% - {/yquant/every control line/.append style={#1}, - /yquant/this control/.append style={#1}}, + {/yquant/every control line/.append style={#1},% + /yquant/this control/.append style={#1}},% style/.style=% - {/yquant/this operator/.append style={#1}, - /yquant/every control line/.append style={#1}, - /yquant/this control/.append style={#1}}, + {/yquant/this operator/.append style={#1},% + /yquant/every control line/.append style={#1},% + /yquant/this control/.append style={#1}},% % different operator appearances operators/every box/.style=% - {shape=yquant-rectangle, draw, align=center, inner xsep=1mm, x radius=2mm, y radius=2.47mm}, - operators/every h/.style=% - {/yquant/operators/every box}, + {shape=yquant-rectangle, draw, align=center, inner xsep=1mm, x radius=2mm, y radius=2.47mm},% + operators/every subcircuit/.style=% + {},% + operators/every subcircuit box/.style=% + {/yquant/operators/every box},% + subcircuit box style/.style=% + {/yquant/operators/every subcircuit box/.append style={#1}},% + operators/this subcircuit box/.style=% + {},% + this subcircuit box style/.style=% + {/yquant/operators/this subcircuit box/.append style={#1}},% + operators/every custom gate/.style=% + {/yquant/operators/this subcircuit box/.append style={draw=none, inner sep=0pt},% + /yquant/register/default name=}, + % every h, every x, every y, every z are implicitly defined during gate declaration operators/every pauli/.style=% - {/yquant/operators/every box}, - operators/every x/.style=% - {/yquant/operators/every pauli}, - operators/every y/.style=% - {/yquant/operators/every pauli}, - operators/every z/.style=% - {/yquant/operators/every pauli}, -% operators/every subcircuit/.style=% -% {/yquant/operators/every box, inner ysep=0pt}, + {/yquant/operators/every box},% operators/every phase/.style=% - {shape=yquant-circle, radius=.5mm, fill}, + {shape=yquant-circle, radius=.5mm, fill},% operators/every zz/.style=% - {shape=yquant-circle, radius=.5mm, fill}, + {shape=yquant-circle, radius=.5mm, fill},% operators/every xx/.style=% - {shape=yquant-rectangle, radius=.75mm, draw}, + {shape=yquant-rectangle, radius=.75mm, draw},% operators/every slash/.style=% - {shape=yquant-slash, x radius=.5mm, y radius=.7mm, draw}, + {shape=yquant-slash, x radius=.5mm, y radius=.7mm, draw},% operators/every swap/.style=% - {shape=yquant-swap, radius=.75mm, draw}, + {shape=yquant-swap, radius=.75mm, draw},% operators/every not/.style=% - {shape=yquant-oplus, radius=1.3mm, draw}, + {shape=yquant-oplus, radius=1.3mm, draw},% operators/every measure/.style=% - {shape=yquant-measure, x radius=4mm, y radius=2.5mm, draw}, + {shape=yquant-measure, x radius=4mm, y radius=2.5mm, draw},% operators/every measure meter/.style=% - {draw, -{Latex[length=2.5pt]}}, + {draw, -{Latex[length=2.5pt]}},% operators/every dmeter/.style=% - {shape=yquant-dmeter, x radius=2mm, y radius=2mm, draw}, + {shape=yquant-dmeter, x radius=2mm, y radius=2mm, draw},% operators/every barrier/.style=% - {shape=yquant-line, dashed, draw}, + {shape=yquant-line, dashed, draw},% operators/every wave/.style=% - {shape=yquant-circle, radius=.5mm, fill}, - /pgf/decoration/from to/.store in=\pgfdecorationsegmentfromto, + {shape=yquant-circle, radius=.5mm, fill},% + /pgf/decoration/from to/.store in=\pgfdecorationsegmentfromto,% gapped brace/apply shift/.code={% \let\tikz@timer@line=\yquant@gappedbrace@timer% - }, + },% } \def\yquant@config@register@default@name{\regidx} @@ -162,7 +168,7 @@ \ifdim\tikz@time pt=-1pt % % first set \pgfdecoratedremainingdistance appropriately \pgfpointdiff\tikz@timer@start\tikz@timer@end% - \pgfmathsqrt@{\dimexpr\pgf@x*\pgf@x/65536+\pgf@y*\pgf@y/65536\relax\@gobbletwo} + \pgfmathsqrt@{\dimexpr\pgf@x*\pgf@x/65536+\pgf@y*\pgf@y/65536\relax\@gobbletwo}% \pgfdecoratedremainingdistance=\pgfmathresult pt % % now perform the transformation \pgf@xc=\pgfdecorationsegmentaspect\pgfdecoratedremainingdistance% diff --git a/graphics/pgf/contrib/yquant/tex/yquant-draw.tex b/graphics/pgf/contrib/yquant/tex/yquant-draw.tex index c89eb3ef98..ec4dc80837 100644 --- a/graphics/pgf/contrib/yquant/tex/yquant-draw.tex +++ b/graphics/pgf/contrib/yquant/tex/yquant-draw.tex @@ -3,7 +3,11 @@ \protected\def\yquant@draw@group#1#2#3#4#5{% \begingroup% - \def\yquant@draw@@x{#1}% + \ifcsname\yquant@prefix xshift\endcsname% + \dimdef\yquant@draw@@x{#1+\csname\yquant@prefix xshift\endcsname}% + \else% + \def\yquant@draw@@x{#1}% + \fi% \ifx F#2% \yquant@draw@@currentcontroltype=0 % \else% @@ -65,7 +69,7 @@ /yquant/this operator}% }% \cmd% - \yquant@circuit@extendwire{#1}% + \yquant@circuit@extendwire{#1}{center}% \expandafter\yquant@circuit@extendcontrolline\expandafter% {\the\yquant@draw@@currentcontroltype}\yquant@draw@@x% % check for empty name parameter @@ -106,14 +110,14 @@ y radius/.expanded=\the\dimexpr.5\dimexpr\yquant@register@get@ydist{#1}{#2}\relax\relax+% .5*\noexpand\pgfkeysvalueof{/tikz/y radius}\fi,% name prefix=, name suffix=, name=yquantbox]% - {\unexpanded\expandafter{\yquant@draw@@content}}; + {\unexpanded\expandafter{\yquant@draw@@content}};% \pgfshapeclippath{yquantbox}% {/yquant/every operator, \yquant@draw@@style,% /yquant/this operator}% }% \cmd% \yquant@for \i := #1 to #2 {% - \yquant@circuit@extendwire\i% + \yquant@circuit@extendwire\i{center}% }% \yquant@circuit@extendmultiline\yquant@draw@@x% \expandafter\yquant@circuit@extendcontrolline\expandafter% @@ -148,7 +152,7 @@ (\yquant@draw@@x, \yquant@draw@multiinit@@min) --% (\yquant@draw@@x, \yquant@draw@multiinit@@max)% node[name prefix=, name suffix=, name=yquantbox]% - {\unexpanded\expandafter{\yquant@draw@@content}}; + {\unexpanded\expandafter{\yquant@draw@@content}};% }% \cmd% % no wire extension (we are still at the initial position), no control line (init doesn't allow for those, so just save the no-op), no multi line @@ -197,6 +201,162 @@ \fi% } +\newbox\yquant@draw@subcircuit@box + +\protected\def\yquant@draw@subcircuit@nodecallback#1{% + \ifstrequal{#1}{yquantbox}\relax{% + \listcsxadd{\yquant@prefix draw@subcircuit@nodelist}{#1}% + }% +} + +\protected\long\def\yquant@draw@subcircuit@prepare#1#2{% + \let\idx=\yquant@draw@@idx@content% + % In order to wrap the inner circuit in a proper box operator and clip outer paths appropriately (which was not possible yet, as we didn't know the exact vertical positions), we first place it within a box. During the setup time, we assumed that the subcircuit be placed at position #3; however, now, this has changed due to the additional box. + % First, we anticipate the macro that is used by our subcircuit to store the node + % names. + \edef\yquant@draw@subcircuit@nodelist{yquant@env#1@draw@subcircuit@nodelist}% + \global\cslet\yquant@draw@subcircuit@nodelist\empty% + \pgfinterruptboundingbox% + \let\yquant@parent=\yquant@prefix% + \def\yquant@prefix{yquant@env#1@}% + \ifstrempty{#2}{% + % we make sure there are no conflicts by prefixing any named nodes in any case. + \pgfkeys{/tikz/name prefix/.expanded={sub\yquant@prefix-}}% + \let\pgf@nodecallback=\yquant@draw@subcircuit@nodecallback% + }{% + \pgfkeys{/tikz/name prefix/.expanded={\pgfkeysvalueof{/tikz/name prefix}#2-}}% + }% + \letcs\xmin{\yquant@prefix xmin}% + \letcs\xmax{\yquant@prefix xmax}% + \global\setbox\yquant@draw@subcircuit@box=\hbox to 0pt {{% + % bypass 'overlay' option + \pgf@relevantforpicturesizetrue% + \pgfsys@beginpicture% + % reset all styles to the expected defaults (similar, but extended to \pgfpicture, see pgf issue #870) + \pgfsetcolor{.}% + \pgfsetlinewidth{0.4pt}% + \pgfsetbuttcap% + \pgfsetmiterjoin% + \pgfsetmiterlimit{10}% + \pgfsetdash{}{0pt}% + % The left outer position of our box will be \yquant@draw@@x-.5(xmax-xmin). + % To compensate for, we perform a left shift of all commands that take explicit coordinates from the subcircuit. + % The y positions, on the other hand, are exactly the ones as they should be integrated in the picture. + \csdimdef{\yquant@prefix xshift}{\yquant@draw@@x-.5\dimexpr\xmax+\xmin\relax}% + \csname\yquant@prefix draw\endcsname% + \ifdim\pgf@picmaxx=-16000pt % + \global\pgf@picmaxx=0pt % + \global\pgf@picminx=0pt % + \global\pgf@picmaxy=0pt % + \global\pgf@picminy=0pt % + \fi% + \ifyquantdebug% + \pgf@relevantforpicturesizefalse% + \draw[green] (current bounding box.north east) rectangle (current bounding box.south west);% + \fi% + \pgfsys@endpicture% + }}% + \global\setbox\yquant@draw@subcircuit@box=\hbox to \dimexpr\xmax-\xmin\relax {% + \hskip-\dimexpr\yquant@draw@@x-.5\dimexpr\xmax-\xmin\relax\relax% + \lower\pgf@picmaxy% + \box\yquant@draw@subcircuit@box% + }% + \ht\yquant@draw@subcircuit@box=0pt% + \dp\yquant@draw@subcircuit@box=\dimexpr\pgf@picmaxy-\pgf@picminy\relax% + \expandafter% + \endpgfinterruptboundingbox% + \expandafter\edef\expandafter\yquant@draw@subcircuit@y\expandafter{% + \the\dimexpr.5\pgf@picminy+.5\pgf@picmaxy\relax% + }% + \ifstrempty{#2}{% + % However, if the outer node was not named, no access to the inner nodes is desired, so we delete all nodes again. + \def\do##1{% + \csgundef{pgf@sh@ns@##1}% + \csgundef{pgf@sh@np@##1}% + \csgundef{pgf@sh@nt@##1}% + \csgundef{pgf@sh@pi@##1}% + \csgundef{pgf@sh@ma@##1}% + }% + \dolistcsloop{\yquant@draw@subcircuit@nodelist}% + \csgundef\yquant@draw@subcircuit@nodelist% + }{% + \ifcsname\yquant@prefix draw@subcircuit@nodelist\endcsname% + \csxappto{\yquant@prefix draw@subcircuit@nodelist}% + {\csname\yquant@draw@subcircuit@nodelist\endcsname}% + \fi% + }% +} + +\protected\long\def\yquant@draw@subcircuit@single#1#2#3{% + \yquant@draw@subcircuit@prepare{#2}{#3}% + \edef\cmd{% + \noexpand\path (\yquant@draw@@x, \yquant@draw@subcircuit@y)% + node[/yquant/every operator, \yquant@draw@@style,% + /yquant/operators/every subcircuit box, /yquant/this operator,% + /yquant/operators/this subcircuit box,% + name prefix=, name suffix=, name=yquantbox]% + {\box\yquant@draw@subcircuit@box};% + \pgfshapeclippath{yquantbox}% + {/yquant/every operator, \yquant@draw@@style,% + /yquant/operators/every subcircuit box, /yquant/this operator,% + /yquant/operators/this subcircuit box}% + }% + \cmd% + % see comment in draw@subcircuit@multi + \yquant@softpath@extractmaxxat\pgfshapeclippathhorzresult{\yquant@register@get@y{#1}}% + \let\pgfshapeclippathhorzresult=\empty% + \yquant@circuit@extendwire{#1}{*}% + \expandafter\yquant@circuit@extendcontrolline\expandafter% + {\the\yquant@draw@@currentcontroltype}\yquant@draw@@x% + % check for empty name parameter + \ifstrempty{#3}\relax{% + \pgfnodealias{\tikz@pp@name{#3}}{yquantbox}% + }% + \numdef\yquant@draw@@idx@content{\yquant@draw@@idx@content+1}% +} + +\protected\long\def\yquant@draw@subcircuit@multi#1#2#3#4#5#6{% + % there is no contiguous slicing for subcircuits, as they may have all kinds of wire operations that can extend beyond the individual slices, let alone ancillas + \yquant@draw@subcircuit@prepare{#5}{#6}% + % We need to somehow extract the y radius + \edef\cmd{% + \noexpand\path (\yquant@draw@@x, \yquant@draw@subcircuit@y)% + node[/yquant/every operator, \yquant@draw@@style,% + /yquant/operators/every subcircuit box, /yquant/this operator,% + /yquant/operators/this subcircuit box, + /yquant/operator/multi main=true,% + name prefix=, name suffix=, name=yquantbox]% + {\box\yquant@draw@subcircuit@box};% + \pgfshapeclippath{yquantbox}% + {/yquant/every operator, \yquant@draw@@style,% + /yquant/operators/every subcircuit box, /yquant/this operator,% + /yquant/operators/this subcircuit box,% + /yquant/operator/multi main=true}% + }% + \cmd% + % install the clippings - but only on wires that are visually between the first and list while not being part of the circuit. + \let\nonaffectedpgfshapeclippathhorzresult=\pgfshapeclippathhorzresult% + \yquant@for \i := #1 to #2 {% + \xifinlist{\i}{#4}{% + % Usually, we always begin with a wire from the center of the operator shape and clip the inner parts away. This can't be done here, as the wire needs to be drawn _inside_ of the outer box operator here. Instead of clipping against the clip path, we extract its maximum x position at the position of the wire (which is an overkill for simple shapes, but the allows to specify even more complicated ones) and place the wire at this position without clipping. + % Note: this works very well for lines joining at perpendicular angles; but if the shape of the box is more fancy, while the position will be calculated correctly, the wire has a rectangular (or rounded, depending on the line cap) shape that is drawn on top of thw operator. While \yquant@softpath@extractmaxxat could without much effort determine exactly the segment of the path that corresponds to the rightmost line, we would then have to convert this single line into a closed path that fills the linewidth and clip against it to get proper joiners. Since most likely, no-one will ever need this, we don't do it. But file a feature request if desired. + \yquant@softpath@extractmaxxat\nonaffectedpgfshapeclippathhorzresult% + {\yquant@register@get@y\i}% + \let\pgfshapeclippathhorzresult=\empty% + \yquant@circuit@extendwire\i{*}% + }{% + \let\pgfshapeclippathhorzresult=\nonaffectedpgfshapeclippathhorzresult% + \yquant@circuit@extendwire\i{center}% + }% + }% + \expandafter\yquant@circuit@extendcontrolline\expandafter% + {\the\yquant@draw@@currentcontroltype}\yquant@draw@@x% + \ifstrempty{#6}\relax{% + \pgfnodealias{\tikz@pp@name{#6}}{yquantbox}% + }% + \numdef\yquant@draw@@idx@content{\yquant@draw@@idx@content+1}% +} + \protected\def\yquant@draw@control#1#2#3{% \edef\cmd{% \noexpand\path (\yquant@draw@@x, \yquant@register@get@y{#2})% @@ -208,7 +368,7 @@ /yquant/this control}% }% \cmd% - \yquant@circuit@extendwire{#2}% + \yquant@circuit@extendwire{#2}{center}% \yquant@draw@@currentcontroltype=\yquant@register@get@type{#2}\relax% \expandafter\yquant@circuit@extendcontrolline\expandafter% {\yquant@draw@@currentcontroltype}\yquant@draw@@x% @@ -251,7 +411,7 @@ \fi% \edef\cmd{% \noexpand\path[/yquant/every control line]% - \yquant@circuit@extendcontrolline@cmd; + \yquant@circuit@extendcontrolline@cmd;% }% \cmd% \endpgfscope% @@ -285,7 +445,7 @@ \pgfusepathqclip% \endgroup% \fi% - \path[/yquant/every multi line] #2; + \path[/yquant/every multi line] #2;% \endpgfscope% } @@ -300,18 +460,18 @@ \protected\def\yquant@draw@wire#1#2{% \begingroup% \yquant@register@get@typeywire{#1}\wiretype\wireypos\wirelast% - \edef\wirexprevpos{\expandafter\@firstoffour\wirelast}% - \ifx\yquant@env@end@xpos#2\relax% - \let\wirexpos=\yquant@env@end@xpos% - \else% - \edef\wirexpos{\expandafter\@secondoffour\wirelast}% - \fi% \unless\ifnum\wiretype=\yquant@register@type@none% + \edef\wirexprevpos{\expandafter\@firstoffour\wirelast}% + \ifx0#2% + \edef\wirexpos{\expandafter\@secondoffour\wirelast}% + \else% + \let\wirexpos=\yquant@env@end@xpos% + \fi% \ifdim\wirexpos>\wirexprevpos % \edef\wirestyle{\noexpand\tikzset{% /yquant/this wire/.style={% /yquant/every wire,% - /yquant/every \ifcase\wiretype\relax nobit\or qubit \or cbit \or qubits \fi wire,% + /yquant/every \yquant@register@type@tostring\wiretype\space wire,% \yquant@register@get@style{#1}% }, /yquant/this wire% }}% @@ -334,13 +494,13 @@ % We need to access the current bounding box as well as other positions in the local coordinate frame. For this, transform the bounding box to the current frame (though this is expensive). Does this capture rotations correctly? \begingroup% \pgftransforminvert% - \pgfpointtransformednonlinear{\pgfqpoint{\pgf@picminx}{\pgf@picminy}} + \pgfpointtransformednonlinear{\pgfqpoint{\pgf@picminx}{\pgf@picminy}}% \global\@tempdima=\pgf@y% \pgfpointtransformednonlinear{\pgfqpoint{\pgf@picmaxx}{\pgf@picmaxy}}% \global\@tempdimb=\pgf@y% \endgroup% % To avoid rendering artifacts at all zoom levels with all renderers, we need to make the clipping region large. Let's try the current bounding box first. - % This may be insufficient if there no or a tiny wire label and only registers of a small height. In this case, take at ten times the line width or at least 1cm, but don't let it affect the bounding box. + % This may be insufficient if there no or a tiny wire label and only registers of a small height. In this case, take ten times the line width or at least 1cm, but don't let it affect the bounding box. \ifdim\dimexpr\@tempdimb-\@tempdima\relax<10\pgflinewidth % \@tempdima=\dimexpr\wireypos-5\pgflinewidth\relax% \@tempdimb=\dimexpr\wireypos+5\pgflinewidth\relax% @@ -370,7 +530,7 @@ % quantum wire \protected\csdef{yquant@draw@wire@\yquant@register@type@q}#1{% \edef\cmd{% - \noexpand\path [/yquant/this wire] + \noexpand\path [/yquant/this wire]% (\wirexprevpos,\wireypos) -- (\wirexpos,\wireypos);% }% \cmd% @@ -379,7 +539,7 @@ % classical wire \protected\csdef{yquant@draw@wire@\yquant@register@type@c}#1{% \edef\cmd{% - \noexpand\path [/yquant/this wire] + \noexpand\path [/yquant/this wire]% (\wirexprevpos,\wireypos+2\pgflinewidth)--(\wirexpos,\wireypos+2\pgflinewidth)% (\wirexprevpos,\wireypos-2\pgflinewidth)--(\wirexpos,\wireypos-2\pgflinewidth);% }% @@ -389,13 +549,49 @@ % quantum-bundle \protected\csdef{yquant@draw@wire@\yquant@register@type@qs}#1{% \edef\cmd{% - \noexpand\path [/yquant/this wire] + \noexpand\path [/yquant/this wire]% (\wirexprevpos,\wireypos+2\pgflinewidth)--(\wirexpos,\wireypos+2\pgflinewidth)% (\wirexprevpos,\wireypos)--(\wirexpos,\wireypos)% (\wirexprevpos,\wireypos-2\pgflinewidth)--(\wirexpos,\wireypos-2\pgflinewidth);% }% \cmd% } + +\protected\long\def\yquant@draw@output@group#1{% + \begingroup% + \def\idx{0}% + \yquant@set{#1}% +} + +\let\yquant@draw@output@endgroup=\endgroup% + +\protected\long\def\yquant@draw@output@single#1#2{% + \path% + (\yquant@env@end@xpos, \yquant@register@get@y{#1})% + node[/yquant/every output,% + /yquant/every \yquant@register@type@tostring{\yquant@register@get@type{#1}} output] {#2}; + \numdef\idx{\idx+1}% +} + +\protected\long\def\yquant@draw@output@multi#1#2#3#4{% + % extremely similar to \yquant@draw@multiinit + \@tempdima=-.5\dimexpr\yquant@config@register@sep\relax% + \dimdef\yquant@draw@multiinit@@min{\yquant@register@get@y{#1}-\@tempdima}% + \dimdef\yquant@draw@multiinit@@max{\yquant@register@get@y{#2}+\@tempdima}% + \dimdef\yquant@draw@multiinit@@total{% + \yquant@draw@multiinit@@max-\yquant@draw@multiinit@@min% + }% + \def\pgfdecorationsegmentaspect{0}% + \let\yquant@register@multi@contiguous=\yquant@draw@multiinit@contiguous% + \let\pgfdecorationsegmentfromto=\empty% + #3% + \edef\pgfdecorationsegmentfromto{\expandafter\@gobble\pgfdecorationsegmentfromto}% + \path[/yquant/every multi output]% + (\yquant@env@end@xpos, \yquant@draw@multiinit@@min) --% + (\yquant@env@end@xpos, \yquant@draw@multiinit@@max)% + node {#4};% + \numdef\idx{\idx+1}% +} % END_FOLD % BEGIN_FOLD Preparation of drawing a generic shape @@ -443,6 +639,12 @@ }{% \yquant@draw@@single{#1}{#2}{##1}% }% + \ifx\yquant@draw@@multi\yquant@draw@@multiinit% + % if we draw an initialization (whether multi or single), this possibly affects the minimal x position. All other gates will be shifted so that they cannot extend beyond the minimal position. + \ifdim\pgf@picminx<\csname\yquant@prefix xmin\endcsname% + \csxdef{\yquant@prefix xmin}{\the\pgf@picminx}% + \fi% + \fi% \expandafter% \endpgfinterruptboundingbox% \expandafter\dimen\expandafter0\expandafter=% @@ -451,41 +653,44 @@ \dimen2=\dimen0 % \fi% \numdef\idx{\idx+1}% - % TODO -% \yquant@draw@callback@box\nodename% }% \dolistloop\yquant@circuit@operator@targets% % END_FOLD - % BEGIN_FOLD controls + \yquant@draw@@controls% + \yquant@draw@@finalize{#1}{#2}% +} + +\protected\def\yquant@draw@@controls@loop#1#2{% + \ifx\yquant@lang@attr@name\empty% + \let\nodename=\empty% + \else% + \edef\nodename{\yquant@lang@attr@name-#1\idx}% + \fi% + \yquant@sort@eadd{% + \expandafter\noexpand\csname yquant@draw@#1control\endcsname% + {#2}% register index + {\nodename}% + }% + \unless\ifdefined\yquant@draw@controltype% + \edef\yquant@draw@controltype{#2}% + \fi% + \numdef\idx{\idx+1}% +} + +\protected\def\yquant@draw@@controls{% \ifyquant@circuit@operator@hasControls% - \def\do##1{% - \ifx\yquant@lang@attr@name\empty% - \let\nodename=\empty% - \else% - \edef\nodename{\yquant@lang@attr@name-\yquant@draw@controlprefix\idx}% - \fi% - \yquant@sort@eadd{% - \expandafter\noexpand\csname yquant@draw@\yquant@draw@controlprefix control\endcsname% - {##1}% register index - {\nodename}% - }% - \unless\ifdefined\yquant@draw@controltype% - \edef\yquant@draw@controltype{##1}% - \fi% - \numdef\idx{\idx+1}% - } - \def\yquant@draw@controlprefix{p}% \def\idx{0}% - \dolistloop\yquant@circuit@operator@pctrls% - \def\yquant@draw@controlprefix{n}% + \forlistloop{\yquant@draw@@controls@loop p}\yquant@circuit@operator@pctrls% \def\idx{0}% - \dolistloop\yquant@circuit@operator@nctrls% + \forlistloop{\yquant@draw@@controls@loop n}\yquant@circuit@operator@nctrls% \unless\ifdefined\yquant@draw@controltype% \PackageError{yquant.sty}{Assertion failure}% {Internal inconsistency in yquant: Controlled action detected, but no controls were found.}% \fi% \fi% - % END_FOLD +} + +\protected\long\def\yquant@draw@@finalize#1#2{% % We now know the dimensions of all the registers (though we didn't bother with the height of the control knobs [if present], we just assume they are too small to change this). \protected\def\idx{}% \protected@edef\yquant@draw@append{% @@ -502,16 +707,15 @@ }% \yquant@sort\yquant@draw@sort% \advance \dimen2 by \yquant@circuit@operator@x\relax% - % BEGIN_FOLD shipout \ifyquant@circuit@operator@hasControls% - % If we draw a control line, all intermediate registers are affected in their position so that the line is never crossed. If the vertical line is instead caused by a multi register, \yquant@draw@finalize@ctrl will be responsible for advancing only the affected positions. + % If we draw a control line, all intermediate registers are affected in their position so that the line is never crossed. If the vertical line is instead caused by a multi register, \yquant@draw@@finalize@ctrl will be responsible for advancing only the affected positions. \yquant@for \yquant@i := \yquant@circuit@operator@minctrl to \yquant@circuit@operator@maxctrl {% \yquant@register@set@x\yquant@i{\the\dimen2}% }% \fi% \def\do##1{% \appto\yquant@draw@append{##1}% - \yquant@draw@finalize@ctrl##1% + \yquant@draw@@finalize@ctrl##1% }% \yquant@sort@dolistloop% \csxappto{\yquant@prefix draw}{% @@ -557,7 +761,6 @@ \fi% \fi% }% - % END_FOLD } \protected\def\yquant@draw@@single#1#2#3{% @@ -570,12 +773,11 @@ \pgfinterruptboundingbox% \yquant@env@virtualize@path% \path% - (0pt, 0pt) + (0pt, 0pt)% node[/yquant/every operator, #2, /yquant/this operator,% name prefix=, name suffix=, name=] {#1};% - \yquant@register@update@height{#3}{% - \the\dimexpr\pgf@picmaxy-\pgf@picminy\relax% - }% + \yquant@register@update@height{#3}{\the\pgf@picmaxy}% + \yquant@register@update@depth{#3}{\the\dimexpr-\pgf@picminy\relax}% } \protected\def\yquant@draw@@multi#1#2#3{% @@ -594,9 +796,9 @@ \ifdim\pgf@picmaxy=-16000pt % % if there was no single contiguous part before, determine the width now \path% - (0pt, 0pt) + (0pt, 0pt)% node[/yquant/every operator, #2, /yquant/this operator,% - name prefix=, name suffix=, name=] {#1}; + name prefix=, name suffix=, name=] {#1};% \fi% } @@ -608,14 +810,13 @@ \edef\cmd{% \noexpand\path (0pt, 0pt)% node[/yquant/every operator, \yquant@draw@@style, /yquant/this operator,% - /yquant/operator/multi main=\ifnum#3=1 true\else false\fi, + /yquant/operator/multi main=\ifnum#3=1 true\else false\fi,% name prefix=, name suffix=, name=]% - {\unexpanded\expandafter{\yquant@draw@@content}}; + {\unexpanded\expandafter{\yquant@draw@@content}};% }% \cmd% - \yquant@register@update@height{#1}{% - \the\dimexpr\pgf@picmaxy-\pgf@picminy\relax% - }% + \yquant@register@update@height{#1}{\the\pgf@picmaxy}% + \yquant@register@update@depth{#1}{\the\dimexpr-\pgf@picminy\relax}% \fi% } @@ -629,24 +830,116 @@ \pgfinterruptboundingbox% \yquant@env@virtualize@path% \path% - (0pt, 0pt) + (0pt, 0pt)% node[/yquant/every operator, #2, /yquant/every multi label,% - name prefix=, name suffix=, name=] {#1}; + name prefix=, name suffix=, name=] {#1};% +} + +\protected\long\def\yquant@draw@@subcircuit#1{% + \yquant@sort@clear% + \def\idx{0}% + \dimen2=\yquant@config@operator@minimum@width% + % BEGIN_FOLD register + \def\do##1{% + \ifx\yquant@lang@attr@name\empty% + \let\nodename=\empty% + \else% + \edef\nodename{\yquant@lang@attr@name-\idx}% + \fi% + \ifyquant@firsttoken\yquant@register@multi{##1}{% + \yquant@draw@@subcircuit@multi{#1}{##1}% + }{% + \yquant@draw@@subcircuit@single{#1}{##1}% + }% + \dimen0=\dimexpr% + \csname yquant@env\yquant@circuit@subcircuit@id @xmax\endcsname-% + \csname yquant@env\yquant@circuit@subcircuit@id @xmin\endcsname% + \relax\relax% + \pgfinterruptboundingbox% + % There will still be some extra width taken by separations or other things related to the box itself. + \yquant@env@virtualize@path% + \path% + (0pt, 0pt)% + node[/yquant/every operator, #1,% + /yquant/operators/every subcircuit box, /yquant/this operator,% + /yquant/operators/this subcircuit box,% + name prefix=, name suffix=, name=]% + {\hbox to \dimen0{}};% + % We also don't update the height here, as the height of the subcircuit is undetermined as long as we did not match inner and outer wires. + \expandafter% + \endpgfinterruptboundingbox% + \expandafter\dimen\expandafter0\expandafter=% + \the\dimexpr\pgf@picmaxx-\pgf@picminx\relax\relax% + \ifdim\dimen0>\dimen2 % + \dimen2=\dimen0 % + \fi% + \numdef\idx{\idx+1}% + }% + \dolistloop\yquant@circuit@operator@targets% + % END_FOLD + \yquant@draw@@controls% + \yquant@draw@@finalize{}{#1}% +} + +\protected\def\yquant@draw@@subcircuit@single#1#2{% + \edef\yquant@circuit@subcircuit@param{#2\yquant@list@delim}% + \yquant@circuit@subcircuit{#1}% + \yquant@sort@eadd{% + \yquant@draw@subcircuit@single% + {#2}% register index + {\yquant@circuit@subcircuit@id}% + {\nodename}% + }% +} + +\protected\def\yquant@draw@@subcircuit@multi#1#2{% + \edef\yquant@circuit@subcircuit@param{\@fifthoffive#2}% + \yquant@sort@list\yquant@circuit@subcircuit@param\yquant@sort@ascending% + \yquant@circuit@subcircuit{#1}% + \yquant@sort@eadd{% + \yquant@draw@subcircuit@multi% + #2% + {\yquant@circuit@subcircuit@id}% + {\nodename}% + } +} + +\protected\long\def\yquant@draw@@output@single#1#2{% + \path + (\yquant@env@end@xpos, 0pt)% + node[/yquant/every output,% + /yquant/every \yquant@register@type@tostring{\yquant@register@get@type{#1}} output] {#2};% + \numdef\idx{\idx+1}% +} + +\protected\long\def\yquant@draw@@output@multi#1{% + \path[/yquant/every multi output]% + (\yquant@env@end@xpos, 0pt) -- (\yquant@env@end@xpos, 1cm)% + node {#1};% + \numdef\idx{\idx+1}% } -\def\yquant@draw@finalize@ctrl#1{% +\def\yquant@draw@@finalize@ctrl#1{% + \let\next=\yquant@draw@@finalize@ctrl@single% \ifx\yquant@draw@multi#1% - \expandafter\yquant@draw@finalize@ctrl@multi% + \let\next=\yquant@draw@@finalize@ctrl@multi% \else% \ifx\yquant@draw@multiinit#1% - \expandafter\expandafter\expandafter\yquant@draw@finalize@ctrl@multi% + \let\next=\yquant@draw@@finalize@ctrl@multi% \else% - \expandafter\expandafter\expandafter\yquant@draw@finalize@ctrl@single% + \ifx\yquant@draw@subcircuit@multi#1% + \let\next=\yquant@draw@@finalize@ctrl@subcircuit@multi% + \else% + \ifx\yquant@draw@subcircuit@single#1% + \let\next=\yquant@draw@@finalize@ctrl@subcircuit@single% + \fi% + \fi% \fi% \fi% + \next% } -\protected\def\yquant@draw@finalize@ctrl@single#1#2{% +\protected\def\yquant@draw@@finalize@ctrl@single#1#2{% \unless\ifyquant@circuit@operator@hasControls% \yquant@register@set@x#1{\the\dimen2}% \fi% @@ -655,13 +948,17 @@ }% } -\protected\def\yquant@draw@finalize@ctrl@singleinit#1#2{% +\def\yquant@draw@@finalize@ctrl@subcircuit@single#1#2#3{% + \yquant@draw@@finalize@ctrl@single{#1}{#3}% +} + +\protected\def\yquant@draw@@finalize@ctrl@singleinit#1#2{% \eappto\yquant@draw@append{% \yquant@draw@callback@wire{#1}% }% } -\protected\def\yquant@draw@finalize@ctrl@multi#1#2#3#4#5{% +\protected\def\yquant@draw@@finalize@ctrl@multi#1#2#3#4#5{% \unless\ifyquant@circuit@operator@hasControls{% % \yquant@for uses \loop...\repeat and hence redefines \body, which would destroy an outer loop. % if we did not draw a control line, the x position has not yet been set. A multi-qubit register might visually extend over multiple registers that are not even part, hence we update them all. @@ -669,16 +966,15 @@ \yquant@register@set@x\yquant@i{\the\dimen2}% }% }\fi% - % this is called from a do loop itself, so preserve \do (but do not enter grouping) - \let\yquant@register@multi@contiguous=\yquant@draw@finalize@ctrl@multi@contiguous% + \let\yquant@register@multi@contiguous=\yquant@draw@@finalize@ctrl@multi@contiguous% \ifyquant@circuit@operator@hasControls% \ifyquant@config@operator@multi@warn% - \def\yquant@draw@finalize@ctrl@multi@contiguous@warn{0}% + \def\yquant@draw@@finalize@ctrl@multi@contiguous@warn{0}% \else% - \def\yquant@draw@finalize@ctrl@multi@contiguous@warn{2}% + \def\yquant@draw@@finalize@ctrl@multi@contiguous@warn{2}% \fi% \else% - \def\yquant@draw@finalize@ctrl@multi@contiguous@warn{2}% + \def\yquant@draw@@finalize@ctrl@multi@contiguous@warn{2}% \fi% \cslet{\yquant@prefix finalize@ctrl@draw@appto}\empty% #4% @@ -686,17 +982,37 @@ \csgundef{\yquant@prefix finalize@ctrl@draw@appto}% } -\protected\def\yquant@draw@finalize@ctrl@multiinit#1#2#3#4#5{% +\protected\def\yquant@draw@@finalize@ctrl@subcircuit@multi@loop#1{% + \begingroup% + \edef\tmp{\yquant@draw@callback@wire{#1}}% + \expandafter% + \endgroup% + \expandafter\appto\expandafter\yquant@draw@append\expandafter{\tmp}% +} + +\protected\def\yquant@draw@@finalize@ctrl@subcircuit@multi#1#2#3#4#5#6{% + % there are no contiguous parts here, don't call the normal @multi + \unless\ifyquant@circuit@operator@hasControls{% + % \yquant@for uses \loop...\repeat and hence redefines \body, which would destroy an outer loop. + % if we did not draw a control line, the x position has not yet been set. A multi-qubit register might visually extend over multiple registers that are not even part, hence we update them all. + \yquant@for \yquant@i := #1 to #2 {% + \yquant@register@set@x\yquant@i{\the\dimen2}% + }% + }\fi% + \forlistloop\yquant@draw@@finalize@ctrl@subcircuit@multi@loop{#4}% +} + +\protected\def\yquant@draw@@finalize@ctrl@multiinit#1#2#3#4#5{% % this is called from a do loop itself, so preserve \do (but do not enter grouping) - \let\yquant@register@multi@contiguous=\yquant@draw@finalize@ctrl@multi@contiguous% + \let\yquant@register@multi@contiguous=\yquant@draw@@finalize@ctrl@multi@contiguous% \ifyquant@circuit@operator@hasControls% \ifyquant@config@operator@multi@warn% - \def\yquant@draw@finalize@ctrl@multi@contiguous@warn{0}% + \def\yquant@draw@@finalize@ctrl@multi@contiguous@warn{0}% \else% - \def\yquant@draw@finalize@ctrl@multi@contiguous@warn{2}% + \def\yquant@draw@@finalize@ctrl@multi@contiguous@warn{2}% \fi% \else% - \def\yquant@draw@finalize@ctrl@multi@contiguous@warn{2}% + \def\yquant@draw@@finalize@ctrl@multi@contiguous@warn{2}% \fi% \cslet{\yquant@prefix finalize@ctrl@draw@appto}\empty% #4% @@ -704,15 +1020,15 @@ \csgundef{\yquant@prefix finalize@ctrl@draw@appto}% } -\protected\def\yquant@draw@finalize@ctrl@multi@contiguous#1#2#3{% - \ifnum\yquant@draw@finalize@ctrl@multi@contiguous@warn=1 % +\protected\def\yquant@draw@@finalize@ctrl@multi@contiguous#1#2#3{% + \ifnum\yquant@draw@@finalize@ctrl@multi@contiguous@warn=1 % \PackageWarning{yquant.sty}{Ambiguous operation: multiple discontiguous multi-register operations in combination with controls make it hard to visually determine on which registers the gates act on.}% % switch the warning off for this group (which is a single operation) \yquant@config@operator@multi@warnfalse% - \def\yquant@draw@finalize@ctrl@multi@contiguous@warn{2}% + \def\yquant@draw@@finalize@ctrl@multi@contiguous@warn{2}% \else% - \numdef\yquant@draw@finalize@ctrl@multi@contiguous@warn{% - \yquant@draw@finalize@ctrl@multi@contiguous@warn+1% + \numdef\yquant@draw@@finalize@ctrl@multi@contiguous@warn{% + \yquant@draw@@finalize@ctrl@multi@contiguous@warn+1% }% \fi% {% save \body diff --git a/graphics/pgf/contrib/yquant/tex/yquant-env.tex b/graphics/pgf/contrib/yquant/tex/yquant-env.tex index 16c3598af3..bb901d1d2c 100644 --- a/graphics/pgf/contrib/yquant/tex/yquant-env.tex +++ b/graphics/pgf/contrib/yquant/tex/yquant-env.tex @@ -42,71 +42,235 @@ \yquant@env@begin@arg[]% } -\long\protected\def\yquant@env@begin@arg[#1]{% +\def\yquant@env@begin@arg{% + \let\yquant@env@check=\yquant@env@check@% + \yquant@env@begin@generic\yquant% +} + +\long\protected\def\yquant@env@begin@generic#1[#2]{ \begingroup% - \advance\yquant@env by 1 % + \let\yquant@parent=\yquant@prefix% + \global\advance\yquant@env by 1 % \edef\yquant@prefix{yquant@env\the\yquant@env @}% - \let\yquant=\yquant@env@scan% - \yquant@lang@reset@attrs% + \ifnum\yquant@env=1 % + \yquant@env@substikz#1% + \def\yquant@env@create@x{0pt}% + \global\cslet{\yquant@prefix parameters}\empty% + \else% + \let\yquant@lang@reset@attrs@inputoutput=\yquant@lang@reset@attrs@inputoutput@subcircuit% + \let\yquant@env@create@x=\yquant@circuit@operator@x% + \global\cslet{\yquant@prefix parameters}\yquant@circuit@subcircuit@param% + \yquant@env@lazyfalse% forbid lazy register creation in subcircuits. We need a proper and in-order declaration of the subcircuit's interface. + \fi% + \let#1=\yquant@env@scan% + \yquant@env@reset@commands% \csgdef{\yquant@prefix registers}{0}% \global\cslet{\yquant@prefix draw}\relax% \global\cslet{\yquant@prefix outputs}\relax% + \csdimgdef{\yquant@prefix xmin}{\yquant@env@create@x+\yquant@config@operator@sep}% + \global\cslet{\yquant@prefix subcircuits}\empty% + \global\cslet{\yquant@prefix inonly}\empty% \csxdef{\yquant@prefix cleanup}{% \expandafter\noexpand\csname\yquant@prefix registers\endcsname% \expandafter\noexpand\csname\yquant@prefix draw\endcsname% \expandafter\noexpand\csname\yquant@prefix outputs\endcsname% + \expandafter\noexpand\csname\yquant@prefix parameters\endcsname% + \expandafter\noexpand\csname\yquant@prefix xmin\endcsname% + \expandafter\noexpand\csname\yquant@prefix subcircuits\endcsname% + \expandafter\noexpand\csname\yquant@prefix inonly\endcsname% \expandafter\noexpand\csname\yquant@prefix cleanup\endcsname% }% - \ifnum\yquant@env=1 % - \yquant@env@substikz% - \fi% - \scope[{/yquant/.cd, #1, /tikz/.cd, /yquant/every circuit}]% + \scope[{/yquant/.cd, #2, /tikz/.cd, /yquant/every circuit}]% } -\newif\ifyquantdebug + \protected\def\yquant@env@end{% \letcs\yquant@env@end@registers{\yquant@prefix registers}% \ifnum\yquant@env@end@registers>0 % % draw all wires \yquant@register@get@maxxrange\yquant@env@end@xpos{1}{\yquant@env@end@registers}% - % to have a symmetric situation, we extend again one separation at the end + \ifdim\csname\yquant@prefix xmin\endcsname<% + \dimexpr\yquant@env@create@x+\yquant@config@operator@sep\relax% + % to have a symmetric situation, we extend again one separation at the end + \dimdef\yquant@env@end@xpos{\yquant@env@end@xpos+\yquant@config@operator@sep}% + \global\cslet{\yquant@prefix xmax}\yquant@env@end@xpos% + \else% + % while the outputs need this, the subcircuit doesn't if there are no outputs. + \global\cslet{\yquant@prefix xmax}\yquant@env@end@xpos% + \dimdef\yquant@env@end@xpos{\yquant@env@end@xpos+\yquant@config@operator@sep}% + \fi% + \yquant@cleanup@csadd{xmax}% \csxappto{\yquant@prefix draw}{% - \def\noexpand\yquant@env@end@xpos{% - \the\dimexpr\yquant@env@end@xpos+\yquant@config@operator@sep\relax% - }% - \yquant@circuit@endwires{\yquant@env@end@registers}% - } - % also calculate the true y positions - \dimen0=0pt % - \dimen2=0pt % - \dimen4=\yquant@config@register@sep % - \yquant@for \i := 1 to \yquant@env@end@registers {% - % we do not care if the wire is present for the y position - \dimen2=.5\dimexpr\yquant@register@get@height\i\relax% - \advance\dimen0 by \dimen2\relax% - % top-to-bottom means negative coordinates in pgf - \yquant@register@set@y\i{-\the\dimen0}% - \advance\dimen0 by \dimen2\relax% - \advance\dimen0 by \dimen4\relax% + \yquant@circuit@endwires{\yquant@env@end@xpos}% }% \csname\yquant@prefix outputs\endcsname% + % also calculate the true y positions + \unless\ifdefined\yquant@parent% + \yquant@env@end@calcypositions% + \fi% + \else% + \ifdefined\yquant@parent% + \PackageError{yquant.sty}{Empty subcircuit}% + {Subcircuits must contain registers.}% + \else% + \PackageWarning{yquant.sty}{Empty quantum circuit}% + \fi% + \fi% + \global\let\yquant@env@scan=\relax% don't rescan after the scope + \endscope% this will exit five to seven groups (depending on the transparency group state, and it might even be driver-dependent, though it is not at the moment), so better make the relax global + \global\let\yquant@env@scan=\yquant@env@scan@% + \ifdefined\yquant@parent% + % We are in a subcircuit. The drawing and cleanup is delayed until the end. + \csxappto{\yquant@parent cleanup}% + {\unexpanded\expandafter\expandafter\expandafter{% + \csname\yquant@prefix cleanup\endcsname% + }}% + \ifyquantdebug% + \csshow{\yquant@prefix draw}% + \fi% + \else% + % Now we actually carry out the tikz commands which were previously stored in the draw command. But before this, we get rid of all \yquant@env@scan calls and also restore the scope command, since this would add itself once again. And get@y needs to expand. + \let\path=\tikz@command@path% + \let\tikz@lib@scope@check=\yquant@env@substikz@scopecheck% + \let\tikz@scope@opt=\yquant@env@substikz@scope% + \let\endtikz@scope@env=\yquant@env@substikz@endscope% + \let\endscope=\endtikz@scope@env% + \let\stopscope=\endscope% + \yquant@register@get@y@@expandable% + \ifyquantdebug% + \csshow{\yquant@prefix draw}% \fi% - \endscope% - % Now we actually carry out the tikz commands which were previously stored in the draw command. But before this, we get rid of all \yquant@env@scan calls and also restore the scope command, since this would add itself once again. And get@y needs to expand. - \let\path=\tikz@command@path% - \let\tikz@lib@scope@check=\yquant@env@substikz@scopecheck% - \let\tikz@scope@opt=\yquant@env@substikz@scope% - \let\endtikz@scope@env=\yquant@env@substikz@endscope% - \let\endscope=\endtikz@scope@env% - \let\stopscope=\endscope% - \yquant@register@get@y@@expandable% - \ifyquantdebug% - \csshow{\yquant@prefix draw}% + \csname\yquant@prefix draw\endcsname% + \expandafter\expandafter\expandafter\yquant@cleanup\csname\yquant@prefix cleanup\endcsname|% + \global\yquant@env=0 % \fi% - \csname\yquant@prefix draw\endcsname% - \expandafter\expandafter\expandafter\yquant@cleanup\csname\yquant@prefix cleanup\endcsname|% \endgroup% } +\protected\def\yquant@env@end@calcypositions{% + \begingroup% + \dimen4=\yquant@config@register@sep % + % We know the heights of most gates, but subcircuits are tricky. Since the position of their inner wires depends on the heights of the outer wires, we could not make any assumption about their heights yet. So we now need multiple iterations: First, we fix the positions of our own wires preliminarily. Then, we iterate through all subcircuits at the first level, place their wires appropriately and try to align input and output. In doing so, we recognize when there's not enough space at an outer wire. If this is the case, we enlarge the outer wire's height appropriately and restart alignment from the outmost level. If everything is proper, we start aligning at the next level. + \yquant@env@end@calcypositions@toplevel1% + % Turn the preliminary positions into true ones at every level. + \yquant@env@end@setypositions1% + \endgroup% +} + +\protected\def\yquant@env@end@calcypositions@loop#1{% + % \yquant@parent has to be set already + \def\yquant@prefix{yquant@env#1@}% + % #1 now holds the id of the subcircuit. Find the first input. + \edef\firstinput{% + \expandafter\expandafter\expandafter% + \@firstoftwo\csname\yquant@prefix firstinput\endcsname% + }% + \edef\lastinput{% + \expandafter\expandafter\expandafter% + \@firstoftwo\csname\yquant@prefix lastinput\endcsname% + }% + % we already made sure during in \yquant@circuit@subcircuit that there is enough space above and below the subcircuit. Still, the wires need to be positioned. However, we will first deal with all intermediate wires, which need to be placed by means of shifts - there is no direct correspondence to heights or depths of parent wires any more. + \ifnum\firstinput<\numexpr\lastinput-1\relax% + \dimen0=\dimexpr% + \csname y@\csname\yquant@prefix registermap@\firstinput\endcsname\endcsname+% + \yquant@register@get@depth\firstinput+\dimen4% + \relax% + \yquant@for \i := \numexpr\firstinput+1\relax to \lastinput {% + \advance\dimen0 by \yquant@register@get@height\i\relax% + \ifcsname\yquant@prefix registermap@\i\endcsname% + % this is an input: do we have enough space by using the outer position? + \letcs\outername{\yquant@prefix registermap@\i}% + \letcs\outery{y@\outername}% + \ifdim\dimen0>\outery\relax% + % re-aligning the outer positions is required + \ifcsname y+@\outername\endcsname% + \csdimdef{y+@\outername}% + {\csname y+@\outername\endcsname+\dimen0-\outery}% + \else% + \csdimdef{y+@\outername}{\dimen0-\outery}% + \fi% + \let\yquant@env@end@calcypositions@redo=\relax% + \fi% + \else% + \csedef{y@\yquant@prefix register@\i}{\the\dimen0}% + \fi% + \ifdefined\yquant@env@end@calcypositions@redo% + \expandafter\yquant@for@break% + \else% + \advance\dimen0 by \dimexpr\yquant@register@get@depth\i+\dimen4\relax% + \fi% + }% + \fi% + \unless\ifdefined\yquant@env@end@calcypositions@redo% + % sounds good, no readjustments necessary. Now transfer the wires above and below in the appropriate macros. + \ifnum\firstinput>1 % + \dimen0=\dimexpr% + \csname y@\csname\yquant@prefix registermap@\firstinput\endcsname\endcsname-% + \yquant@register@get@height\firstinput-\dimen4% + \relax% + \yquant@fordown \i := \numexpr\firstinput-1\relax downto 1 {% + \advance\dimen0 by -\yquant@register@get@depth\i\relax% + \csedef{y@\yquant@prefix register@\i}{\the\dimen0}% + \advance\dimen0 by -\dimexpr\yquant@register@get@height\i+\dimen4\relax% + }% + \fi% + \ifnum\lastinput<\csname\yquant@prefix registers\endcsname% + \dimen0=\dimexpr% + \csname y@\csname\yquant@prefix registermap@\lastinput\endcsname\endcsname+% + \yquant@register@get@depth\lastinput+\dimen4% + \relax% + \yquant@for \i := \numexpr\lastinput+1\relax to \csname\yquant@prefix registers\endcsname {% + \advance\dimen0 by \yquant@register@get@height\i\relax% + \csedef{y@\yquant@prefix register@\i}{\the\dimen0}% + \advance\dimen0 by \dimexpr\yquant@register@get@depth\i+\dimen4\relax% + }% + \fi% + \fi% + \ifdefined\yquant@env@end@calcypositions@redo% + % forget every plan about going deeper, restart. + \expandafter\listbreak% + \else% + \expandafter\yquant@env@end@calcypositions@subcircuits% + \fi% +} + +\protected\def\yquant@env@end@calcypositions@subcircuits{% + \let\yquant@parent=\yquant@prefix% + \forlistcsloop\yquant@env@end@calcypositions@loop{\yquant@prefix subcircuits}% + \ifdefined\yquant@env@end@calcypositions@redo% + \expandafter\listbreak% + \fi% +} + +\protected\def\yquant@env@end@calcypositions@toplevel{% + \def\yquant@prefix{yquant@env1@}% + \dimen0=0pt % + \yquant@for \i := 1 to \yquant@env@end@registers {% + % we do not care if the wire is present for the y position + \advance\dimen0 by \yquant@register@get@height\i\relax% + \ifcsname y+@\yquant@prefix register@\i\endcsname% + \advance\dimen0 by \csname y+@\yquant@prefix register@\i\endcsname\relax% + \fi% + \csedef{y@\yquant@prefix register@\i}{\the\dimen0}% + \advance\dimen0 by \dimexpr\yquant@register@get@depth\i+\dimen4\relax% + }% + \undef\yquant@env@end@calcypositions@redo% + \let\yquant@parent=\yquant@prefix% + \forlistcsloop\yquant@env@end@calcypositions@loop{\yquant@prefix subcircuits}% + \ifdefined\yquant@env@end@calcypositions@redo% + \expandafter\yquant@env@end@calcypositions@toplevel% + \fi% +} + +\protected\def\yquant@env@end@setypositions#1{% + \def\yquant@prefix{yquant@env#1@}% + \yquant@for \i := 1 to \csname\yquant@prefix registers\endcsname {% + \unless\ifcsname\yquant@prefix registermap@\i\endcsname% + \yquant@register@set@y\i{-\csname y@\yquant@prefix register@\i\endcsname}% + \fi% + }% + \forlistcsloop\yquant@env@end@setypositions{\yquant@prefix subcircuits}% +} + \tikzaddtikzonlycommandshortcutlet\yquant\yquant@envunstar \expandafter\tikzaddtikzonlycommandshortcutlet\csname yquant*\endcsname\yquant@envstar \tikzaddtikzonlycommandshortcutlet\endyquant\yquant@env@end @@ -117,11 +281,16 @@ } \let\yquant@set=\yquantset% -% private yquant-language related helpers % In order to allow nested environments and also grouping (without the need to smuggle definitions out of the groups whenever necessary), we count the number of nested environments. \newcount\yquant@env -\def\yquant@env@substikz@finish{% +% Some commands may be overwritten while a subcircuit is processed, in particular attributes, but also some others. However, within the subcircuit, they need to have their original (un)definition. +\protected\def\yquant@env@reset@commands{% + \yquant@lang@reset@attrs% + \yquant@register@reset@multi% +} + +\protected\def\yquant@env@substikz@finish{% % Rendering pipeline \endgroup% \global\pgflinewidth=\tikzscope@linewidth\relax% @@ -137,24 +306,24 @@ } % substitute the tikz commands (defined in \tikz@installcommands) so that they can be arbitrarily interleaved with yquant code. We patch \path, \scope, \endscope, \stopscope, their internal complements, and also patch \yquantset. -\protected\def\yquant@env@substikz{% +\protected\def\yquant@env@substikz#1{% % \tikz@path@do@at@end is called after a path. Hence, it is an ideal candidate to re-invoke \yquant@env@scan. However, it is by default defined to be \tikz@lib@scope@check, and we need this definition for the scopes library to work correctly. But since \tikz@lib@scope@check is also called after a scope and the end of a scope, this is even better. Yet, we need to check whether the scopes library is present or not. \let\yquant@env@substikz@scopecheck=\tikz@lib@scope@check% \ifx\tikz@lib@scope@check\pgfutil@empty% % no, it is not. This is simple. - \let\tikz@lib@scope@check=\yquant@env@scan% + \def\tikz@lib@scope@check{\yquant@env@scan}% \else% % yes, it is. Call it after the special behavior is done. \patchcmd\tikz@lib@scope@check{{}}{\yquant@env@scan}\relax{% \PackageWarning{yquant.sty}{Patching \string\tikz@lib@scope@check\space failed; you must invoke \string\yquant\space manually after every tikz command to switch back to yquant code.}% - } + }% \fi% % We not only need to re-invoke yquant after the tikz command, but we must also make sure that the tikz command is not actually drawn now, but at the end. However, what happens if some macros are used within the command? Here, we choose to expand the macros to the values they have _now_, but protected (which should prevent bad things for formatting commands). If you find this to be an issue, please report. \def\path##1;{% \protected@csxappto{\yquant@prefix draw}{% \noexpand\path##1;% }% - \yquant% + #1% }% % no need for \scoped, because it internally calls \scope. % We need to hack into \scope, but this is a bit tricky due to its argument handling. In order to get all optional arguments, including the possible animations library, correct, we change \tikz@scope@opt. @@ -189,6 +358,7 @@ \begingroup% \yquant@env@contscan% } +\let\yquant@env@scan@=\yquant@env@scan \protected\def\yquant@env@contscan{% \yquant@futurenonspacelet\yquant@env@nextchar\yquant@env@check% @@ -199,7 +369,7 @@ \yquant@env@scan% } -\protected\def\yquant@env@check{% +\protected\def\yquant@env@check@{% \let\next=\relax% % Here we assume standard catcodes for A and [, but our language specification also requires this implicitly. \ifx\yquant@env@nextchar[% @@ -254,4 +424,59 @@ \def\yquant@env@gobblepar{% \afterassignment\yquant@env@contscan% \let\@eattoken= % +} + +\def\yquantimport@now#1{% + \expandafter\yquant\@@input #1\relax% +} + +\def\yquantimportcommand{\yquantimport@now}% + +\AtBeginDocument{% + % do we have the import package? + \ifdefined\@doimport% + \providecommand\yquantimportpath{./}% + \def\yquantimportcommand{\@doimport\yquantimport@now{\yquantimportpath}}% + \fi% +} + +\def\yquantimport{% + \@ifstar{\yquantimport@i{*}}{\yquantimport@i{}}% +} + +\def\yquantimport@i#1{% + \@ifnextchar[{\yquantimport@ii{#1}}{\yquantimport@ii{#1}[]}% +}% + +\def\yquantimport@ii#1[#2]#3{% + \ifpgfpicture% + \ifnum\yquant@env>0 % + \begingroup% + \ifstrequal{#1}{*}{% + \yquant@env@lazytrue% + }{% + \yquant@env@lazyfalse% + }% + \ifstrempty{#2}{% + \yquantimportcommand{#3}% + }{% + \scope% + \yquantset{#2}% + \yquantimportcommand{#3}% + \endscope% + }% + \endgroup% + \expandafter\expandafter\expandafter\yquant% + \else% + \begin{yquant#1}[{#2}] + \yquantimportcommand{#3}% + \end{yquant#1}% + \fi% + \else% + \begin{tikzpicture}% + \begin{yquant#1}[{#2}] + \yquantimportcommand{#3}% + \end{yquant#1}% + \end{tikzpicture} + \fi% }
\ No newline at end of file diff --git a/graphics/pgf/contrib/yquant/tex/yquant-lang.tex b/graphics/pgf/contrib/yquant/tex/yquant-lang.tex index b250f78827..2ea08e8b16 100644 --- a/graphics/pgf/contrib/yquant/tex/yquant-lang.tex +++ b/graphics/pgf/contrib/yquant/tex/yquant-lang.tex @@ -1,70 +1,100 @@ % BEGIN_FOLD Attributes -\yquant@langhelper@declare@attr{ - value/.store in=\yquant@lang@attr@value, +\yquant@langhelper@declare@attr{% + value/.store in=\yquant@lang@attr@value,% after/.code={% \yquant@register@get@ids{#1}% \let\yquant@lang@attr@after=\yquant@register@get@ids@list% - }, - type/.store in=\yquant@lang@attr@type + },% + type/.store in=\yquant@lang@attr@type,% + ancilla/.code={% + \undef\yquant@lang@attr@input% + \undef\yquant@lang@attr@output% + },% + in/.code={% + \let\yquant@lang@attr@input=\relax% + \undef\yquant@lang@attr@output% + },% + in/.default=\regidx,% + out/.code={% + \undef\yquant@lang@attr@input% + \let\yquant@lang@attr@output=\relax% + },% + out/.default=\regidx,% + inout/.code={% + \let\yquant@lang@attr@input=\relax% + \let\yquant@lang@attr@output=\relax% + }% + inout/.default=\regidx,% } -\yquant@langhelper@declare@attr@global{ - name/.store in=\yquant@lang@attr@name +\yquant@langhelper@declare@attr@global{% + name/.store in=\yquant@lang@attr@name% } \protected\def\yquant@lang@reset@attrs{% \undef\yquant@lang@attr@value% \undef\yquant@lang@attr@after% \undef\yquant@lang@attr@type% + \yquant@lang@reset@attrs@inputoutput% \let\yquant@lang@attr@name=\empty% } + +\protected\def\yquant@lang@reset@attrs@inputoutput{% + \undef\yquant@lang@attr@input% + \undef\yquant@lang@attr@output% +} + +\protected\def\yquant@lang@reset@attrs@inputoutput@subcircuit{% + \let\yquant@lang@attr@input=\relax% + \let\yquant@lang@attr@output=\relax% +} % END_FOLD % BEGIN_FOLD Declaration of registers \yquant@langhelper@declare@command@uncontrolled{nobit}\yquant@lang@@nobit -\yquant@langhelper@setup@attrs{nobit}{}{} +\yquant@langhelper@setup@attrs{nobit}{}{ancilla,out} \def\yquant@lang@@nobit#1{% \let\yquant@lang@create@type=\yquant@register@type@none% \def\yquant@lang@create@style{initial}% there is no separate style, just duplicate \ifdefined\yquant@lang@attr@value% \PackageError{yquant.sty}{Placeholder initialization must not have value}% {You must not provide a description for an invisible register.} - \else + \else% \let\yquant@lang@attr@value=\empty% \fi% - \yquant@lang@create@parse@name#1[; + \yquant@lang@create@parse@name#1[;% } \yquant@langhelper@declare@command@uncontrolled{qubit}\yquant@lang@@qubit -\yquant@langhelper@setup@attrs{qubit}{}{after,value} +\yquant@langhelper@setup@attrs{qubit}{}{after,value,ancilla,in,out,inout} \def\yquant@lang@@qubit#1{% \let\yquant@lang@create@type=\yquant@register@type@q% \def\yquant@lang@create@style{qubit}% \unless\ifdefined\yquant@lang@attr@value% \let\yquant@lang@attr@value=\yquant@config@register@default@name% \fi% - \yquant@lang@create@parse@name#1[; + \yquant@lang@create@parse@name#1[;% } \yquant@langhelper@declare@command@uncontrolled{cbit}\yquant@lang@@cbit -\yquant@langhelper@setup@attrs{qubit}{}{after,value} +\yquant@langhelper@setup@attrs{cbit}{}{after,value,ancilla,in,out,inout} \def\yquant@lang@@cbit#1{% \let\yquant@lang@create@type=\yquant@register@type@c% \def\yquant@lang@create@style{qubit}% \unless\ifdefined\yquant@lang@attr@value% \let\yquant@lang@attr@value=\yquant@config@register@default@name% \fi% - \yquant@lang@create@parse@name#1[; + \yquant@lang@create@parse@name#1[;% } \yquant@langhelper@declare@command@uncontrolled{qubits}\yquant@lang@@qubits -\yquant@langhelper@setup@attrs{qubit}{}{after,value} +\yquant@langhelper@setup@attrs{qubits}{}{after,value,ancilla,in,out,inout} \def\yquant@lang@@qubits#1{% \let\yquant@lang@create@type=\yquant@register@type@qs% \def\yquant@lang@create@style{qubits}% \unless\ifdefined\yquant@lang@attr@value% \let\yquant@lang@attr@value=\yquant@config@register@default@name% \fi% - \yquant@lang@create@parse@name#1[; + \yquant@lang@create@parse@name#1[;% } \def\yquant@lang@create@parse@name#1[#2;{% @@ -82,7 +112,7 @@ \ifnum\len<1 % \PackageError{yquant.sty}{Invalid register length}% {Valid register lengths are integers greater or equal to one.}% - \fi + \fi% }{% \PackageError{yquant.sty}{Invalid register name}% {Register names must not contain `[' apart from register length indication.}% @@ -109,8 +139,11 @@ % determine x position \ifdefined\yquant@lang@attr@after% \yquant@register@get@maxxlist\yquant@lang@create@x\yquant@lang@attr@after% + \ifdefined\yquant@lang@attr@input% + \PackageError{yquant.sty}{An input register cannot be created with `after` attribute}{}% + \fi% \else% - \def\yquant@lang@create@x{0pt}% + \let\yquant@lang@create@x=\yquant@env@create@x% \fi% \begingroup% \ifx\yquant@lang@attr@name\empty% @@ -120,29 +153,87 @@ \fi% % pre-set y position \yquant@for \idx := \idx to \numexpr \len -1\relax {% - \yquant@register@define% - \yquant@lang@create@type% - \yquant@lang@create@x% - \reg\idx% + \ifdefined\yquant@lang@attr@input% + \expandafter\yquant@list@gdequeue\csname \yquant@prefix parameters\endcsname\outermap% + \ifx\outermap\empty% + \PackageError{yquant.sty}{Invalid subcircuit parameter count}% + {No outer register available for input register `\reg[\idx]`.}% + \fi% + \csxappto{\yquant@prefix draw}{% + \yquant@lang@create@check@input{\outermap}{\yquant@lang@create@type}% + {\reg[\idx]}% + }% + \unless\ifdefined\yquant@lang@attr@output% + \listcsxadd{\yquant@prefix inonly}% + {\the\numexpr\csname\yquant@prefix registers\endcsname+1\relax}% + \fi% + \yquant@register@alias% + \yquant@lang@create@type% + \yquant@lang@create@x% + \reg\idx\outermap% + \else% + \ifdefined\yquant@lang@attr@output% + \expandafter\yquant@list@gdequeue\csname\yquant@prefix parameters\endcsname\outermap% + \ifx\outermap\empty% + \PackageError{yquant.sty}{Invalid subcircuit parameter count}% + {No outer register available for output register `\reg`.}% + \fi% + \csxappto{\yquant@prefix draw}{% + \yquant@lang@create@check@output{\outermap}{\reg[\idx]}% + }% + \yquant@register@alias% + \yquant@lang@create@type% + \yquant@lang@create@x% + \reg\idx\outermap% + \else% + \yquant@register@define% + \yquant@lang@create@type% + \yquant@lang@create@x% + \reg\idx% + \fi% + \fi% % First determine the actual height by a virtual draw command - \pgfinterruptboundingbox% - \yquant@env@virtualize@path% - \path% - (\yquant@lang@create@x, 0pt) - node[/yquant/every label, /yquant/every initial label,% - /yquant/every \yquant@lang@create@style\space label] - {\trim@spaces{\yquant@lang@attr@value}};% - \expandafter\yquant@register@update@height% - \csname\yquant@prefix registers\endcsname% - {\the\dimexpr\pgf@picmaxy-\pgf@picminy\relax}% - \endpgfinterruptboundingbox% + \protected@edef\trimmedvalue{\trim@spaces{\yquant@lang@attr@value}}% + \unless\ifx\empty\trimmedvalue% + \pgfinterruptboundingbox% + \yquant@env@virtualize@path% + \edef\cmd{% + \noexpand\path% + (\yquant@lang@create@x, 0pt)% + node[/yquant/every label, /yquant/every initial label,% + /yquant/every \yquant@lang@create@style\space label% + \ifdefined\yquant@lang@attr@input, /yquant/every input label\fi]% + {\unexpanded\expandafter{\trimmedvalue}};% + }% + \cmd% + \ifdim\pgf@picminx<\csname\yquant@prefix xmin\endcsname% + \csxdef{\yquant@prefix xmin}{\the\pgf@picminx}% + \fi% + \expandafter\yquant@register@update@height% + \csname\yquant@prefix registers\endcsname% + {\the\pgf@picmaxy}% + \expandafter\yquant@register@update@depth% + \csname\yquant@prefix registers\endcsname% + {\the\dimexpr-\pgf@picminy\relax}% + \endpgfinterruptboundingbox% + \fi% % Prepare to shipout - \protected@csxappto{\yquant@prefix draw}{% + \csxappto{\yquant@prefix draw}{% \yquant@lang@create@draw{\csname\yquant@prefix registers\endcsname}% {\yquant@lang@create@x}% {\yquant@lang@create@style}% - {\yquant@lang@attr@value}% + \ifdefined\yquant@lang@attr@input1\else0\fi% + {\unexpanded\expandafter{\trimmedvalue}}% {\yquant@lang@create@name}% + \unless\ifdefined\yquant@lang@attr@input% + \ifdefined\yquant@lang@attr@output% + \yquant@circuit@flushwire% + {\csname\yquant@prefix registers\endcsname}% + \yquant@register@set@type% + {\csname\yquant@prefix registers\endcsname}% + \yquant@lang@create@type% + \fi% + \fi% }% }% \unless\ifx\yquant@lang@attr@name\empty% @@ -154,32 +245,166 @@ \endgroup% } -\protected\def\yquant@lang@create@draw#1#2#3#4#5{% +\protected\def\yquant@lang@create@check@input#1#2#3{% + \begingroup% + \let\yquant@prefix=\yquant@parent% + \unless\if#2\yquant@register@get@type{#1}% + \PackageError{yquant.sty}{Subcircuit expects wire of type `\yquant@register@type@tostring{#2}', but got `\yquant@register@type@tostring{\yquant@register@get@type{#1}}'}% + {Outer and inner wire types must match for input wire `\detokenize{#3}`.}% + \fi% + \endgroup% +} + +\protected\def\yquant@lang@create@check@output#1#2{% + \begingroup% + \let\yquant@prefix=\yquant@parent% + \unless\if\yquant@register@type@none\yquant@register@get@type{#1}% + \PackageError{yquant.sty}% + {Subcircuit expects discarded wire, got `\yquant@register@type@tostring{\yquant@register@get@type{#1}}'}% + {Outer wire must be discarded before being acceptable for output-only register `\detokenize{#2}`.}% + \fi% + \endgroup% +} + +\protected\def\yquant@lang@create@draw#1#2#3#4#5#6{% \begingroup% \dimdef\wireypos{\yquant@register@get@y{#1}}% - \ifstrempty{#4}{% + \ifcsname\yquant@prefix xshift\endcsname% + \dimdef\createxpos{#2+\csname\yquant@prefix xshift\endcsname}% + \else% + \dimdef\createxpos{#2}% + \fi% + \ifstrempty{#5}{% % For empty labels, we still put the node at the appropriate position as it may needs to be referenced, but we will not let it effect the bounding box (so that the left end is not shifted), and we don't need an inner separation, so that the label is truely just a coordinate. - \path[overlay] - (#2, \wireypos)% - coordinate[name prefix=, name suffix=, name=yquantbox]; + \path[overlay]% + (\createxpos, \wireypos)% + coordinate[name prefix=, name suffix=, name=yquantbox];% + \let\pgfshapeclippathhorzresult=\empty% }{% - \path - (#2, \wireypos)% - node[/yquant/every label, /yquant/every initial label,% - /yquant/every #3 label, name prefix=, name suffix=, name=yquantbox]% - {#4};% + \edef\cmd{% + \noexpand\path% + (\createxpos, \wireypos)% + node[/yquant/every label, /yquant/every initial label,% + /yquant/every #3 label\ifx1#4, /yquant/every input label\fi,% + name prefix=, name suffix=, name=yquantbox]% + {\unexpanded{#5}};% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \pgfshapeclippath{yquantbox}% + {/yquant/every label, /yquant/every initial label,% + /yquant/every #3 label\ifx1#4, /yquant/every input label\fi}% + \fi% + }% + \cmd% }% - % set the wire style to have the correct \pgflinewidth available (we don't allow individual line widths for different types of wires) - \tikzset{/yquant/every wire}% - \pgfpointanchor{yquantbox}{east}% - \yquant@register@set@lastwire{#1}{{\the\pgf@x}{\the\pgf@x}{}{}}% - \ifstrempty{#5}\relax{% - \pgfnodealias{\tikz@pp@name{#5}}{yquantbox}% + \ifcsname\yquant@prefix registermap@#1\endcsname% + % if this is an alias, the creation is just an extension + \if\yquant@register@type@none\yquant@register@get@type{#1}% + \ifstrequal{#3}{initial}{% + \yquant@circuit@extendwire{#1}{east}% + }{% + % however, our inner wire is present, while the outer wire was discarded. + \tikzset{/yquant/every wire}% + \pgfpointanchor{yquantbox}{east}% + \yquant@register@set@lastwire{#1}{% + {\the\pgf@x}{\the\pgf@x}{}% + {\unexpanded\expandafter{\pgfshapeclippathhorzresult}}% + }% + }% + \else% + \yquant@circuit@extendwire{#1}{east}% + \fi% + \else% + % set the wire style to have the correct \pgflinewidth available (we don't allow individual line widths for different types of wires) + \tikzset{/yquant/every wire}% + \pgfpointanchor{yquantbox}{east}% + \yquant@register@set@lastwire{#1}{{\the\pgf@x}{\the\pgf@x}{}{}}% + \fi% + \ifstrempty{#6}\relax{% + \pgfnodealias{\tikz@pp@name{#6}}{yquantbox}% }% \endgroup% } % END_FOLD +% BEGIN_FOLD Define own gates +\def\yquantdefinegate#1{% + \ifcsname yquant@lang@#1\endcsname% + \PackageError{yquant.sty}{Gate redefined}% + {The gate `#1' already exists. Use \string\yquantredefinegate\space if you really want to redefine it.}% + \fi% + \@ifnextchar[{\yquantdefinegate@i{#1}}% + {\yquantdefinegate@i{#1}[/yquant/operators/every custom gate]}% +} + +% while this command is provided to redefine gates, we do not clear the attributes that were once assigned to the previous one, so gate redefinition is discouraged! +\def\yquantredefinegate#1{% + \unless\ifcsname yquant@lang@#1\endcsname% + \PackageError{yquant.sty}{Unknown gate redefined}% + {The gate `#1' is unknown and cannot be redefined. Use \string\yquantdefinegate\space to define it.}% + \fi% + \@ifnextchar[{\yquantdefinegate@i{#1}}% + {\yquantdefinegate@i{#1}[/yquant/operators/every custom gate]}% +} + +\protected\long\def\yquantdefinegate@i#1[#2]#3{% + \pgfkeys{/yquant/operators/every #1/.style={#2}}% + \protected@edef\yquantdefinegate@do{% + \yquant@langhelper@declare@command% + {#1}% + \expandafter\noexpand\csname yquant@lang@@#1\endcsname% + % This does not clear the attributes for redefines, but makes at least sure nothing is marked as required that should not be. + \yquant@langhelper@setup@attrs{#1}{}{}% + % Now define the gate's content as a macro + \def\expandafter\noexpand\csname yquant@lang@@@#1\endcsname{% + #3% + }% + % And provide the implementation + \protected\def\expandafter\noexpand\csname yquant@lang@@#1\endcsname####1####2####3{% + \yquant@register@get@multiaslist% + \yquant@circuit@operator{####1}{####2}{####3}% + \let\noexpand\yquant@lang@attr@value=\expandafter\noexpand\csname yquant@lang@@@#1\endcsname% + \yquant@draw@@subcircuit{/yquant/operators/every #1}% + }% + }% + \yquantdefinegate@do% +} + +\def\yquantdefinebox#1{% + \ifcsname yquant@lang@#1\endcsname% + \PackageError{yquant.sty}{Gate redefined}% + {The gate `#1' already exists. Use \string\yquantredefinebox\space if you really want to redefine it.}% + \fi% + \@ifnextchar[{\yquantdefinebox@i{#1}}% + {\yquantdefinebox@i{#1}[/yquant/operators/every box]}% +} + +\def\yquantredefinebox#1{% + \unless\ifcsname yquant@lang@#1\endcsname% + \PackageError{yquant.sty}{Unknown gate redefined}% + {The gate `#1' is unknown and cannot be redefined. Use \string\yquantdefinebox\space to define it.}% + \fi% + \yquantdefinebox@i{#1}% + \@ifnextchar[{\yquantdefinebox@i{#1}}% + {\yquantdefinebox@i{#1}[/yquant/operators/every box]}% +} + +\protected\long\def\yquantdefinebox@i#1[#2]#3{% + \pgfkeys{/yquant/operators/every #1/.style={#2}}% + \protected@edef\yquantdefinebox@do{% + \yquant@langhelper@declare@command% + {#1}% + \expandafter\noexpand\csname yquant@lang@@#1\endcsname% + \yquant@langhelper@setup@attrs{#1}{}{}% + \def\expandafter\noexpand\csname yquant@lang@@#1\endcsname{% + \yquant@draw% + {#3}% + {/yquant/operators/every #1}% + }% + }% + \yquantdefinebox@do% +} +% END_FOLD + % BEGIN_FOLD Box registers % all-purpose box with arbitrary text \yquant@langhelper@declare@command{box}\yquant@lang@@box @@ -187,68 +412,30 @@ \def\yquant@lang@@box{% \yquant@register@get@allowmultitrue% \expandafter\yquant@draw% - \expandafter{\yquant@lang@attr@value} + \expandafter{\yquant@lang@attr@value}% {/yquant/operators/every box}% } % Hadamard -\yquant@langhelper@declare@command{h}\yquant@lang@@h -\yquant@langhelper@setup@attrs{h}{}{} -\def\yquant@lang@@h{% - \yquant@draw% - {$H$}% - {/yquant/operators/every h}% -} +\yquantdefinebox{h}{$H$} % Pauli X (or NOT) -\yquant@langhelper@declare@command{x}\yquant@lang@@x -\yquant@langhelper@setup@attrs{x}{}{} -\def\yquant@lang@@x{% - \yquant@draw% - {$X$}% - {/yquant/operators/every x}% -} +\yquantdefinebox{x}[/yquant/operators/every pauli]{$X$} % Pauli Y -\yquant@langhelper@declare@command{y}\yquant@lang@@y -\yquant@langhelper@setup@attrs{y}{}{} -\def\yquant@lang@@y{% - \yquant@draw% - {$Y$}% - {/yquant/operators/every y}% -} +\yquantdefinebox{y}[/yquant/operators/every pauli]{$Y$} % Pauli Z -\yquant@langhelper@declare@command{z}\yquant@lang@@z -\yquant@langhelper@setup@attrs{z}{}{} -\def\yquant@lang@@z{% - \yquant@draw% - {$Z$}% - {/yquant/operators/every z}% -} +\yquantdefinebox{z}[/yquant/operators/every pauli]{$Z$} % sub-circuit: This is a nested circuit. -%\yquant@langhelper@declare@command{subcircuit}\yquant@lang@@subcircuit -%\yquant@langhelper@setup@attrs{subcircuit}{}{shift} -%\protected\def\yquant@lang@@subcircuit#1#2#3{% -% % First we restore access to the yquant environment (which was a shorthand to -% % re-starting the parser within the environment, conveniently forbidding nesting). -% \let\yquant=\yquant@envunstar% -% \cslet{yquant*}\yquant@envstar% -% % Then determine the actual subcircuit content. -% \yquant@circuit@subcircuit\yquant@lang@attr@value% -% % Now the subcircuit is stored in \yquant@circuit@subcircuit@box. However, note that -% % it may contain named nodes (whose names are stored in -% % \csname\yquant@prefix circuit@subcircuit@nodelist\endcsname) that need to be shifted -% % whenever we actually position the subcircuit. -%% \let\yquant@draw@callback@box=\yquant@circuit@subcircuit@shiftnodes% -% \yquant@register@get@allowmultitrue% -% \yquant@draw% -% {\copy\yquant@circuit@subcircuit@box}% -% {/yquant/operators/every subcircuit} -% {#1}{#2}{#3}% -% \global\setbox\yquant@circuit@subcircuit@box=\box\voidb@x% memory management -%} +\yquant@langhelper@declare@command{subcircuit}\yquant@lang@@subcircuit +\yquant@langhelper@setup@attrs{subcircuit}{value}{} +\protected\def\yquant@lang@@subcircuit#1#2#3{% + \yquant@register@get@multiaslist% + \yquant@circuit@operator{#1}{#2}{#3}% + \yquant@draw@@subcircuit{/yquant/operators/every subcircuit}% +} % END_FOLD % BEGIN_FOLD other geometric shapes @@ -291,8 +478,8 @@ \protected\def\yquant@lang@@slash#1{% % temporarily squeeze most into the separation \pgfkeys{% - /yquant/operator/minimum width=0pt, - /yquant/operator/separation=.5\dimexpr\yquant@config@operator@sep-\pgflinewidth\relax + /yquant/operator/minimum width=0pt,% + /yquant/operator/separation=.5\dimexpr\yquant@config@operator@sep-\pgflinewidth\relax% }% \def\yquant@draw@callback@wire##1{% \yquant@register@set@x% @@ -332,20 +519,7 @@ \yquant@langhelper@setup@attrs{measure}{}{value,type} \def\yquant@lang@@measure{% \ifdefined\yquant@lang@attr@type% - \expandafter\ifstrequal\expandafter{\yquant@lang@attr@type}{qubit}% - {\let\yquant@circuit@settype@to=\yquant@register@type@q}% - {% - \expandafter\ifstrequal\expandafter{\yquant@lang@attr@type}{cbit}% - {\let\yquant@circuit@settype@to=\yquant@register@type@c}% - {% - \expandafter\ifstrequal\expandafter{\yquant@lang@attr@type}{qubits}% - {\let\yquant@circuit@settype@to=\yquant@register@type@qs}% - {% - \PackageError{yquant.sty}{Invalid bit type: `\yquant@lang@attr@type}% - {Use one of `qubit', `cbit', or `qubits'.}% - }% - }% - }% + \yquant@register@type@fromstring\yquant@lang@attr@type\yquant@circuit@settype@to% \else% \let\yquant@circuit@settype@to=\yquant@register@type@c% \fi% @@ -365,20 +539,7 @@ \yquant@langhelper@setup@attrs{dmeter}{}{value,type} \def\yquant@lang@@dmeter{% \ifdefined\yquant@lang@attr@type% - \expandafter\ifstrequal\expandafter{\yquant@lang@attr@type}{qubit}% - {\let\yquant@circuit@settype@to=\yquant@register@type@q}% - {% - \expandafter\ifstrequal\expandafter{\yquant@lang@attr@type}{cbit}% - {\let\yquant@circuit@settype@to=\yquant@register@type@c}% - {% - \expandafter\ifstrequal\expandafter{\yquant@lang@attr@type}{qubits}% - {\let\yquant@circuit@settype@to=\yquant@register@type@qs}% - {% - \PackageError{yquant.sty}{Invalid bit type: `\yquant@lang@attr@type}% - {Use one of `qubit', `cbit', or `qubits'.}% - }% - }% - }% + \yquant@register@type@fromstring\yquant@lang@attr@type\yquant@circuit@settype@to% \else% \let\yquant@circuit@settype@to=\yquant@register@type@c% \fi% @@ -402,7 +563,7 @@ \yquant@draw% {}% {/yquant/operators/every barrier}% - {}{} + {}{}% } \yquant@langhelper@declare@command@uncontrolled{correlate}\yquant@lang@@correlate @@ -453,25 +614,12 @@ \fi% }% } -\long\def\@fifthoffive#1#2#3#4#5{#5} + \protected\def\yquant@lang@@init#1{% \yquant@register@get@allowmultitrue% \yquant@register@get@ids{#1}% \ifdefined\yquant@lang@attr@type% - \expandafter\ifstrequal\expandafter{\yquant@lang@attr@type}{qubit}% - {\let\yquant@circuit@settype@to=\yquant@register@type@q}% - {% - \expandafter\ifstrequal\expandafter{\yquant@lang@attr@type}{cbit}% - {\let\yquant@circuit@settype@to=\yquant@register@type@c}% - {% - \expandafter\ifstrequal\expandafter{\yquant@lang@attr@type}{qubits}% - {\let\yquant@circuit@settype@to=\yquant@register@type@qs}% - {% - \PackageError{yquant.sty}{Invalid bit type: `\yquant@lang@attr@type}% - {Use one of `qubit', `cbit', or `qubits'.}% - }% - }% - }% + \yquant@register@type@fromstring\yquant@lang@attr@type\yquant@circuit@settype@to% \else% % We don't know which type is desired. Scan all target registers and use the first wire that is available as a type. \let\yquant@circuit@settype@to=\yquant@register@type@none% @@ -492,15 +640,9 @@ % now we don't have a clue; assume it's a qubit \let\yquant@circuit@settype@to=\yquant@register@type@q% \fi% - \ifx\yquant@circuit@settype@to\yquant@register@type@q% - \def\yquant@lang@attr@type{qubit}% - \else% - \ifx\yquant@circuit@settype@to\yquant@register@type@c% - \def\yquant@lang@attr@type{cbit}% - \else% - \def\yquant@lang@attr@type{qubits}% - \fi% - \fi% + \edef\yquant@lang@attr@type{% + \yquant@register@type@tostring\yquant@circuit@settype@to% + }% \fi% \let\yquant@draw@callback@wire=\yquant@circuit@settype% \let\yquant@draw@@multi=\yquant@draw@@multiinit% @@ -532,20 +674,7 @@ \yquant@langhelper@setup@attrs{settype}{value}{} \protected\def\yquant@lang@@settype#1{% \yquant@register@get@ids{#1}% - \expandafter\ifstrequal\expandafter{\yquant@lang@attr@value}{qubit}% - {\let\yquant@circuit@settype@to=\yquant@register@type@q}% - {% - \expandafter\ifstrequal\expandafter{\yquant@lang@attr@value}{cbit}% - {\let\yquant@circuit@settype@to=\yquant@register@type@c}% - {% - \expandafter\ifstrequal\expandafter{\yquant@lang@attr@value}{qubits}% - {\let\yquant@circuit@settype@to=\yquant@register@type@qs}% - {% - \PackageError{yquant.sty}{Invalid bit type: `\yquant@lang@attr@value}% - {Use one of `qubit', `cbit', or `qubits'.}% - }% - }% - }% + \yquant@register@type@fromstring\yquant@lang@attr@value\yquant@circuit@settype@to% \yquant@circuit@actonwires% \yquant@circuit@settype% \yquant@register@get@ids@list% diff --git a/graphics/pgf/contrib/yquant/tex/yquant-langhelper.tex b/graphics/pgf/contrib/yquant/tex/yquant-langhelper.tex index 102a8959d9..8611424194 100644 --- a/graphics/pgf/contrib/yquant/tex/yquant-langhelper.tex +++ b/graphics/pgf/contrib/yquant/tex/yquant-langhelper.tex @@ -45,7 +45,7 @@ }% \fi% \endpgfkeysinterruptkeyfilter% - }, + },% /pgf/key filters/attr filter/.code={% % we need to capture every non-attribute (which means filtering them out). \expandafter\ifyquant@beginswith\expandafter{\pgfkeyscurrentkey}{/yquant/attrs/}{% @@ -84,9 +84,9 @@ \pgfkeysfiltercontinuefalse% }% }% - }, - /yquant/attr filter/.style={ - /pgf/key filters/attr filter/.install key filter, + },% + /yquant/attr filter/.style={% + /pgf/key filters/attr filter/.install key filter,% /yquant/attr filter handler/.install key filter handler=\yquant@attrs@remaining% }% } @@ -112,7 +112,7 @@ \pgfkeysinterruptkeyfilter% \pgfkeys{/yquant/all attrs/##1={####1}}% \endpgfkeysinterruptkeyfilter% - } + }% }% }% \eappto\keysset{% diff --git a/graphics/pgf/contrib/yquant/tex/yquant-registers.tex b/graphics/pgf/contrib/yquant/tex/yquant-registers.tex index 18a23662d3..c90a44614c 100644 --- a/graphics/pgf/contrib/yquant/tex/yquant-registers.tex +++ b/graphics/pgf/contrib/yquant/tex/yquant-registers.tex @@ -3,6 +3,38 @@ \def\yquant@register@type@c{2} \def\yquant@register@type@qs{3} +\def\yquant@register@type@tostring#1{% + \ifcase#1 % + nobit% + \or% + qubit% + \or% + cbit% + \or% + qubits% + \else% + \PackageError{yquant.sty}{Internal inconsistency detected}% + {Unknown wire type: `#1'.}% + \fi% +} + +\protected\def\yquant@register@type@fromstring#1#2{% + \expandafter\ifstrequal\expandafter{#1}{qubit}% + {\let#2=\yquant@register@type@q}% + {% + \expandafter\ifstrequal\expandafter{#1}{cbit}% + {\let#2=\yquant@register@type@c}% + {% + \expandafter\ifstrequal\expandafter{#1}{qubits}% + {\let#2=\yquant@register@type@qs}% + {% + \PackageError{yquant.sty}{Invalid bit type: `#1'}% + {Use one of `qubit', `cbit', or `qubits'.}% + }% + }% + }% +} + % Internally, we store the register information in a single macro. Indeed, this is almost always faster than using multiple macros (at least in the way implemented here), apart from changing a single type of information, which is almost as fast. % BEGIN_FOLD Constructor: create single register and cleanup environment @@ -16,17 +48,55 @@ \csxdef{\yquant@prefix register@\csname\yquant@prefix registers\endcsname}{% {#1}% type {#2}% x pos - {\yquant@config@register@minimum@height}% height; at the end, the y position - {{0pt}{0pt}{}{}}% wire start positions and clipping + {{\the\dimexpr.5\dimexpr\yquant@config@register@minimum@height\relax\relax}% + {\the\dimexpr.5\dimexpr\yquant@config@register@minimum@height\relax\relax}}% height and depth; at the end, the y position + {{\yquant@env@create@x}{\yquant@env@create@x}{}{}}% wire start positions and clipping {}% wire style }% \global\csletcs{\yquant@prefix registername@#3[#4]}{\yquant@prefix registers}% - \csxdef{\yquant@prefix registerhigh@\reg}{#4}% + \csxdef{\yquant@prefix registerhigh@#3}{#4}% \yquant@cleanup@csadd{\yquant@prefix register@\csname\yquant@prefix registers\endcsname}% \yquant@cleanup@csadd{\yquant@prefix registername@#3[#4]}% \ifnum0=#4\relax% - \yquant@cleanup@csadd{\yquant@prefix registerhigh@\reg}% + \yquant@cleanup@csadd{\yquant@prefix registerhigh@#3}% + \fi% +} + +% in a subcircuit, create a new register that is only an alias for an existing register in the outer circuit. +% #5: id in the outer circuit +\protected\def\yquant@register@alias#1#2#3#4#5{% + \csnumgdef{\yquant@prefix registers}% + {\csname\yquant@prefix registers\endcsname+1}% + \ifcsname\yquant@parent registermap@#5\endcsname% + % the parent is already an alias itself, pass this on transparently + \global\csletcs% + {\yquant@prefix registermap@\csname\yquant@prefix registers\endcsname}% + {\yquant@parent registermap@#5}% + \else% + \csxdef{\yquant@prefix registermap@\csname\yquant@prefix registers\endcsname}% + {\yquant@parent register@#5}% + \fi% + % even though this is an alias, we still need to keep track of its internal dimensions + \csgdef{\yquant@prefix registerdim@\csname\yquant@prefix registers\endcsname}% + {{0pt}{0pt}}% + \yquant@cleanup@csadd{\yquant@prefix registerdim@\csname\yquant@prefix registers\endcsname}% + \global\csletcs{\yquant@prefix registername@#3[#4]}{\yquant@prefix registers}% + \csxdef{\yquant@prefix registerhigh@#3}{#4}% + \yquant@cleanup@csadd{\yquant@prefix registermap@\csname\yquant@prefix registers\endcsname}% + \yquant@cleanup@csadd{\yquant@prefix registername@#3[#4]}% + \ifnum0=#4\relax% + \yquant@cleanup@csadd{\yquant@prefix registerhigh@#3}% + \fi% + \csxdef{\yquant@prefix lastinput}{{\csname\yquant@prefix registers\endcsname}{#5}}% + \unless\ifcsname\yquant@prefix firstinput\endcsname% + \csxdef{\yquant@prefix firstinput}{{\csname\yquant@prefix registers\endcsname}{#5}}% + \yquant@cleanup@csadd{\yquant@prefix firstinput}% + \yquant@cleanup@csadd{\yquant@prefix lastinput}% \fi% + \expandafter\yquant@register@set@@aux% + \csname\csname\yquant@prefix registermap@\csname\yquant@prefix registers\endcsname\endcsname\endcsname% + \yquant@register@set@x@aux% + {#2}% } % END_FOLD @@ -43,19 +113,17 @@ % same as before, but resolves to the _index_ of the last register \protected\def\yquant@register@get@id@high#1#2{% - \ifcsname\yquant@prefix registerhigh@#2\endcsname% - \letcs#1{\yquant@prefix registerhigh@#2}% - \else% + \unless\ifcsname\yquant@prefix registerhigh@#2\endcsname% \yquant@register@get@id@lazycreate{#2}% - \letcs#1{\yquant@prefix registers}% \fi% + \letcs#1{\yquant@prefix registerhigh@#2}% } % In the lazy mode, we create all unknown registers on-the-fly. \def\yquant@register@get@id@lazycreate#1{% \ifyquant@env@lazy% % In principle, we could just call \yquant@lang@@qubit. However, if access to a vector register is desired and a _part_ of this does already exist (though not the requested index), we only create the missing registers. - \yquant@register@get@id@lazycreate@parse#1[; + \yquant@register@get@id@lazycreate@parse#1[;% \else% \PackageError{yquant.sty}{Register `#1' unknown}% {You referred to an unknown register. @@ -96,13 +164,14 @@ \yquant@for \idx := \idx to \numexpr \len -1\relax {% \yquant@register@define% \yquant@register@type@q% - {0pt}% - \reg\idx + {\yquant@env@create@x}% + \reg\idx% % Prepare to shipout \csxappto{\yquant@prefix draw}{% \yquant@lang@create@draw{\csname\yquant@prefix registers\endcsname}% {0pt}% {qubit}% + 0% {}% {}% }% @@ -137,7 +206,10 @@ \catcode`(=\active% \def[##1]{\yquant@register@get@ids@@index{##1}}% \def(##1){\yquant@register@get@ids@@multi{##1}}% - \edef\yquant@register@get@ids@retokenized{\scantokens{#1\noexpand}}% + % this is also invoked by other languages which might have completely redefined all catcodes (qasm redefines the backslash), so don't just add \noexpand at the end of the \scantokens... + \everyeof{\noexpand}% + \endlinechar=-1 % + \edef\yquant@register@get@ids@retokenized{\scantokens{#1}}% \expandafter% \endgroup% \expandafter\docsvlist\expandafter{\yquant@register@get@ids@retokenized}% @@ -239,7 +311,7 @@ }% \count0=2147483647 % \csletcs{ifallowmain}{iffalse}% - }{ + }{% \let\yquant@register@get@ids@norange@checkindex@setmain=\relax% }% \else% @@ -346,7 +418,7 @@ \expandafter\yquant@register@get@id\expandafter\idx\expandafter{\idx}% \count6=\idx% \csletcs{ifallowmain}{iffalse}% - }{ + }{% \yquant@register@get@id\idx{\current[#1]}% }% \else% @@ -575,50 +647,99 @@ }% } +\protected\def\yquant@register@multi@splitparts@sort{% + \yquant@sort@list\yquant@register@get@ids@list\yquant@sort@ascending% +} + \protected\def\yquant@register@get@multiassingle{% \yquant@register@get@allowmultitrue% \let\yquant@register@multi@splitparts=\yquant@register@multi@splitparts@sepall% \preto\yquant@attrs@remaining{/yquant/operator/multi as single,}% } + +\protected\def\yquant@register@get@multiaslist{% + \yquant@register@get@allowmultitrue% + \let\yquant@register@multi@splitparts=\yquant@register@multi@splitparts@sort% +} + +\let\yquant@register@multi@reset@original@splitparts=\yquant@register@multi@splitparts% +\protected\def\yquant@register@reset@multi{% +% \yquant@register@get@allowmultifalse% not needed, as \yquant@circuit@operator automatically resets it + \let\yquant@register@multi@splitparts=\yquant@register@multi@reset@original@splitparts% +} % END_FOLD % BEGIN_FOLD Getters: extract the requested information from the register with given id \def\yquant@register@get@type#1{% - \expandafter\expandafter\expandafter% - \yquant@register@get@type@aux\csname\yquant@prefix register@#1\endcsname% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\expandafter\expandafter% + \yquant@register@get@type@aux\csname\csname\yquant@prefix registermap@#1\endcsname\endcsname% + \else% + \expandafter\expandafter\expandafter% + \yquant@register@get@type@aux\csname\yquant@prefix register@#1\endcsname% + \fi% } \def\yquant@register@get@type@aux#1#2#3#4#5{#1} \def\yquant@register@get@x#1{% - \expandafter\expandafter\expandafter% - \yquant@register@get@x@aux\csname\yquant@prefix register@#1\endcsname% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\expandafter\expandafter% + \yquant@register@get@x@aux\csname\csname\yquant@prefix registermap@#1\endcsname\endcsname% + \else% + \expandafter\expandafter\expandafter% + \yquant@register@get@x@aux\csname\yquant@prefix register@#1\endcsname% + \fi% } \def\yquant@register@get@x@aux#1#2#3#4#5{#2} \def\yquant@register@get@height#1{% - \expandafter\expandafter\expandafter% - \yquant@register@get@height@aux\csname\yquant@prefix register@#1\endcsname% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\expandafter\expandafter% + \@firstoftwo\csname\yquant@prefix registerdim@#1\endcsname% + \else% + \expandafter\expandafter\expandafter% + \yquant@register@get@height@aux\csname\yquant@prefix register@#1\endcsname% + \fi% } -\def\yquant@register@get@height@aux#1#2#3#4#5{#3} +\def\yquant@register@get@height@aux#1#2#3#4#5{\@firstoftwo#3} + +\def\yquant@register@get@depth#1{% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\expandafter\expandafter% + \@secondoftwo\csname\yquant@prefix registerdim@#1\endcsname% + \else% + \expandafter\expandafter\expandafter% + \yquant@register@get@depth@aux\csname\yquant@prefix register@#1\endcsname% + \fi% +} + +\def\yquant@register@get@depth@aux#1#2#3#4#5{\@secondoftwo#3} % The y parameter get macros exist in two forms: The protected one is used during the storage to the draw macro; it should never be executed. The env environment then maps them to their proper expandable forms. -\protected\def\yquant@register@get@@protected{% +\protected\def\yquant@register@get@y{% \PackageError% {yquant.sty}% {Execution of a get-y macro in an illegal context}% {get-y macros may not be called unless the yquant environment ends.}% } -\let\yquant@register@get@y=\yquant@register@get@@protected -\let\yquant@register@y=\yquant@register@get@@protected % This plays a similar role: It must never be expanded before the tikz command is invoked (because it does not exist). -\let\nodepart=\yquant@register@get@@protected +\protected\def\nodepart{} -% getting the y position is the same as getting the height parameter, since we will reuse it at the end. -\let\yquant@register@get@y@unprotected=\yquant@register@get@height +\def\yquant@register@get@y@unprotected#1{% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\expandafter\expandafter% + \yquant@register@get@y@aux\csname\csname\yquant@prefix registermap@#1\endcsname\endcsname% + \else% + \expandafter\expandafter\expandafter% + \yquant@register@get@y@aux\csname\yquant@prefix register@#1\endcsname% + \fi% +} + +\def\yquant@register@get@y@aux#1#2#3#4#5{#3} % y distance between two registers. \def\yquant@register@get@ydist#1#2{% @@ -626,17 +747,23 @@ {\the\dimexpr\yquant@register@get@y{#2}-\yquant@register@get@y{#1}\relax}% } -% y position of the current register -\def\yquant@register@y@unprotected{0pt}% - \protected\def\yquant@register@get@y@@expandable{% \let\yquant@register@get@y=\yquant@register@get@y@unprotected% - \let\yquant@register@y=\yquant@register@y@unprotected% } \def\yquant@register@get@lastwire#1{% - \expandafter\expandafter\expandafter% - \yquant@register@get@lastwire@aux\csname\yquant@prefix register@#1\endcsname% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\@firstoftwo% + \else% + \expandafter\@secondoftwo% + \fi% + {% + \expandafter\expandafter\expandafter% + \yquant@register@get@lastwire@aux\csname\csname\yquant@prefix registermap@#1\endcsname\endcsname% + }{% + \expandafter\expandafter\expandafter% + \yquant@register@get@lastwire@aux\csname\yquant@prefix register@#1\endcsname% + }% } \protected\def\yquant@register@get@lastwire@aux#1#2#3#4#5#6{% @@ -644,15 +771,30 @@ } \def\yquant@register@get@style#1{% - \expandafter\expandafter\expandafter% - \yquant@register@get@style@aux\csname\yquant@prefix register@#1\endcsname% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\expandafter\expandafter% + \yquant@register@get@style@aux\csname\csname\yquant@prefix registermap@#1\endcsname\endcsname% + \else% + \expandafter\expandafter\expandafter% + \yquant@register@get@style@aux\csname\yquant@prefix register@#1\endcsname% + \fi% } \def\yquant@register@get@style@aux#1#2#3#4#5{#5} \def\yquant@register@get@typeywire#1{% - \expandafter\expandafter\expandafter% - \yquant@register@get@typeywire@aux\csname\yquant@prefix register@#1\endcsname% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\@firstoftwo% + \else% + \expandafter\@secondoftwo% + \fi% + {% + \expandafter\expandafter\expandafter% + \yquant@register@get@typeywire@aux\csname\csname\yquant@prefix registermap@#1\endcsname\endcsname% + }{% + \expandafter\expandafter\expandafter% + \yquant@register@get@typeywire@aux\csname\yquant@prefix register@#1\endcsname% + }% } \protected\def\yquant@register@get@typeywire@aux#1#2#3#4#5#6#7#8{% @@ -695,12 +837,23 @@ % BEGIN_FOLD Setters: change register information \protected\long\def\yquant@register@set@@aux#1#2#3{% - \long\xdef#1{\expandafter#2#1{#3}}% + \xdef#1{\expandafter#2#1{#3}}% } \protected\def\yquant@register@set@type#1{% - \expandafter\yquant@register@set@@aux% - \csname\yquant@prefix register@#1\endcsname\yquant@register@set@type@aux% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\@firstoftwo% + \else% + \expandafter\@secondoftwo% + \fi% + {% + \expandafter\yquant@register@set@@aux% + \csname\csname\yquant@prefix registermap@#1\endcsname\endcsname% + }{% + \expandafter\yquant@register@set@@aux% + \csname\yquant@prefix register@#1\endcsname% + }% + \yquant@register@set@type@aux% } \long\def\yquant@register@set@type@aux#1#2#3#4#5#6{% @@ -708,8 +861,19 @@ } \protected\def\yquant@register@set@x#1{% - \expandafter\yquant@register@set@@aux% - \csname\yquant@prefix register@#1\endcsname\yquant@register@set@x@aux% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\@firstoftwo% + \else% + \expandafter\@secondoftwo% + \fi% + {% + \expandafter\yquant@register@set@@aux% + \csname\csname\yquant@prefix registermap@#1\endcsname\endcsname% + }{% + \expandafter\yquant@register@set@@aux% + \csname\yquant@prefix register@#1\endcsname% + }% + \yquant@register@set@x@aux% } \long\def\yquant@register@set@x@aux#1#2#3#4#5#6{% @@ -717,25 +881,99 @@ } \protected\def\yquant@register@update@height#1#2{% - \ifdim#2>\yquant@register@get@height{#1} % - \expandafter\yquant@register@set@@aux% - \csname\yquant@prefix register@#1\endcsname\yquant@register@set@height@aux{#2}% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \ifdim#2>% + \expandafter\expandafter\expandafter% + \@firstoftwo\csname\yquant@prefix registerdim@#1\endcsname% + \relax% + \csxdef{\yquant@prefix registerdim@#1}{% + {#2}% + {\expandafter\expandafter\expandafter% + \@secondoftwo\csname\yquant@prefix registerdim@#1\endcsname}% + }% + \fi% + \else% + \ifdim#2>% + \expandafter\expandafter\expandafter% + \yquant@register@get@height@aux\csname\yquant@prefix register@#1\endcsname% + \relax% + \expandafter\yquant@register@set@@aux% + \csname\yquant@prefix register@#1\endcsname% + \yquant@register@set@height@aux{#2}% + \fi% + \fi% +} + +\long\def\yquant@register@set@height@aux#1#2#3#4#5#6{% + \unexpanded{{#1}{#2}}% + {{#6}{\unexpanded\expandafter{\@secondoftwo#3}}}% + \unexpanded{{#4}{#5}}% +} + +\protected\def\yquant@register@update@depth#1#2{% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \ifdim#2>% + \expandafter\expandafter\expandafter% + \@secondoftwo\csname\yquant@prefix registerdim@#1\endcsname% + \relax% + \csxdef{\yquant@prefix registerdim@#1}{% + {\expandafter\expandafter\expandafter% + \@firstoftwo\csname\yquant@prefix registerdim@#1\endcsname}% + {#2}% + }% + \fi% + \else% + \ifdim#2>% + \expandafter\expandafter\expandafter% + \yquant@register@get@depth@aux\csname\yquant@prefix register@#1\endcsname% + \relax% + \expandafter\yquant@register@set@@aux% + \csname\yquant@prefix register@#1\endcsname% + \yquant@register@set@depth@aux{#2}% + \fi% \fi% } +\long\def\yquant@register@set@depth@aux#1#2#3#4#5#6{% + \unexpanded{{#1}{#2}}% + {{\unexpanded\expandafter{\@firstoftwo#3}}{#6}}% + \unexpanded{{#4}{#5}}% +} + \protected\def\yquant@register@set@y#1{% - \expandafter\yquant@register@set@@aux% - \csname\yquant@prefix register@#1\endcsname\yquant@register@set@height@aux% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\@firstoftwo% + \else% + \expandafter\@secondoftwo% + \fi% + {% + \expandafter\yquant@register@set@@aux% + \csname\csname\yquant@prefix registermap@#1\endcsname\endcsname% + }{% + \expandafter\yquant@register@set@@aux% + \csname\yquant@prefix register@#1\endcsname% + }% + \yquant@register@set@y@aux% } -% Set the currently used register -\long\def\yquant@register@set@height@aux#1#2#3#4#5#6{% +\long\def\yquant@register@set@y@aux#1#2#3#4#5#6{% \unexpanded{{#1}{#2}}{#6}\unexpanded{{#4}{#5}}% } \protected\def\yquant@register@set@lastwire#1{% - \expandafter\yquant@register@set@@aux% - \csname\yquant@prefix register@#1\endcsname\yquant@register@set@lastwire@aux% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\@firstoftwo% + \else% + \expandafter\@secondoftwo% + \fi% + {% + \expandafter\yquant@register@set@@aux% + \csname\csname\yquant@prefix registermap@#1\endcsname\endcsname% + }{% + \expandafter\yquant@register@set@@aux% + \csname\yquant@prefix register@#1\endcsname% + }% + \yquant@register@set@lastwire@aux% } \long\def\yquant@register@set@lastwire@aux#1#2#3#4#5#6{% @@ -743,8 +981,19 @@ } \protected\def\yquant@register@set@style#1{% - \expandafter\yquant@register@set@@aux% - \csname\yquant@prefix register@#1\endcsname\yquant@register@set@style@aux% + \ifcsname\yquant@prefix registermap@#1\endcsname% + \expandafter\@firstoftwo% + \else% + \expandafter\@secondoftwo% + \fi% + {% + \expandafter\yquant@register@set@@aux% + \csname\csname\yquant@prefix registermap@#1\endcsname\endcsname% + }{% + \expandafter\yquant@register@set@@aux% + \csname\yquant@prefix register@#1\endcsname% + }% + \yquant@register@set@style@aux% } \long\def\yquant@register@set@style@aux#1#2#3#4#5#6{% diff --git a/graphics/pgf/contrib/yquant/tex/yquant-shapes.tex b/graphics/pgf/contrib/yquant/tex/yquant-shapes.tex index 3a03985ca5..7ce146171b 100644 --- a/graphics/pgf/contrib/yquant/tex/yquant-shapes.tex +++ b/graphics/pgf/contrib/yquant/tex/yquant-shapes.tex @@ -21,7 +21,7 @@ {\PackageError{yquant.sty}% {Failed to patch \string\pgfdeclareshape}% {yquant could not provide a necessary extension to pgf.}}% -% Every shape additionally provides information about how it should clip the wires. The clipping softpath instructions of shape #1 are stored into \pgfshapeclippathresult. The path is drawn with the tikz options #2 in place. +% Every shape additionally provides information about how it should clip the wires. The clipping softpath instructions of shape #1 are stored into \pgfshapeclippath[horz|vert]result. The path is drawn with the tikz options #2 in place. \protected\def\pgfshapeclippath#1#2{% % Ok, check whether #1 is known! \ifcsname pgf@sh@ns@#1\endcsname% @@ -56,7 +56,8 @@ \end{pgfinterruptpath}% \else% \pgferror{No shape named #1 is known}% - \pgfpointorigin% + \global\let\pgfshapeclippathhorzresult=\empty% + \global\let\pgfshapeclippathvertresult=\empty% \fi% } @@ -81,7 +82,7 @@ {\southwest% \advance\pgf@x by \@tempdima% \advance\pgf@y by \@tempdimb% - } + }% {\northeast% \advance\pgf@x by -\@tempdima% \advance\pgf@y by -\@tempdimb% @@ -441,7 +442,7 @@ % we only draw the meter symbol if this is the main part of a multi-register (or there is no text) \ifyquant@config@operator@multi@main% % Make sure the meter does not extend beyond the box (we are in a scope here) - \path [clip] + \path [clip]% (-\xradius, \yradius) rectangle (\xradius, -\yradius);% % The position of the meter symbol depends on the presence of the text. If there is no text, we just vertically center. If there is some text, we shift the symbol upwards from the text until there is no overlap any more. \csname pgf@anchor@yquant-measure@text\endcsname% @@ -451,10 +452,10 @@ \else% \@tempdima=\dimexpr\pgf@y+2pt\relax% \fi% - \path [/yquant/operators/every measure meter] + \path [/yquant/operators/every measure meter]% (-2.25mm, \@tempdima) arc[start angle=160, end angle=20,% - x radius=2.25mm, y radius=1.4mm] - (0, \@tempdima) -- ++(1.6mm, 2.3mm); + x radius=2.25mm, y radius=1.4mm]% + (0, \@tempdima) -- ++(1.6mm, 2.3mm);% \fi% }% } @@ -553,7 +554,7 @@ \shorten% \@tempdima=\dimexpr\yradius+\pgf@x\relax% \@tempdimb=\dimexpr\yradius+\pgf@y\relax% - \pgfpathrectanglecorners + \pgfpathrectanglecorners% {\pgfqpoint{-.5\pgflinewidth}{\@tempdima}}% {\pgfqpoint{.5\pgflinewidth}{-\@tempdimb}}% }% diff --git a/graphics/pgf/contrib/yquant/tex/yquant-tools.tex b/graphics/pgf/contrib/yquant/tex/yquant-tools.tex index fe1efecbf4..5f7efe5e03 100644 --- a/graphics/pgf/contrib/yquant/tex/yquant-tools.tex +++ b/graphics/pgf/contrib/yquant/tex/yquant-tools.tex @@ -21,11 +21,27 @@ \let\@eattoken= % } +% a bit faster than nested \@firstoftwo/\@secondoftwo +% note \@thirdofthree is defined in the latex kernel already. +\long\def\@firstofthree#1#2#3{#1}% +\long\def\@secondofthree#1#2#3{#2}% +\long\def\@firstoffour#1#2#3#4{#1}% +\long\def\@secondoffour#1#2#3#4{#2}% +\long\def\@thirdoffour#1#2#3#4{#3}% +\long\def\@fourthoffour#1#2#3#4{#4}% +\long\def\@thirdandfourthoffour#1#2#3#4{#3#4}% +\long\def\@fifthoffive#1#2#3#4#5{#5} + % Loop #1 from min(#2, #3) to max(#2, #3), executing #4 \protected\def\yquant@for #1:=#2to#3#{% \yquant@for@aux#1{#2}{#3}% } +% Loop #1 from max(#2, #3) down to min(#2, #3), executing #4 +\protected\def\yquant@fordown #1:=#2downto#3#{% + \yquant@fordown@aux#1{#2}{#3}% +} + \long\def\yquant@for@aux#1#2#3#4{% \ifnum#2<#3\relax% \numdef#1{#2}% @@ -37,6 +53,17 @@ \fi% } +\long\def\yquant@fordown@aux#1#2#3#4{% + \ifnum#2>#3\relax% + \numdef#1{#2}% + % to allow for things like \yquant@for \i := \i to ..., expand the boundaries + \expandafter\yquant@fordown@loop\expandafter#1\expandafter{\the\numexpr#3-1\relax}{#4}% + \else% + \numdef#1{#3}% + \expandafter\yquant@fordown@loop\expandafter#1\expandafter{\the\numexpr#2-1\relax}{#4}% + \fi% +} + \long\def\yquant@for@loop#1#2#3{% \loop% \ifnum#1<#2\relax% @@ -45,6 +72,14 @@ \repeat% } +\long\def\yquant@fordown@loop#1#2#3{% + \loop% + \ifnum#1>#2\relax% + #3% + \numdef#1{#1-1}% + \repeat% +} + \def\yquant@for@break{% \fi% \iffalse% @@ -219,7 +254,7 @@ \expandafter\iffalse@hidden% \fi% \repeat% - \expandafter + \expandafter% }% \expandafter\count\expandafter2\expandafter=\the\count2\relax% \ifnum\count0<\count2 % @@ -235,15 +270,21 @@ \cslet{yquant@sort@item#2}\tmp% } +% Add an internal etoolbox list to the sorted items +\def\yquant@sort@addlist#1{% + \forlistloop\yquant@sort@addlist@aux#1% +} + +\protected\def\yquant@sort@addlist@aux#1{% + \csdef{yquant@sort@item\the\yquant@sort@count}{#1}% + \advance\yquant@sort@count by 1 % +} + % Sorts an internal etoolbox list #1 using macro #2 \protected\def\yquant@sort@list#1#2{% \begingroup% \yquant@sort@count=0 % - \def\do##1{% - \csdef{yquant@sort@item\the\yquant@sort@count}{##1}% - \advance\yquant@sort@count by 1 % - }% - \dolistloop#1% + \yquant@sort@addlist#1% \yquant@sort#2% \let#1=\empty% \count0=0 % @@ -268,7 +309,278 @@ \expandafter\expandafter\expandafter\do% \expandafter\expandafter\expandafter{% \csname yquant@sort@item\the\count0\endcsname% - } + }% \advance\count0 by 1 % \repeat% +} + +\begingroup +\catcode`\|=3 +\gdef\yquant@list@delim{|} + +\protected\gdef\yquant@list@dequeue#1#2{% + \expandafter\ifblank\expandafter{#1}{% + \let#2=\empty% + }{% + \expandafter\yquant@list@dequeue@i#1\etb@lst@q@end{#1}{#2}\def% + }% +}% + +\protected\gdef\yquant@list@dequeue@i#1|#2\etb@lst@q@end#3#4#5{% + \def#4{#1}% + #5#3{#2}% +} + +\protected\gdef\yquant@list@gdequeue#1#2{% + \expandafter\ifblank\expandafter{#1}{% + \let#2=\empty% + }{% + \expandafter\yquant@list@dequeue@i#1\etb@lst@q@end{#1}{#2}\gdef% + }% +} +\endgroup + +\def\ifyquant@OR#1#2{% + #1% + \expandafter\@firstoftwo% + \else% + #2% + \expandafter\expandafter\expandafter\@firstoftwo% + \else% + \expandafter\expandafter\expandafter\@secondoftwo% + \fi% + \fi% +} + +% #1 is a pgf soft path. We extract the maximum x position at the y position specified in #2 and assign it to \dimen0. +\protected\def\yquant@softpath@extractmaxxat#1#2{% + \begingroup% + \dimen0=-16000pt % + \dimen2=#2 % + \let\pgfsyssoftpath@movetotoken=\yquant@softpath@extractmaxxat@moveto% + \let\pgfsyssoftpath@linetotoken=\yquant@softpath@extractmaxxat@lineto% + \let\pgfsyssoftpath@curvetosupportatoken=\yquant@softpath@extractmaxxat@curveto% + \let\pgfsyssoftpath@rectcornertoken=\yquant@softpath@extractmaxxat@rectto% + \let\pgfsyssoftpath@closepath=\@gobbletwo% + % the specialroundtoken (undocumented) is \@gobbletwo by default. + #1% + \expandafter% + \endgroup% + \expandafter\dimen\expandafter0\expandafter=\the\dimen0 % +} + +\protected\def\yquant@softpath@extractmaxxat@update#1{% + \ifdim\dimen0<#1 % + \dimen0=#1 % + \fi% +} + +\protected\def\yquant@softpath@extractmaxxat@moveto#1#2{% + \dimen4=#1 % + \dimen6=#2 % +} + +\protected\def\yquant@softpath@extractmaxxat@lineto#1#2{% + \ifyquant@OR{\ifdim\dimen4>\dimen0 }{\ifdim#1>\dimen0 }{% + \ifdim\dimen6=\dimen2 % + \yquant@softpath@extractmaxxat@update{\dimen4}% + \else% + \ifdim\dimen6<\dimen2 % + \unless\ifdim#2<\dimen2 % + \expandafter\yquant@softpath@extractmaxxat@update\expandafter{\the\dimexpr% + \dimen4+% x0 + \dimexpr#1-\dimen4\relax*% (x1-x0) + \dimexpr\dimen2-\dimen6\relax/\dimexpr#2-\dimen6\relax% (y-y0)/(y1-y0) + \relax}% + \fi% + \else% + \unless\ifdim#2>\dimen2 % + \expandafter\yquant@softpath@extractmaxxat@update\expandafter{\the\dimexpr% + \dimen4+% x0 + \dimexpr#1-\dimen4\relax*% (x1-x0) + \dimexpr\dimen2-\dimen6\relax/\dimexpr#2-\dimen6\relax% (y-y0)/(y1-y0) + \relax}% + \fi% + \fi% + \fi% + }\relax% + \dimen4=#1 % + \dimen6=#2 % +} + +\protected\def\yquant@softpath@extractmaxxat@curveto@checkx#1#2#3{% + % \dimen11 holds our only candidate for t. Is it within the curve? + \unless\ifdim\dimen11<0pt % + \unless\ifdim\dimen11>1pt % + % it is. \dimen4: x0, #1: xa, #2: xb, #3: x1 + \begingroup% + \dimen12=\dimexpr1pt-\dimen11\relax% 1 - t + \dimen13=\dimexpr\dimen11*\dimen11/65535\relax% t^2 + \dimen14=\dimexpr\dimen12*\dimen12/65535\relax% (1 - t)^2 + \dimen255=\dimexpr\dimen13*\dimen11/65535*\dimexpr#3\relax/65535+% t^3 x1 + 3\dimen13*\dimen12/65535*\dimexpr#2\relax/65535+% t^2(1 - t) xb + \dimen14*\dimen12/65535*\dimen4/65535+% (1 - t)^3 x0 + 3\dimen11*\dimen14/65535*\dimexpr#1\relax/65535% 3t(1 - t)^2 xa + \relax% + \expandafter% + \endgroup% + \expandafter\yquant@softpath@extractmaxxat@update\expandafter{\the\dimen255}% + \fi% + \fi% +} + +\protected\def\yquant@softpath@extractmaxxat@curveto#1#2\pgfsyssoftpath@curvetosupportbtoken#3#4\pgfsyssoftpath@curvetotoken#5#6{% + % There's really no good way to do this apart from solving the Bézier curve (a third-order polynomial). Let's do it. (Yes, this is inefficient, but if someone substitutes the rectangular box of a subcircuit by a more fancy design, this is not our fault). + % Parametrized by t, the x coordinates of the curve are + % x0 + 3 (xa - x0) t + 3 (x0 - 2xa + xb) t^2 + (3xa - 3xb + x1 - x0) t^3 + % where x0 = \dimen4 (the moveto point), xa = #1, xb = #3, x1 = #5. + % Likewise for y: + % y0 = \dimen6 (the moveto point), ya = #2, yb = #4, y1 = #6. + % We first solve the third-order polynomial for t using the y value, then plug it back into the x value. + % TODO: this is accurate to approx. 3 digits. Can this be improved by reformulating Cardanos formula to involve less divisions? + \begingroup% + % We need so may dimensions that we break with TeX's convention for their use. + % for the multiplications with and divisions by dimensions, we exploit that eTeX fuses muldiv to 64 bits. Further note that each dimension has a scaling factor of 65535 for sp<->pt conversion. This is why don't factor out divisions (which would be more efficient, but not give the benefit of 64bit accuracy). + % a = 3(ya - yb) + (y1 - y0) + \dimen1=\dimexpr3\dimexpr#2-#4\relax+#6-\dimen6\relax% + \ifdim\dimen1=0pt % + % this is only a quadratic curve! + % b = 3(y0 - 2ya + yb) + \dimen3=\dimexpr3\dimexpr\dimen6-2\dimexpr#2\relax+#4\relax*65535\relax% + % c: 3(ya - y0) + \dimen5=\dimexpr3\dimexpr#2-\dimen6\relax*65535\relax% + % d: y0 - <desired y> + \dimen7=\dimexpr\dimexpr\dimen6-\dimen2\relax*65535\relax% + % check the discriminant of the equation + \dimen8=\dimexpr\dimen3*\dimen3/65535-4\dimen3*\dimen7/65535\relax% + \unless\ifdim\dimen8<0pt% + % there are two potential candidates, (-c +- sqrt(c^2 - 4b d))/2b + \pgfmathsqrt@{\the\dimen8\@gobbletwo}% + \dimen11=\dimexpr\dimexpr-\dimen5+\pgfmathresult pt\relax*65535/% + \dimexpr2\dimen3\relax\relax% + \yquant@softpath@extractmaxxat@curveto@checkx{#1}{#3}{#5}% + \dimen11=\dimexpr\dimexpr-\dimen5-\pgfmathresult pt\relax*65535/% + \dimexpr2\dimen3\relax\relax% + \yquant@softpath@extractmaxxat@curveto@checkx{#1}{#3}{#5}% + \fi% + \else% + % We will simplify by directly dividing all coefficients by a + % b = 3(y0 - 2ya + yb) + \dimen3=\dimexpr3\dimexpr\dimen6-2\dimexpr#2\relax+#4\relax*65535/\dimen1\relax% + % c: 3(ya - y0) + \dimen5=\dimexpr3\dimexpr#2-\dimen6\relax*65535/\dimen1\relax% + % d: y0 - <desired y> + \dimen7=\dimexpr\dimexpr\dimen6-\dimen2\relax*65535/\dimen1\relax% + % Note that now our a value (\dimen1) is no longer needed, it is one. + % check the discriminant of the equation + % Q = (3c - b^2)/9 + \dimen8=\dimexpr\dimexpr3\dimen5-\dimen3*\dimen3/65535\relax/9\relax% + % R = (9bc - 27d - 2b^3)/54 = bc/6 - d/2 - b^3/27 + \dimen9=\dimexpr\dimen3*\dimen5/393210-% 6*65535 + .5\dimen7-% + \dimen3*\dimen3/65535*\dimen3/1769445% 27*65535 + \relax% + % D = Q^3 + R^2 + \dimen10=\dimexpr\dimen8*\dimen8/65535*\dimen8/65535+\dimen9*\dimen9/65535\relax% + \ifdim\dimen10>0pt % + % only one real root: y_1 = S + T - b/3a + % S = cbrt(R + sqrt(Q^3 + R^2)) + % T = cbrt(R - sqrt(Q^3 + R^2)) + \pgfmathsqrt@{\the\dimen10\@gobbletwo}% + \dimen12=\dimexpr\dimen9+\pgfmathresult pt\relax% + \dimen13=\dimexpr\dimen9-\pgfmathresult pt\relax% + \ifdim\dimen12>0pt % + \pgfmathpow@{\the\dimen12\@gobbletwo}{.3333333333}% + \dimen11=\pgfmathresult pt % + \else% + \pgfmathpow@{\the\dimexpr-\dimen12\relax\@gobbletwo}{.3333333333}% + \dimen11=-\pgfmathresult pt % + \fi% + \ifdim\dimen13>0pt % + \pgfmathpow@{\the\dimen13\@gobbletwo}{.3333333333}% + \dimen11=\dimexpr\dimen11+\pgfmathresult pt-.33333333333\dimen3\relax% + \else% + \pgfmathpow@{\the\dimexpr-\dimen13\relax\@gobbletwo}{.3333333333}% + \dimen11=\dimexpr\dimen11-\pgfmathresult pt-.33333333333\dimen3\relax% + \fi% + \yquant@softpath@extractmaxxat@curveto@checkx{#1}{#3}{#5}% + \else% + \ifdim\dimen10=0pt % + % easiest case, three real roots, two of which are equal: + % y_1 = 2cbrt(R) - b/3a + % y_2, x_3 = -cbrt(R) - b/3a + \ifdim\dimen9>0pt % + \pgfmathpow@{\the\dimen9\@gobbletwo}{.3333333333}% + \dimen15=\pgfmathresult pt % + \else% + \pgfmathpow@{\the\dimexpr-\dimen9\relax\@gobbletwo}{.3333333333}% + \dimen15=-\pgfmathresult pt % + \fi% + \dimen11=\dimexpr2\dimen15-.33333333333\dimen3\relax% + \yquant@softpath@extractmaxxat@curveto@checkx{#1}{#3}{#5}% + % check the next candidate + \dimen11=\dimexpr-\dimen15-.33333333333\dimen3\relax% + \yquant@softpath@extractmaxxat@curveto@checkx{#1}{#3}{#5}% + \else% + % nastiest case, three distinct real roots which we can find only by taking a complex-valued cube root. + % p + i q = cbrt(R + i sqrt(|D|)) + \pgfmathsqrt@{\the\dimexpr-\dimen10\relax\@gobbletwo}% + \dimen10=\pgfmathresult pt % + % Let us first find the absolute value + \dimen12=\dimexpr\dimen9*\dimen9/65535+\dimen10*\dimen10/65535\relax% + \pgfmathpow@{\the\dimen12\@gobbletwo}{.1666666667}% + \dimen12=\pgfmathresult pt% + % then we need 1/3 the argument of R + i sqrt(|D|). + \pgfmathatantwo@{\the\dimen10\@gobbletwo}{\the\dimen9\@gobbletwo}% + \dimen13=.3333333333\dimexpr\pgfmathresult pt\relax% + % and then the real and imaginary parts as cosine and sine. + \pgfmathcos@{\the\dimen13\@gobbletwo}% + \dimen14=\dimexpr\pgfmathresult\dimen12\relax% + \pgfmathsin@{\the\dimen13\@gobbletwo}% + \dimen15=\dimexpr\pgfmathresult\dimen12\relax% + % Now the candidates are + % y_1 = 2p - b/3a + % y_2 = -p - sqrt(3)q - b/3a + % y_3 = -p + sqrt(3)q - b/3a + \dimen11=\dimexpr2\dimen14-.33333333333\dimen3\relax% + \yquant@softpath@extractmaxxat@curveto@checkx{#1}{#3}{#5}% + \dimen11=\dimexpr-\dimen14-1.732050808\dimen15-.33333333333\dimen3\relax% + \yquant@softpath@extractmaxxat@curveto@checkx{#1}{#3}{#5}% + \dimen11=\dimexpr-\dimen14+1.732050808\dimen15-.33333333333\dimen3\relax% + \yquant@softpath@extractmaxxat@curveto@checkx{#1}{#3}{#5}% + \fi% + \fi% + \fi% + % Now after all these calculations, \dimen0 was updated within the group. Make available outside. + \expandafter% + \endgroup% + \expandafter\dimen\expandafter0\expandafter=\the\dimen0 % + \dimen4=#5 % + \dimen6=#6 % +} + +\protected\def\yquant@softpath@extractmaxxat@rectto#1#2\pgfsyssoftpath@rectsizetoken#3#4{% + % #1: lower left x, #2: lower left y, #3: width, #4: height + % note that neither width nor height need be positive! + \ifdim#4>0pt % + \unless\ifdim#2>\dimen2 % + \unless\ifdim\dimexpr#2+#4\relax<\dimen2 % + \ifdim#3>0pt % + \yquant@softpath@extractmaxxat@update{\dimexpr#1+#3\relax}% + \else% + \yquant@softpath@extractmaxxat@update{#1}% + \fi% + \fi% + \fi% + \else% + \unless\ifdim#2<\dimen2 % + \unless\ifdim\dimexpr#2+#4\relax>\dimen2 % + \ifdim#3>0pt % + \yquant@softpath@extractmaxxat@update{\dimexpr#1+#3\relax}% + \else% + \yquant@softpath@extractmaxxat@update{#1}% + \fi% + \fi% + \fi% + \fi% }
\ No newline at end of file diff --git a/graphics/pgf/contrib/yquant/tex/yquant.sty b/graphics/pgf/contrib/yquant/tex/yquant.sty index c402c6342c..2395f67462 100644 --- a/graphics/pgf/contrib/yquant/tex/yquant.sty +++ b/graphics/pgf/contrib/yquant/tex/yquant.sty @@ -11,17 +11,18 @@ % and version 1.3c or later is part of all distributions of LaTeX version 2005/12/01 or % later. % -% This work has the LPPL maintenance status `maintained'. +% This work has the LPPL maintenance status `author-maintained'. % % The Current Maintainer of this work is Benjamin Desef. \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{yquant}[2020/04/11 v0.1.2 Yet another quantum circuit library for LaTeX] +\ProvidesPackage{yquant}[2020/06/13 v0.3 Yet another quantum circuit library for LaTeX] \RequirePackage{etoolbox}[2018/02/11] \RequirePackage{tikz}[2015/08/29] \RequirePackage{trimspaces}[2009/09/17] \usetikzlibrary{arrows.meta,decorations.pathreplacing,decorations.pathmorphing} +\newif\ifyquantdebug \input yquant-config.tex \input yquant-tools.tex \input yquant-registers.tex @@ -35,6 +36,10 @@ % usually, \\ is robust; but when using \centering, it is \let to \@centercr, which is not robust (probably because this happens only when not protecting). Fix this, so that \\ does not require \protect if a centered circuit is drawn. \robustify\@centercr +\outer\def\useyquantlanguage#1{% + \RequirePackage{yquantlanguage-#1} +} + \endinput %% %% End of file `yquant.sty'.
\ No newline at end of file diff --git a/graphics/pgf/contrib/yquant/tex/yquantlanguage-qasm.sty b/graphics/pgf/contrib/yquant/tex/yquantlanguage-qasm.sty new file mode 100644 index 0000000000..eaa848e03f --- /dev/null +++ b/graphics/pgf/contrib/yquant/tex/yquantlanguage-qasm.sty @@ -0,0 +1,681 @@ +% yquantlanguage-qasm.sty +% Extend yquant to understand qasm syntax. +% +% Copyright 2020 Benjamin Desef +% +% This work may be distributed and/or modified under the conditions of the LaTeX Project +% Public License, either version 1.3c of this license or (at your option) any later +% version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3c or later is part of all distributions of LaTeX version 2005/12/01 or +% later. +% +% This work has the LPPL maintenance status `author-maintained'. +% +% The Current Maintainer of this work is Benjamin Desef. +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{yquantlanguage-qasm}[2020/06/13 v0.3 yquant-qasm] + +\RequirePackage{yquant}[2020/06/13] + +% BEGIN_FOLD Environment definitions +\begingroup + \catcode`\{=12 \global\let\qasm@env@charbgroup={ + \catcode`\#=12 \global\let\qasm@env@charhashtag=# +\endgroup +{\catcode`\^^M=12 \protected\gdef\qasm@defwithnewline#1#{\def#1^^M}} +{\catcode`\|=0 \catcode`\\=12 |global|let|qasm@env@charbackslash=\ |gdef|qasm@env@charend{\endqasm}} +\protected\def\qasm@env@begin{% + \begingroup% + \qasm@env@setcatcodes% + \@ifnextchar[\qasm@env@begin@arg{\qasm@env@begin@arg[]}% +} + +\protected\def\qasm@env@setcatcodes{% + % make most TeX specials ordinary - not \dospecials, we want to keep spaces + \catcode`\\=12 % + \catcode`\{=12 % + \catcode`\}=12 % + \catcode`\$=12 % + \catcode`\&=12 % + \catcode`\#=12 % + \catcode`\^=12 \catcode`\^^K=12 % + \catcode`\_=12 \catcode`\^^A=12 % + \catcode`\%=12 % + \catcode`\~=12 % + \catcode`\^^M=12 % +} + +\def\qasm@env@begin@arg{% + \yquant@env@lazyfalse% + \let\yquant@env@check=\qasm@env@check% + \let\yquant@register@get@ids=\qasm@register@get@ids% + \let\yquant@attrs@remaining=\empty% we don't have attributes, but the backend requires this to be set up + \let\tikz@ensure@dollar@catcode=\relax% this check will fail, but it does not make sense in our case. Every tikz command will be read with the appropriate dollar catcode. + % provide some commands that might be used during gate construction + \let\m=\qasm@cmd@m% + \let\txt=\qasm@cmd@txt% + \let\meter=\qasm@cmd@meter% + \let\dmeter=\qasm@cmd@dmeter% + \let\dmeterwide=\qasm@cmd@dmeterwide% + \yquant@env@begin@generic\qasm% +} + +\def\qasm@env@end{% + \yquant@env@end% + \endgroup% +} + +% since the backslash is just an `other' character, we cannot leave our environment. Hence, we manually check for \endqasm and \end{qasm}. +\def\qasm@env@checkend#1#2#3#4#5{% + \ifstrequal{#1#2#3#4 }{\end}{% for us, \end is a macro so that TeX will insert another space + \ifx q#5% + \expandafter\qasm@env@checkend@plain% + \else% + \ifx\qasm@env@charbgroup#5% + \expandafter\expandafter\expandafter\qasm@env@checkend@latex% + \else% + \PackageError{yquant.sty}% + {Invalid qasm syntax: `\meaning#1'}% + {Adhere to the specs!}% + \fi% + \fi% + }{% + \PackageError{yquant.sty}% + {Invalid qasm syntax: `\meaning#1'}% + {Adhere to the specs!}% + }% +} + +\def\qasm@env@checkend@plain#1#2#3{% + \ifstrequal{#1#2#3}{asm}{% + \endgroup% we initially thought this was a normal command, so exit the group + \endqasm% + \futurelet\qasm@env@checkend@plain@delimiter\qasm@env@checkend@plain@validate% + }{% + \PackageError{yquant.sty}% + {Invalid qasm syntax: `\meaning\qasm@env@charbackslash'}% + {Adhere to the specs!}% + }% +} + +\def\qasm@env@checkend@plain@validate{% + % we already ended the qasm environment, based on the assumption that what followed was not a letter + \ifcat\qasm@env@checkend@plain@delimiter A% + % we were wrong and should never have left the environment. Now it's too late + \PackageError{yquant.sty}% + {Invalid qasm syntax: `\meaning\qasm@env@charbackslash'}% + {Adhere to the specs!}% + \fi% +} + +\begingroup + \catcode`\[=1 \catcode`\]=2 \catcode`\}=12 % we set [ just for editors that scan for matching parenthesis, though we don't need it + \gdef\qasm@env@checkend@latex#1#2#3#4#5[% + \ifstrequal[#1#2#3#4#5][qasm}][% + \endgroup% we initially thought this was a normal command, so exit the group + \end[qasm]% + ][% + \PackageError[yquant.sty]% + [Invalid qasm syntax: `\meaning\qasm@env@charbackslash']% + [Adhere to the specs!]% + ]% + ]% +\endgroup + +\protected\def\qasm@env@restorecatcodes{% + % restore standard catcodes (hopefully they were standard before entering the environment) + \catcode`\\=0 % backslash is TeX escape character + \catcode`\{=1 % left brace is begin-group character + \catcode`\}=2 % right brace is end-group character + \catcode`\$=3 % dollar sign is math shift + \catcode`\&=4 % ampersand is alignment tab + \catcode`\#=6 % hash mark is macro parameter character + \catcode`\^=7 \catcode`\^^K=7 % circumflex and uparrow are for superscripts + \catcode`\_=8 \catcode`\^^A=8 % underline and downarrow are for subscripts + \catcode`\%=14 % percent sign is comment character + \catcode`\~=\active % tilde is active +% \catcode`\^^M=5 % ascii return is end-line - not needed, is done manually +} + +\tikzaddtikzonlycommandshortcutlet\qasm\qasm@env@begin +\tikzaddtikzonlycommandshortcutlet\endqasm\qasm@env@end + +\protected\def\qasm@env@check{% + \let\next=\relax% + \ifx\yquant@env@nextchar\qasm@env@charhashtag% comment + \let\next=\qasm@env@gobblecomment% + \else% + % Here we assume standard catcodes for A + \ifcat\noexpand\yquant@env@nextchar A% letter + \let\next=\qasm@langhelper@check@name% + \else% + \ifx\yquant@env@nextchar\yquant@env@linebreak% linebreaks are no longer end-of-line characters, but have catcode 12 (other). + \let\next=\yquant@env@gobblepar% + \else% + \ifx\yquant@env@nextchar\par% + \let\next=\yquant@env@gobblepar% + \else% + \ifx\yquant@env@nextchar\qasm@env@charbackslash% backslash might end the environment + \let\next=\qasm@env@checkend% + \else% + \PackageError{yquant.sty}% + {Invalid qasm syntax: `\meaning\yquant@env@nextchar'}% + {Adhere to the specs!}% + \fi% + \fi% + \fi% + \fi% + \fi% + \next% +} + +\qasm@defwithnewline\qasm@env@gobblecomment#1{% + \yquant@env@contscan% +} + +\def\qasmimport#1{% + \ifpgfpicture% + \ifnum\yquant@env>0 % + \PackageError{yquant.sty}{You cannot use qasm circuits as subcircuits}{}% + \else% + \begingroup% + \let\yquantimport@now=\qasmimport@now% + \everyeof{\noexpand}% + \qasm@env@setcatcodes% + \yquantimportcommand{#1}% + \expandafter\expandafter\expandafter\qasm% + \expandafter\qasmimport@file% + \qasm@env@charend% + \endgroup% + \fi% + \else% + \begin{tikzpicture}% + \begingroup% + \let\yquantimport@now=\qasmimport@now% + \everyeof{\noexpand}% + \qasm@env@setcatcodes% + \yquantimportcommand{#1}% + \expandafter\expandafter\expandafter\qasm% + \expandafter\qasmimport@file% + \qasm@env@charend% + \endgroup% + \end{tikzpicture} + \fi% +} + +\def\qasmimport@now#1{% + \edef\qasmimport@file{\@@input #1 }% +} +% END_FOLD + +% BEGIN_FOLD Langhelper definitions +% Parsing command itself +\protected\qasm@defwithnewline\qasm@langhelper@check@name#1 #2{% + \lowercase{\edef\cmd{#1}}% + \unless\ifcsname qasm@lang@\cmd\endcsname% + \PackageError{yquant.sty}{Unsupported qasm command: `#1'}% + {You used a command that is unknown to qasm.}% + \fi% + \catcode`\^^M=5 % this catcode is required for scantokens, which we almost always need (because we use yquant's extensive register name facilities) + \csname qasm@lang@\cmd\endcsname#2 \qasm@end% +} + +% Defining commands that accept registers and take an optional value +% #1: name of the argument +% #2: command that is to be called +% #3: number of controls +% #4: number of targets +\protected\def\qasm@langhelper@declare@command#1#2#3#4{% + \begingroup% + \lowercase{\edef\cmd{#1}}% + % everything after the next space is just gobbled + \protected\long\csgdef{qasm@lang@\cmd}##1 ##2\qasm@end{% + \qasm@langhelper@declare@command@@fetchargs{#3}{#4}{##1}{#2}% + \yquant@env@rescan% + }% + \endgroup% +} + +\protected\def\qasm@langhelper@declare@command@@fetchargs#1#2#3#4{% + \let\targets=\empty% + \let\controls=\empty% + \count0=0 % + \count2=#1 % + \forcsvlist% + \qasm@langhelper@declare@command@@fetchargs@% + {#3}% + \unless\ifnum\count0=\numexpr\count2+#2\relax % + \PackageError{yquant.sty}{Invalid command use}% + {This gate requires #2 target\unless\ifnum#2=1 s\fi\space and #1 control\unless\ifnum#1=1 s\fi.}% + \fi% + \edef\cmd{% + \unexpanded{#4}% + {\expandafter\@gobble\controls\empty}{}% + {\expandafter\@gobble\targets\empty}% + }% + \cmd% +} + +\protected\def\qasm@langhelper@declare@command@@fetchargs@#1{% + \advance\count0 by 1 % + \unless\ifnum\count0>\count2 % + % we are at the beginning + \appto\controls{,#1}% + \else% + \appto\targets{,#1}% + \fi% +} + +% converts names to indices +\protected\def\qasm@register@get@ids#1{% + \begingroup% + \let\yquant@register@get@ids@list=\empty% + \count0=2147483647 % minimal id + \count2=0 % maximal id + \count4=0 % number of total registers + \forcsvlist\qasm@register@get@ids@outerlist{#1}% + \global\let\yquant@register@get@ids@list=\yquant@register@get@ids@list% + \xdef\yquant@register@get@ids@min{\the\count0}% + \xdef\yquant@register@get@ids@max{\the\count2}% + \xdef\yquant@register@get@ids@count{\the\count4}% + % this is very simple: if multi-registers are allowed and we have more than one, then we are in a multi-register; else not. + \ifyquant@register@get@allowmulti% + \ifnum\count4> 1% + \count6=\count0 % no way to chain the main register + \yquant@register@multi@splitparts% + \xdef\yquant@register@get@ids@list{% + \noexpand\yquant@register@multi% + {\the\count0}{\the\count2}{\the\count4}{\yquant@register@get@ids@list}% + \yquant@list@delim% + }% + \count4=1 % + \fi% + \fi% + \endgroup% +} + +\protected\def\qasm@register@get@ids@outerlist#1{% + \yquant@register@get@id\idx{#1[0]}% + \listeadd\yquant@register@get@ids@list{\idx}% + \ifnum\count0>\idx % + \count0=\idx % + \fi% + \ifnum\count2<\idx % + \count2=\idx % + \fi% + \advance\count4 by 1 % +} +% END_FOLD + +% BEGIN_FOLD Configuration +\pgfkeys{% + /yquant/operators/every s/.style={% + /yquant/operators/every box% + },% + /yquant/operators/every t/.style={% + /yquant/operators/every box% + },% + /yquant/operators/every utwo/.style={% + /yquant/operators/every box% + }, + /qasm/zero/.store in=% + \qasm@config@zero,% + /qasm/register/default qubit name/.store in=% + \qasm@config@qubit@nameonly,% + /qasm/register/default qubit name value/.store in=% + \qasm@config@qubit@namevalue% +} +\def\qasm@ket#1{\mathopen|\mathinner{#1}\rangle} +\def\qasm@config@zero{$\qasm@ket0$} +\let\qasm@config@qubit@nameonly=\qasm@ket +\def\qasm@config@qubit@namevalue#1#2{\qasm@ket{#1} = \qasm@ket{#2}} +% END_FOLD + +% BEGIN_FOLD Automagically convert names +% if ([A-z]+)(\d+) matches, replace by $1_{$2}, else let unchanged, fully expandable +\def\qasmname#1{% + \expandafter\qasmname@entry\expandafter{#1}% +} + +\def\qasmname@entry#1{% + \ifstrempty{#1}{}{% + \qasmname@checkletter#1\relax\qasmname@end{}% + }% +} + +\def\qasmname@checkletter#1#2\qasmname@end#3{% + \ifstrempty{#2}{% + % done, and we didn't get a number, so regex doesn't match (#1 is \relax) + #3% + }{% + \ifnum`#1>64 % + \ifnum`#1<123 % + \expandafter\expandafter\expandafter\@firstoftwo% + \else% + \expandafter\expandafter\expandafter\@secondoftwo% + \fi% + \else% + \expandafter\@secondoftwo% + \fi% + {% + \qasmname@checkletter#2\qasmname@end{#3#1}% + }{% + % not in A-z, move to the number part - but only if there was something matching before! + \ifstrempty{#3}{% + \qasmname@droprelax#1#2\qasmname@end% + }{% + \qasmname@checknumber#1#2\qasmname@end{#3}{}% + }% + }% + }% +} + +\def\qasmname@checknumber#1#2\qasmname@end#3#4{% + \ifstrempty{#2}{% + % done - was there a number? + \ifstrempty{#4}{% + #3% + }{% + #3_{#4}% + }% + }{% + \ifnum`#1>47 % + \ifnum`#1<58 % + \expandafter\expandafter\expandafter\@firstoftwo% + \else% + \expandafter\expandafter\expandafter\@secondoftwo% + \fi% + \else% + \expandafter\@secondoftwo% + \fi% + {% + \qasmname@checknumber#2\qasmname@end{#3}{#4#1}% + }{% + \qasmname@droprelax#3#4#1#2\qasmname@end% + }% + }% +} + +\def\qasmname@droprelax#1\relax#2\qasmname@end{% + \ifstrempty{#2}{% + #1% + }{% + \qasmname@droprelax{#1\relax}#2\qasmname@end% + }% +} +% END_FOLD + +% BEGIN_FOLD Language definitions +\protected\def\qasm@lang@qubit#1 #2\qasm@end{% + \let\yquant@lang@create@type=\yquant@register@type@q% + \def\yquant@lang@create@style{qubit}% + \qasm@lang@create#1,,,,\qasm@end% +} + +\protected\def\qasm@lang@cbit#1 #2\qasm@end{% + \let\yquant@lang@create@type=\yquant@register@type@c% + \def\yquant@lang@create@style{cbit}% + \qasm@lang@create#1,,,,\qasm@end% +} + +\protected\def\qasm@lang@create#1,#2,#3,#4,#5\qasm@end{% + \ifstrempty{#4}\relax{% + \PackageError{yquant.sty}{Invalid number of arguments}% + {Register creation in qasm expects at most three arguments.}% + }% + \ifstrequal{#5}{,,}{% + % we have a third parameter which defines the TeX name - retokenize it + \begingroup% + \qasm@env@restorecatcodes% + \everyeof{\noexpand}% + \endlinechar=-1 % + \edef\process{% + \def\noexpand\yquant@lang@attr@value{% + \scantokens{\unexpanded{#3}}% + }% + } + \expandafter% + \endgroup% + \process% + }{% + % make num subscript if name = alpha+numbers + \edef\yquant@lang@attr@value{\qasmname{#1}}% + }% + \ifx\yquant@lang@create@type\yquant@register@type@c% + \ifstrempty{#2}{% cbit has initial value? + \edef\yquant@lang@attr@value{% + $\unexpanded\expandafter{\yquant@lang@attr@value}$% + }% + }{% + \begingroup% + \qasm@env@restorecatcodes% + \everyeof{\noexpand}% + \endlinechar=-1 % + \edef\process{% + \def\noexpand\yquant@lang@attr@value{% + $\unexpanded\expandafter{\yquant@lang@attr@value} = % + \scantokens{\unexpanded{#2}}$% + }% + } + \expandafter% + \endgroup% + \process% + }% + \else% + \ifstrempty{#2}{% qubit has initial value? + \edef\yquant@lang@attr@value{% + \unexpanded\expandafter{\expandafter$% + \expandafter\qasm@config@qubit@nameonly% + \expandafter{\yquant@lang@attr@value}% + $}% + }% + }{% + \begingroup% + \qasm@env@restorecatcodes% + \everyeof{\noexpand}% + \endlinechar=-1 % + \edef\process{% + \def\noexpand\yquant@lang@attr@value{% + $\noexpand\qasm@config@qubit@namevalue% + {\unexpanded\expandafter{\yquant@lang@attr@value}}% + {\scantokens{\unexpanded{#2}}}$% + }% + } + \expandafter% + \endgroup% + \process% + }% + \fi% + \yquant@lang@create@do{#1}[1][;% + \yquant@env@rescan% +} + +\protected\def\qasm@lang@def#1,#2,'#3' #4\qasm@end{% + \lowercase{\def\cmd{#1}}% + % we need to do a couple of case distictions (it might seem crazy to look for the existence of a particular macro in #3, but this is what qasm does) + \ifstrequal{#3}{bullet}{% + \edef\process{% + \def\expandafter\noexpand\csname qasm@lang@@def@\cmd\endcsname{% + \let\noexpand\yquant@lang@attr@value=\noexpand\empty% + \noexpand\yquant@lang@@phase% + }% + }% + }{% + % re-tokenize the code + \begingroup% + \qasm@env@restorecatcodes% + \everyeof{\noexpand}% + \endlinechar=-1 % + \edef\process{% + \def\noexpand\texcode{% + \scantokens{\unexpanded{#3}}% + }% + }% + \expandafter% + \endgroup% + \process% + % now check whether the text begins with \meter, \dmeter or \dmeterwide. This is not 100% equivalent to qasm, which only checks whether these macros are present, not whether they are at the beginning. But due to our node approach, anything different from the whole content being this macro does not make sense. + \expandafter\ifyquant@firsttoken\expandafter\meter\expandafter{\texcode}{% + \edef\process{% + \def\expandafter\noexpand\csname qasm@lang@@def@\cmd\endcsname####1####2{% + \noexpand\yquant@lang@@measure% + }% + }% + }{% + \expandafter\ifyquant@firsttoken\expandafter\dmeter\expandafter{\texcode}{% + \protected@edef\process{% + \def\expandafter\noexpand\csname qasm@lang@@def@\cmd\endcsname####1####2{% + \def\noexpand\yquant@lang@attr@value{\texcode}% + \noexpand\yquant@lang@@dmeter% + }% + }% + }{% + \expandafter\ifyquant@firsttoken\expandafter\dmeterwide\expandafter{\texcode}{% + \protected@edef\process{% + \def\expandafter\noexpand\csname qasm@lang@@def@\cmd\endcsname####1####2{% + \def\noexpand\yquant@lang@attr@value{\texcode}% + \noexpand\yquant@lang@@dmeter% + }% + }% + }{% + \edef\process{% + \def\expandafter\noexpand\csname qasm@lang@@def@\cmd\endcsname{% + \yquant@draw% + {$\unexpanded\expandafter{\texcode}$}% + {/yquant/operators/every box}% + }% + }% + }% + }% + }% + }% + \eappto\process{% + % we don't use \qasm@langhelper@declare@command here, since it works globally + \protected\long\def\expandafter\noexpand\csname qasm@lang@\cmd\endcsname####1 ####2\noexpand\qasm@end{% + \qasm@langhelper@declare@command@@fetchargs{#2}1{####1}\expandafter\noexpand\csname qasm@lang@@def@\cmd\endcsname% + \noexpand\yquant@env@rescan% + }% + }% + \expandafter% + \endgroup% + \process% + \yquant@env@scan% +} + +\protected\def\qasm@lang@defbox#1,#2,#3,'#4' #5\qasm@end{% + \ifnum#2<#3 % + \PackageError{yquant.sty}{Invalid box definition}% + {You need at least as many total qubits as controls.}% + \fi% + \lowercase{\def\cmd{#1}}% + % no special cases here + \begingroup% + \qasm@env@restorecatcodes% + \everyeof{\noexpand}% + \endlinechar=-1 % + \edef\process{% + \def\noexpand\texcode{% + \scantokens{\unexpanded{#4}}% + }% + }% + \expandafter% + \endgroup% + \process% + \edef\process{% + \def\expandafter\noexpand\csname qasm@lang@@def@\cmd\endcsname{% + \noexpand\yquant@register@get@allowmultitrue% + \yquant@draw% + {$\unexpanded\expandafter{\texcode}$}% + {/yquant/operators/every box}% + }% + % we don't use \qasm@langhelper@declare@command here, since it works globally + \protected\long\def\expandafter\noexpand\csname qasm@lang@\cmd\endcsname####1 ####2\noexpand\qasm@end{% + \qasm@langhelper@declare@command@@fetchargs{#3}{\the\numexpr#2-#3\relax}{####1}\expandafter\noexpand\csname qasm@lang@@def@\cmd\endcsname% + \noexpand\yquant@env@rescan% + }% + }% + \expandafter% + \endgroup% + \process% + \yquant@env@scan% +} + +\qasm@langhelper@declare@command{measure}{\expandafter\yquant@lang@@measure\@gobbletwo}01 + +\qasm@langhelper@declare@command{H}\yquant@lang@@h01 + +\qasm@langhelper@declare@command{X}\yquant@lang@@x01 + +\qasm@langhelper@declare@command{Y}\yquant@lang@@y01 + +\qasm@langhelper@declare@command{Z}\yquant@lang@@z01 + +\qasm@langhelper@declare@command{S}\qasm@lang@@s01 +\def\qasm@lang@@s{% + \yquant@draw% + {$S$}% + {/yquant/operators/every s}% +} + +\qasm@langhelper@declare@command{T}\qasm@lang@@t01 +\def\qasm@lang@@t{% + \yquant@draw% + {$T$}% + {/yquant/operators/every t}% +} + +\qasm@langhelper@declare@command{nop}\qasm@lang@@nop01 +\def\qasm@lang@@nop#1#2#3{% + \dimdef\yquant@lang@attr@value{\yquant@config@operator@minimum@width+\yquant@config@operator@sep}% + \yquant@lang@@hspace{#3}% + % we don't use a grid-based layout, so a nop really does nothing +} + +\qasm@langhelper@declare@command{zero}\qasm@lang@@zero01 +\def\qasm@lang@@zero#1#2#3{% + \let\yquant@lang@attr@value=\qasm@config@zero% + \yquant@lang@@init{#3}% +} + +\qasm@langhelper@declare@command{discard}{\expandafter\yquant@lang@@discard\@gobbletwo}01 + +\qasm@langhelper@declare@command{slash}{\expandafter\yquant@lang@@slash\@gobbletwo}01 + +\qasm@langhelper@declare@command{dmeter}{\expandafter\yquant@lang@@dmeter\@gobbletwo}01 + +\qasm@langhelper@declare@command{cnot}\yquant@lang@@not11 + +\qasm@langhelper@declare@command{c-z}\yquant@lang@@z11 + +\qasm@langhelper@declare@command{c-x}\yquant@lang@@x11 + +\qasm@langhelper@declare@command{toffoli}\yquant@lang@@not21 + +\qasm@langhelper@declare@command{ZZ}{\expandafter\yquant@lang@@zz\@gobbletwo}02 + +\qasm@langhelper@declare@command{XX}\yquant@lang@@xx02 + +\qasm@langhelper@declare@command{swap}\yquant@lang@@swap02 + +\qasm@langhelper@declare@command{Utwo}\qasm@lang@@Utwo02 +\def\qasm@lang@@Utwo{% + \yquant@register@get@allowmultitrue% + \yquant@draw% + {$U$}% + {/yquant/operators/every utwo}% +} + +% space is a hspace _without_ wire - in priciple, we would have to discard and then re-initialize +\qasm@langhelper@declare@command{space}\qasm@lang@@nop01 +% END_FOLD + +% some commands that might be used in boxes +\def\qasm@cmd@m#1{\begin{pmatrix}#1\end{pmatrix}} +\def\qasm@cmd@txt#1{$#1$}% do not use \text{...}, but exit math mode - in this way, TikZ can still handle linebreak +\def\qasm@cmd@meter{}% +\def\qasm@cmd@dmeterwide#1#2{$#1$}% +\def\qasm@cmd@dmeter#1{$#1$}% + +\endinput
\ No newline at end of file |