diff options
author | Karl Berry <karl@freefriends.org> | 2024-01-16 21:27:36 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2024-01-16 21:27:36 +0000 |
commit | 151730c871681c42990824269ff874b253d8dc12 (patch) | |
tree | 9df40a005aa097e8242daf5d47b198c04e8bb2d9 /Master/texmf-dist/tex/latex | |
parent | 42e3678d81208a8374996edf5cc04929128f2733 (diff) |
zx-calculus (16jan24)
git-svn-id: svn://tug.org/texlive/trunk@69455 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex')
-rw-r--r-- | Master/texmf-dist/tex/latex/zx-calculus/tikzlibraryzx-calculus.code.tex | 2754 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/zx-calculus/zx-calculus.sty | 3 |
2 files changed, 2602 insertions, 155 deletions
diff --git a/Master/texmf-dist/tex/latex/zx-calculus/tikzlibraryzx-calculus.code.tex b/Master/texmf-dist/tex/latex/zx-calculus/tikzlibraryzx-calculus.code.tex index af29676b46b..c23955e6cf8 100644 --- a/Master/texmf-dist/tex/latex/zx-calculus/tikzlibraryzx-calculus.code.tex +++ b/Master/texmf-dist/tex/latex/zx-calculus/tikzlibraryzx-calculus.code.tex @@ -1,26 +1,43 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%% Version: 2021/10/22 +%%% Version: 2.0 %%% License: MIT %%% Author: Léo Colisson %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Understand why if a "fake" alias does not exists but was created before I get no error + +%% TODO: +%% - Check why this displays weirdly: +% \begin{ZX}[myBold] +% & & \zxDivider[a=div]{} \ar['>, to=Gll] \ar['>, to=Gll2] & & & \\ +% & \zxH{} \ar[to=div,<',wce] \ar[to=root,<.] & & \zxMatrix[a=Gll]'*{G^\matrixUr} & \zxMatrix[a=Gll2]'/*{G^\matrixUr} & \\ +% \zxN{} \ar[rr] & & [\zxwCol] \zxZ[a=root]{} \ar[B,rrr] \ar[to=Gll,.>] \ar[to=Gll2,.>] & & & +% \end{ZX} +% % A tikzlibrary[libraryName].code.tex is loaded automatically by tikz when using % \usetikzlibrary{libraryName}. Therefore, you should just use % \usetikzlibrary{zx} to load this library. We also provide a package to % directly load this library using \usepackage{zx}. +%%% Some random notes for myself: +%%% - \tikz@pp@name{X} outputs the name prefix + X + the name suffix, where these prefix are local prefix assigned to all node names. While they are often empty, it might not be always the case. + \RequirePackage{amssymb} % For short minus -\RequirePackage{etoolbox} +\RequirePackage{etoolbox} % \AfterEndPreamble... \RequirePackage{ifthen} % For conditions \RequirePackage{xparse} % For NewDocumentComments \RequirePackage{bm} % For bold math fonts +\RequirePackage{xstring} % For \IfInteger +\RequirePackage{varwidth} % For varwidth -\usetikzlibrary{cd,backgrounds,positioning,shapes,calc,intersections} +\usetikzlibrary{cd,backgrounds,positioning,shapes,calc,intersections,fit,decorations.pathreplacing} % Declare layers. \pgfdeclarelayer{background} % Fox boxes using "fit" to group parts of the graph. -\pgfdeclarelayer{edgelayer} % For edges that are explicitely defined "wc" -\pgfdeclarelayer{nodelayer} % For nodes... in theory, this fails for now. https://tex.stackexchange.com/questions/618823/node-on-layer-style-in-tikz-matrix-tikzcd +\pgfdeclarelayer{belownodelayer} % For nodes that always want to stay below any arrow... +\pgfdeclarelayer{edgelayer} % For nodes that always want to stay below any arrow... +\pgfdeclarelayer{nodelayer} % For nodes... in theory, this fails for now. \pgfdeclarelayer{main} +\pgfdeclarelayer{abovenodelayer} % For nodes that want to stay above others. \pgfdeclarelayer{box} % For boxes using "fit" to fake multi-column boxes \pgfdeclarelayer{labellayer} % For labels... in theory, this fails for now. https://tex.stackexchange.com/questions/618823/node-on-layer-style-in-tikz-matrix-tikzcd \pgfdeclarelayer{foreground} % For the user, if they want to put anything really above everything. @@ -33,6 +50,7 @@ \definecolor{colorZxZ}{RGB}{204,255,204} \definecolor{colorZxX}{RGB}{255,136,136} \definecolor{colorZxH}{RGB}{255,255,0} +\definecolor{colorZxMatrix}{RGB}{200,200,200} %%% Some wires (the one having an intermediate H, X, or S gate) may need some additional space for %%% specific columns. @@ -66,9 +84,12 @@ %% Default separation between rows and columns \newcommand{\zxDefaultColumnSep}{1.5mm} \newcommand{\zxDefaultRowSep}{1.5mm} +% In circuit mode, we have mostly gates, and the default setting might be too small +\newcommand{\zxDefaultColumnSepCircuit}{4mm} +\newcommand{\zxDefaultRowSepCircuit}{4mm} % To cancel the default tow separation -\newcommand{\zxZeroCol}{-\zxDefaultColumnSep} -\newcommand{\zxZeroRow}{-\zxDefaultRowSep} +\newcommand{\zxZeroCol}{-\pgfmatrixcolumnsep}%\zxDefaultColumnSep} +\newcommand{\zxZeroRow}{-\pgfmatrixrowsep}%\zxDefaultRowSep} %% When adding two lines with only empty nodes, it can create quite a large space. Use this to reduce it %% Yes, we can add multiple arguments, space will add up (see documentation pgfmatrixnextcell) \newcommand{\zxNCol}{-\zxDefaultColumnSep,.5mm} @@ -92,6 +113,9 @@ \def\zxDefaultSoftAngleO{40} \def\zxDefaultSoftAngleChevron{60} +\def\zxGroundScale{1.8} +\def\zxMeterScale{1} + % Styles for O,N,... (new bezier version) \tikzset{ /zx/args/-andL/.cd, @@ -126,6 +150,15 @@ % Scale to use when scaling 3 dots \def\zxScaleDots{.7} +% Size of the minimum width of boxes +% We need 4ex to fit most elements in height, at least with the default font (f_a is the heigher), and 1.83em to fit them in width (W is the wider). +% Since these two values are quite close, lets take the maximum (1.83em) to have a square shape +\def\zxBoxMinimumWidth{1.83em} +\def\zxBoxMinimumHeight{1.83em} +\def\zxEltMinimumWidth{1.83em} +\def\zxEltMinimumHeight{1.83em} + + % 0.4pt is default in tikz. Also used to ensure it has not been modified document wise by other libraries % (quantikz notably changes this parameter). \newcommand{\zxDefaultLineWidth}{0.4pt} @@ -168,12 +201,43 @@ % center does not exists), but then the wire will be hidden behind the node (it is a problem % mostly if you use H nodes a lot, otherwise we recommend this solution): \def\zxWireInsideIfNoIntersectionName{} -% If you prefer to start the wire on the surface of the node, do that instead... -% but be aware that the shape of the wire will be changed a lot, since we can't use anymore the -% fake anchors... You could also define a style that does that. +% If you prefer to start the wire on the surface of the node, do that instead... but it will take longer to compute. See also our ui style +% as the default styles are not meant to work in that setting. % \let\zxWireInsideIfNoIntersectionName\undefined %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Global temporary variables/dimensions +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\newsavebox{\zx@tmp@box}% + +%%%%%%%%%%%%%%%%%%%%% +%%%% Utils +%%%%%%%%%%%%%%%%%%%%% + +% by default "execute at end node" accumulate by adding at the end of the existing value, +% it can be helpful to reset completely the value, or add it before +\tikzset{ + zx execute before end node/.code={% + \def\zx@options{#1}% + \edef\zx@cmd{% + \noexpand\def\noexpand\tikz@atend@node{\expandonce{\zx@options}\expandonce{\tikz@atend@node}}% + }% + \zx@cmd% + }, + zx set execute at begin node/.code={% + \def\tikz@atbegin@node{#1}% + }, + zx set execute at end node/.code={% + \def\tikz@atend@node{#1}% + }, + zx reset execute node/.style={ + zx set execute at begin node={}, + zx set execute at end node={}, + }, +} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Adding anchors %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -257,6 +321,14 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% For readability +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\NewExpandableDocumentCommand{\zxWire}{m}{ + \arrow[r,#1] +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Tikz styles %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -421,12 +493,10 @@ %%% First intersection: we use the line between the two nodes... but it's really ugly (e.g. in o it does not make a lot of sense) \begin{pgfinterruptboundingbox}% \ifdefined\zxIntersectionLineBetweenStartEnd% - %% Not idea why, but x axis is inverted??? - \pgfpointdiff{\tikz@scan@one@point\pgf@process(#2)}{\pgfpointanchor{#1}{center}}% - \pgfpathmoveto{\pgfpoint{-\pgf@x}{\pgf@y}}% - % And now both axis are??? - \pgfpointdiff{\tikz@scan@one@point\pgf@process(#3)}{\pgfpointanchor{#1}{center}}% - \pgfpathlineto{\pgfpoint{-\pgf@x}{-\pgf@y}}% + \pgfpointdiff{\pgfpointanchor{#1}{center}}{\tikz@scan@one@point\pgf@process(#2)}% + \pgfpathmoveto{\pgfpoint{\pgf@x}{\pgf@y}}% + \pgfpointdiff{\pgfpointanchor{#1}{center}}{\tikz@scan@one@point\pgf@process(#3)}% + \pgfpathlineto{\pgfpoint{\pgf@x}{\pgf@y}}% \else% %% We use now the method used for bezier curve (at least it's what I see "experimentally") %% More precisely, we use the direction of the bezier curve to know where to start the wire. @@ -546,6 +616,12 @@ \fi% }% +\def\zxRevertToNormalSpacing{% + \thinmuskip=3.0mu\relax% + \medmuskip=4.0mu plus 2.0mu minus 4.0mu\relax% + \thickmuskip=5.0mu plus 5.0mu\relax% +} + % Styles. User should not modify "wires definition", but is free to change: % - "/zx/default style nodes/" to change completely the node style % - "/zx/user overlay nodes" to add stuff on current node style @@ -559,12 +635,58 @@ draw, -, line width=\zxDefaultLineWidth, + % This changes globally the thickness of boxes and wires, empty by default, + % mostly useful to change gates and wires at the same time + zx thickness wires style, %%% Useful shortcut (shorter lines means easy "align" of & symbols. Love M-x align in emacs btw.) ls/.style={looseness=##1}, looseness wires only/.style={% Looseness used for wires only. looseness=1.2, }, lw/.style={looseness wires only}, + bold/.style={very thick}, + non bold/.style={ + line width=\zxDefaultLineWidth, + % We need to disable bold later since "bold wires" will automatically add bold at the end + bold/.style={}, + }, + B/.style={bold}, + NB/.style={non bold}, + %% Adds a n above to denote the number of wires + Bn/.style={BnArgs={##1}{}}, + Bn/.default={n}, + boldn/.style={BnArgs={##1}{}}, + boldn/.default={n}, + Bn'/.style={Bn'Args={##1}{}}, + Bn'/.default={n}, + boldn'/.style={Bn'Args={##1}{}}, + boldn'/.default={n}, + Bn./.style={Bn.Args={##1}{}}, + Bn./.default={n}, + boldn./.style={Bn.Args={##1}{}}, + boldn./.default={n}, + Bn-/.style={Bn-Args={##1}{}}, + Bn-/.default={n}, + boldn-/.style={Bn-Args={##1}{}}, + boldn-/.default={n}, + %% For wires left to right + Bn'Args/.style 2 args={bold, "|" {rotate=65-90,anchor=center,##2}, "##1" {above,yshift=3pt,##2}}, + Bn'Args/.default={n}{}, + Bn.Args/.style 2 args={bold, "|" {rotate=65-90,anchor=center,##2}, "##1" {below,yshift=-3pt,##2}}, + Bn.Args/.default={n}{}, + %% for wires top/down (left,right) + BnArgs/.style 2 args={bold, "|" {rotate=-65,anchor=center,##2}, "##1" {left,xshift=-2pt,##2}}, + BnArgs/.default={n}{}, + Bn-Args/.style 2 args={bold, "|" {rotate=-65,anchor=center,##2}, "##1" {right,xshift=2pt,##2}}, + Bn-Args/.default={n}{}, + type'/.style={Bn'={##1}, non bold}, + type./.style={Bn.={##1}, non bold}, + type/.style={Bn={##1}, non bold}, + type-/.style={Bn-={##1}, non bold}, + % boldnPos/.style={bold, "/" {anchor=center}, "##1" {yshift=3pt}}, + % boldnPos/.default={n}{pos=50}, + % boldn.Pos/.style={bold, "/" {anchor=center}, "##1" {below,yshift=-3pt}}, + % boldn.Pos/.default={n}{pos=50}, % Use this when you are drawing lines between none nodes only (like swap gates...) in IO mode between none/.style={ looseness wires only, @@ -633,18 +755,34 @@ C@generic/.style n args={8}{ % min/max, angle1, angle2, anchor, \x or \y, \y or \x, where to move,radius code (for circle should be "radius=\n3") to path={ \pgfextra{%% <- we will use def... so need to "exit" a few seconds pgf + \zxTryFirstSubnodeThenAnchorThenNode{\tikztostart}{true ##4}{##4}% + \edef\StartPoint{\zx@result}% + % % Test if tikztostart is a point or a node, and define StartPoint accordingly. + % \ifPgfpointOrNode{\tikztostart}{% + % \def\StartPoint{\tikztostart}% + % }{% + % % For some nodes, "north" might not point to north (notably after a rotation). So we can define some anchors "true north" that actually point + % % to the north. + % % Test if "true north" etc exists: + % \ifAnchorExistsNodeSpecific{\tikztostart}{true ##4}{% + % \def\StartPoint{\tikztostart.true ##4}% + % }{% + % \def\StartPoint{\tikztostart.##4}% + % }% + % }% % Test if tikztostart is a point or a node, and define StartPoint accordingly. - \ifPgfpointOrNode{\tikztostart}{% - \def\StartPoint{\tikztostart}% - }{% - \def\StartPoint{\tikztostart.##4}% - }% - % Test if tikztostart is a point or a node, and define StartPoint accordingly. - \ifPgfpointOrNode{\tikztotarget}{% - \def\TargetPoint{\tikztotarget}% - }{% - \def\TargetPoint{\tikztotarget.##4}% - }% + \zxTryFirstSubnodeThenAnchorThenNode{\tikztotarget}{true ##4}{##4}% + \edef\TargetPoint{\zx@result}% + % \ifPgfpointOrNode{\tikztotarget}{% + % \def\TargetPoint{\tikztotarget}% + % }{% + % % Test if "true north" etc exists: + % \ifAnchorExistsNodeSpecific{\tikztotarget}{true ##4}{% + % \def\TargetPoint{\tikztotarget.true ##4}% + % }{% + % \def\TargetPoint{\tikztotarget.##4}% + % }% + % }% }% (\StartPoint) % <- the path starts at StartPoint %%% Get x coordinate of left-most point @@ -676,7 +814,7 @@ \pgfmathapproxequalto{##52}{\n1}% }% \ifpgfmathcomparison\else -- (\TargetPoint)\fi - \tikztonodes% All to path finishes with that to deal with futur nodes I think + \tikztonodes% All to path finishes with that to deal with future nodes I think } }, % At the first version, styles were defined using in=... out=... looseness=... However @@ -684,10 +822,6 @@ % too close or too far appart. However, it may still be useful, so now we define the old % styles, that you can use them using \ar[r,IO,C]. % NB: for the newest styles, we add new anchors to the nodes depending on the direction. - % I also wanted to add more complicated ways to configqure the starting point (i.e. start at the boundary - % and not behind the node), but seems like it's hard (impossible?) to do with matrices... - % The reason is that the intersection library seems to fail with matrices. - % If you know how to solve that, you can help here: https://tex.stackexchange.com/questions/619274 C/.style={C@generic={min}{90}{180+90}{west}{\x}{\y}{(\n1,\y1)}{y radius=\n3, x radius=##1*\n3}}, C/.default=1, % Like C, but rotated @@ -866,30 +1000,49 @@ bezier 4 y={\pgfkeysvalueof{/zx/args/-andL/1-}}{\pgfkeysvalueof{/zx/args/-andL/1L}}{\pgfkeysvalueof{/zx/args/-andL/2-}}{\pgfkeysvalueof{/zx/args/-andL/2L}} }% }, + %% /zx/utils/change@tikz@fake@center={\tikztostart}{fake center west}{\myoutput} will set \myoutput to be the coordinate of the fake center + %% if it exists, and of center otherwise (and if tikztostart is already a coordinate, we just set myoutput to this coordinate): % Directions: configure start/end points to "fake center *" if it exists. % If the input is not a node, it's copied to ##3 /zx/utils/change@tikz@fake@center/.code n args={3}{% % ##1: \tikztostart or \tikztotarget, % ##2: fake center north... % ##3 name of result. e.g. \tikztostart - \ifPgfpointOrNode{##1}{% - %%% Sometimes, ##1 is not 1pt,2pt but "tikz-1-2.north east". Since later we use - %%% a parsing mechanism which assumes that we have a coordinate... this is a problem. - \edef##3{##1}% - % This is a great explaination of how parsing is done in tikz: - % https://tex.stackexchange.com/a/516897/116348 - }{% This is a node, not a point: - \ifAnchorExists{##1}{##2}{% - \pgfpointanchor{##1}{##2}% - }{% - \pgfpointanchor{##1}{center}% - }% - %%% Whoo, pgfpoint only redefine pgf@x/pgf@y, but in no way it stores it!!! - %%% So can't do \pgfpoint{\pgf@x}{\pgf@y}... - %%% I needed to create my own system... see \zx@parse@coordx. - \edef##3{\the\pgf@x,\the\pgf@y}% - }% + % This sets \zx@result to the appropriate node or to center if no exists: + \zxTryFirstSubnodeThenAnchorThenNodeToCoordinate{##1}{##2}{center}% + \edef##3{\zx@result}% }, + % /zx/utils/change@tikz@fake@center/.code n args={3}{% + % % ##1: \tikztostart or \tikztotarget, + % % ##2: fake center north... + % % ##3 name of result. e.g. \tikztostart + % \ifPgfpointOrNode{##1}{% + % %%% Sometimes, ##1 is not (1pt,2pt) but "tikz-1-2.north east". Since later we use + % %%% a parsing mechanism which assumes that we have a coordinate... this is a problem. + % \edef##3{##1}% + % % This is a great explaination of how parsing is done in tikz: + % % https://tex.stackexchange.com/a/516897/116348 + % }{% This is a node, not a point: + % % "zx add anchor to node" might define per-node anchors, and they are stored in + % % a macro called like \pgf@sh@ma@tikz@f@3-2-2, so we need to read this first: + % % TODO: maybe use pp@name everywhere? (see comment beginning of this file) + % \begingroup% This group avoids pollution done by executing pgf@sh@ma@NODENAME + % \pgfutil@ifundefined{pgf@sh@ma@\tikz@pp@name{##1}}{}{% + % % We the per-node macro exists, we run it. + % \csname pgf@sh@ma@\tikz@pp@name{##1}\endcsname% + % }% + % \ifAnchorExists{##1}{##2}{% + % \pgfpointanchor{##1}{##2}% + % }{% + % \pgfpointanchor{##1}{center}% + % }% + % %%% Whoo, pgfpoint only redefine pgf@x/pgf@y, but in no way it stores it!!! + % %%% So can't do \pgfpoint{\pgf@x}{\pgf@y}... + % %%% I needed to create my own system... see \zx@parse@coordx. + % \xdef##3{\the\pgf@x,\the\pgf@y}% + % \endgroup% + % }% + % }, % Directions: configure start/end points to the intersection between % the "fake center *" if it exists and the "fake center *" of the destination. % If the input is not a node, nothing is done. @@ -971,6 +1124,119 @@ start anchor=, end anchor=, }, + % Classical wires: we make them bend + classical/.style={ + double distance=1pt, + double, + line cap=rect, + % the .5pt is half of the double distance + shorten <=.5pt+.5\pgflinewidth, + shorten >=.5pt+.5\pgflinewidth, + % to path={}, + }, + cl/.style={classical}, + connect -|/.style={ + on layer={edgelayer}, + to path={(\tikztostart) -| (\tikztotarget) \tikztonodes} + }, + --|/.style={connect -|}, + connect |-/.style={ + on layer={edgelayer}, + to path={(\tikztostart) |- (\tikztotarget) \tikztonodes} + }, + |--/.style={connect |-}, + horizontal |--/.style={ + on layer={edgelayer}, + to path={(\tikztostart |- \tikztotarget) -- (\tikztotarget) \tikztonodes} + }, + horizontal --|/.style={ + on layer={edgelayer}, + to path={(\tikztostart) -- (\tikztostart -| \tikztotarget) \tikztonodes} + }, + vertical |--/.style={ + on layer={edgelayer}, + to path={(\tikztostart) -- (\tikztostart |- \tikztotarget) \tikztonodes} + }, + vertical --|/.style={ + on layer={edgelayer}, + to path={(\tikztostart -| \tikztotarget) -- (\tikztotarget) \tikztonodes} + }, + h|--/.style={horizontal |--}, + h--|/.style={horizontal --|}, + v|--/.style={vertical |--}, + v--|/.style={vertical --|}, + % fake a wire being above by putting white stuff around + 3d above/.style={ + draw=white, + double=black, + double distance=\pgflinewidth, + very thick, + }, + %% To go to a subnode defined in a pic with from subnode=mysubnode. + start subnode/.code={% + \zxGetSubnodeOfNode{\tikzcd@ar@start}{##1}{\edef\tikzcd@ar@start{\zx@result}}{\PackageError{zx-calculus}{In "start subnode=##1", \zx@error}}% + }, + % start subnode/.code={% + % \edef\zx@tmp{zx@alias@\zxCurrentDiagram @\tikzcd@ar@start}% + % % First, rewrite \tikzcd@ar@start so that it equals the name of the current node without alias + % \ifcsname \zx@tmp\endcsname% There exists an alias + % \edef\zx@tmp@alias{(alias \zx@tmp) }% Mostly for the error message + % \edef\tikzcd@ar@start{\csname zx@alias@\zxCurrentDiagram @\tikzcd@ar@start\endcsname}% + % \else% + % \edef\zx@tmp@alias{(no alias) }% Mostly for the error message + % \fi + % % First, we check if there is a node with this name on this node. If not, we will try with the parent node + % \@ifundefined{pgf@sh@ns@\tikzcd@ar@start ##1}{% + % % The current node has no such subnode name: let's start its parent. + % \@ifundefined{\tikzcd@ar@start -zxOriginalRow}{% + % % There is no original coordinate: error + % \PackageError{zx-calculus}{In "start subnode=##1", the subnode ##1 of node \tikzcd@ar@start \zx@tmp@alias does not exist.}{}% + % }{% + % % There is an original coordinate: we try to see if the original node admits a subnode. + % \edef\zx@tmp@originalRow{\csname \tikzcd@ar@start-zxOriginalRow\endcsname}% + % \edef\zx@tmp@originalCol{\csname \tikzcd@ar@start-zxOriginalCol\endcsname}% + % \@ifundefined{pgf@sh@ns@\zxCurrentDiagram-\zx@tmp@originalRow-\zx@tmp@originalCol ##1}{% + % \PackageError{zx-calculus}{In "start subnode=##1", the subnode ##1 of aliased node \tikzcd@ar@start{} \zx@tmp@alias does not exist (even in the parent node at coordinate \zx@tmp@originalRow - \zx@tmp@originalCol).}{}% + % }{% + % \edef\tikzcd@ar@start{\zxCurrentDiagram-\zx@tmp@originalRow-\zx@tmp@originalCol ##1}%% + % }% + % }% + % }{% There exists a subnode in the current name + % \edef\tikzcd@ar@start{\tikzcd@ar@start ##1}%% + % }% + % }, + end subnode/.code={% The edef is needed, or it always go into the first loop and might give errors later + \zxGetSubnodeOfNode{\tikzcd@ar@target}{##1}{\edef\tikzcd@ar@target{\zx@result}}{\PackageError{zx-calculus}{In "end subnode=##1", \zx@error}}% + }, + % end subnode/.code={% The edef is needed, or it always go into the first loop and might give errors later + % \edef\zx@tmp{zx@alias@\zxCurrentDiagram @\tikzcd@ar@target}% + % % First, rewrite \tikzcd@ar@target so that it equals the name of the current node without alias + % \ifcsname \zx@tmp\endcsname% There exists an alias + % \edef\zx@tmp@alias{(alias \zx@tmp) }% Mostly for the error message + % \edef\tikzcd@ar@target{\csname zx@alias@\zxCurrentDiagram @\tikzcd@ar@target\endcsname}% + % \else% + % \edef\zx@tmp@alias{(no alias) }% Mostly for the error message + % \fi + % % First, we check if there is a node with this name on this node. If not, we will try with the parent node + % \@ifundefined{pgf@sh@ns@\tikzcd@ar@target ##1}{% + % % The current node has no such subnode name: let's start its parent. + % \@ifundefined{\tikzcd@ar@target -zxOriginalRow}{% + % % There is no original coordinate: error + % \PackageError{zx-calculus}{In "end subnode=##1", the subnode ##1 of node \tikzcd@ar@target{} \zx@tmp@alias does not exist.}{}% + % }{% + % % There is an original coordinate: we try to see if the original node admits a subnode. + % \edef\zx@tmp@originalRow{\csname \tikzcd@ar@target-zxOriginalRow\endcsname}% + % \edef\zx@tmp@originalCol{\csname \tikzcd@ar@target-zxOriginalCol\endcsname}% + % \@ifundefined{pgf@sh@ns@\zxCurrentDiagram-\zx@tmp@originalRow-\zx@tmp@originalCol ##1}{% + % \PackageError{zx-calculus}{In "end subnode=##1", the subnode ##1 of aliased node \tikzcd@ar@target{} \zx@tmp@alias does not exist (even in the parent node at coordinate \zx@tmp@originalRow - \zx@tmp@originalCol).}{}% + % }{% + % \edef\tikzcd@ar@target{\zxCurrentDiagram-\zx@tmp@originalRow-\zx@tmp@originalCol ##1}%% + % }% + % }% + % }{% There exists a subnode in the current name + % \edef\tikzcd@ar@target{\tikzcd@ar@target ##1}%% + % }% + % }, %% Forced versions are versions which do not nicely fallback to center if shape does not %% have "fake center XXX". This is used mostly for wires based on in/out (our function b. %% Not sure how to have a code which always fallback to center if shape does not. @@ -1258,9 +1524,11 @@ N.-/.default=\zxDefaultSoftAngleN, }, % No line but vdots/dots in between. - 3 vdots/.style={draw=none, "\makebox[0pt][r]{##1}\scalebox{\zxScaleDots}{$\cvdotsCenterMathline$}" anchor=center}, + 3 vdots/.style={draw=none, "\makebox[0pt][r]{\footnotesize\smash{##1\,}}\scalebox{\zxScaleDots}{$\cvdotsCenterMathline$}" {anchor=center,zxNormalFont}}, 3 vdots/.default={}, - 3 dots/.style={draw=none, "\makebox[0pt][r]{##1}\scalebox{\zxScaleDots}{$\chdots$}" anchor=center}, + 3 vdotsr/.style={draw=none, "\scalebox{\zxScaleDots}{$\cvdotsCenterMathline$}\makebox[0pt][l]{\footnotesize\smash{\,##1}}" {anchor=center,zxNormalFont}}, + 3 vdotsr/.default={}, + 3 dots/.style={draw=none, "\makebox[0pt][r]{\footnotesize\smash{##1}}\scalebox{\zxScaleDots}{$\chdots$}" {anchor=center,zxNormalFont}}, 3 dots/.default={}, % Add a Hadmard/Z/X (no phase) in the middle of the line. Practical to add small nodes without creating % a new column/row. However, make sure the corresponding row/column is larger, using &[\zxHCol] @@ -1272,7 +1540,19 @@ Z/.default={}, X/.style={"" {zxNoPhaseSmallX,anchor=center,##1}}, X/.default={}, - % Arrow will go out from the center of the shape instead of from the border. Useful + % Sometimes, it might be handy to specify an anchor only if no anchor was set before, notably when using "post arrow style if end node" (see + % for instance the Divider). + end anchor if not set/.code={% + \ifx\tikzcd@endanchor\pgfutil@empty% If there is no anchor, we can set ours: + \pgfkeysalso{/tikz/commutative diagrams/end anchor={##1}}% + \fi% + }, + start anchor if not set/.code={% + \ifx\tikzcd@startanchor\pgfutil@empty% If there is no anchor, we can set ours: + \pgfkeysalso{/tikz/commutative diagrams/start anchor=##1}% + \fi% + }, + % Arrow will go out from the center of the shape instead of from the border. Useful e.g. % when connecting nodes with different shapes, it will give back a symetric connection. wire centered/.style={ on layer=edgelayer, @@ -1295,14 +1575,90 @@ /tikz/commutative diagrams/end anchor=, }, }, + %% Will be loaded in tikzcd options directly. + /zx/styles/rounded style preload/.style={ + content fixed baseline/.style={ + /zx/user overlay nodes/.style={ + zxShort/.append style={content fixed baseline}, + % fixed baseline gives poor result in fractions, so we disable it here + zxSpecificFrac/.append style={content vertically centered}, + }, + }, + content fixed baseline also frac/.style={ + /zx/user overlay nodes/.style={ + zxShort/.append style={content fixed baseline}, + }, + }, + content vertically centered/.style={ + /zx/user overlay nodes/.style={ + zxShort/.append style={content vertically centered} + }, + }, + /zx/styles/rounded style common nodes and ZX, + }, + % These styles make sense both in "ZX" options and in nodes options. + /zx/styles/rounded style common nodes and ZX/.style={ + small minus/.code={ + \def\zxMinus{\zxShortMinus}% + \def\zxMinusInShort{\zxShortMinus}% + }, + big minus/.code={ + \def\zxMinus{-}% + \def\zxMinusInShort{-}% + }, + }, /zx/styles/rounded style/.style={ + /zx/styles/rounded style common nodes and ZX, %% Can be redefined by user % Style for empty nodes + zxSpacingInsideNodes/.style={ + execute at begin node={\thinmuskip=0mu\medmuskip=0mu\thickmuskip=0mu}, % Reduce space around +/-... + }, + zxNormalSpacing/.style={ + execute at begin node={\thinmuskip=3.0mu\medmuskip=4.0mu plus 2.0mu minus 4.0mu\thickmuskip=5.0mu plus 5.0mu}, % + }, + %% Normalize fonts to avoid different rendering when document has a different font shape. + zxNormalFont/.style={ + font={\fontsize{10}{12}\selectfont}, + }, + zxTinyFont/.style={ + font={\fontsize{6}{6}\selectfont}, + }, + zxTinyFontAndSpacing/.style={ + zxSpacingInsideNodes, + zxTinyFont, + }, + % Practical styles to either vertically center the content, or fix the position of the baseline. + content fixed baseline/.style={ + text height=1.5mm,%5.4pt,%1.5mm,%.45em, + text depth=0.1mm,%1.8pt,%0.1mm,%.15em, + }, + % Style for empty nodes + content vertically centered/.style={ + text height=, + text depth=, + }, + bold/.style={very thick}, + B/.style={bold}, + non bold/.style={% + line width=\zxDefaultLineWidth, + }, + NB/.style={non bold}, + %% To set bold all wires connected to the current wire + bold wires/.style={ + post arrow style if end node={B}, + post arrow style if start node={B}, + }, + wires bold/.style={bold wires},% backward compatible + Bw/.style={wires bold}, + BBw/.style={bold, wires bold,}, zxAllNodes/.style={ shape=rectangle, % Otherwise nodes are asymetrical rectangle, which is not practical in our case. Gives notably anchor "center" which is really centered compared to asymatrical rectangles anchor=center, % Center cells line width=\zxDefaultLineWidth, - execute at begin node={\thinmuskip=0mu\medmuskip=0mu\thickmuskip=0mu}, % Reduce space around +/-... + % Normalize the font size (avoids different rendering of dots...) + zxSpacingInsideNodes, + zxNormalFont, }, % Use this to denote an empty diagram zxEmptyDiagram/.style={ @@ -1408,6 +1764,9 @@ stylePhaseInLabel, fill=red!20!white }, + % Some styles should be applied only on frac + zxSpecificFrac/.style={ + }, %%%%%%%%%%% Style defined depending on above ones. Feel free to redefine. zxNoPhaseZ/.style={zxNoPhase,fill=colorZxZ}, zxNoPhaseX/.style={zxNoPhase,fill=colorZxX}, @@ -1523,23 +1882,23 @@ }% }% }, - pil/.style={phase in label=##1}, + pil/.style={phase in label={##1}}, phase in label below/.style={ phase in label={label position=below,##1} }, - pilb/.style={phase in label below=##1}, + pilb/.style={phase in label below={##1}}, phase in label above/.style={ phase in label={label position=above,##1} }, - pila/.style={phase in label above=##1}, + pila/.style={phase in label above={##1}}, phase in label right/.style={ phase in label={label position=right,##1} }, - pilr/.style={phase in label right=##1}, + pilr/.style={phase in label right={##1}}, phase in label left/.style={ phase in label={label position=left,##1} }, - pill/.style={phase in label left=##1}, + pill/.style={phase in label left={##1}}, %%% Was supposed to automatically find the good style depending on content... Can't find how to do. % Styles zxLong{X/Z} zxNoPhase{X/Z} are automatically selected by \zxZ4{...} and \zxX4{...} commands % and zxShort is selected for fractions only like in \zxFracZ-{\pi}{4} @@ -1609,11 +1968,11 @@ %% These take 6 arguments: additional style, sign (string "-" for minus, nothing for "+", %% otherwise inserted directly), above fraction (no parens), below fraction (no parens), above fraction (parens), below fraction (parens). zxFracZ6/.style n args={6}{ - add@Phase@Spider@Frac={zxNoPhaseZ}{zxShortZ}{stylePhaseInLabelZ}{##2}{##3}{##4}{##5}{##6}, + add@Phase@Spider@Frac={zxNoPhaseZ}{zxShortZ,zxSpecificFrac}{stylePhaseInLabelZ}{##2}{##3}{##4}{##5}{##6}, /zx/post preparation labels, /zx/user post preparation labels, ##1, - zx@Execute@Very@End@Frac={zxNoPhaseZ}{zxShortZ}{stylePhaseInLabelZ}{##2}{##3}{##4}{##5}{##6}, + zx@Execute@Very@End@Frac={zxNoPhaseZ}{zxShortZ,zxSpecificFrac}{stylePhaseInLabelZ}{##2}{##3}{##4}{##5}{##6}, }, zxFracX6/.style n args={6}{ add@Phase@Spider@Frac={zxNoPhaseX}{zxShortX}{stylePhaseInLabelX}{##2}{##3}{##4}{##5}{##6}, @@ -1638,9 +1997,16 @@ /zx/default style nodes/.style={ /zx/styles/rounded style }, + % Will be executed in tikzcd options. Useful to define a "global" option specific to a given style. + /zx/default style nodes preload/.style={ + /zx/styles/rounded style preload, + }, % User can put here any additional property /zx/user overlay nodes/.style={ }, + % User can put here any global ZX options + /zx/user overlay/.style={ + }, % Any additional property that needs to be loaded after add@Phase@Spider (by script, not by user). /zx/post preparation labels/.style={ }, @@ -1653,6 +2019,34 @@ % User can add stuff in this style to improve wire styles /zx/user overlay wires/.style={ }, + /zx/every arrow pre/.style={% + /utils/exec={% We provide a way to disable the default behavior + \ifdefined\zxDisablePreRunStart\else% + %%% If it is an alias, we replace it with the original node: + \ifcsname zx@alias@\zxCurrentDiagram @\tikzcd@ar@start\endcsname% This is an alias: let's rename it to the original node + \edef\tikzcd@ar@start{\csname zx@alias@\zxCurrentDiagram @\tikzcd@ar@start\endcsname}% + \fi% + %%% Load the arrow style set by the start node: + \edef\zx@tmp{% Make sure that the style exists and load it: + /zx/internals/preRunIfIamStartNode-\tikzcd@ar@start/.append style={},% + /zx/internals/preRunIfIamStartNode-\tikzcd@ar@start,% + }% + \pgfkeysalsofrom{\zx@tmp}% + \fi% + %%% Load the arrow style set by the end node: + \ifdefined\zxDisablePreRunEnd\else% + %%% If it is an alias, we replace it with the original node: + \ifcsname zx@alias@\zxCurrentDiagram @\tikzcd@ar@target\endcsname% This is an alias: let's rename it to the original node + \edef\tikzcd@ar@target{\csname zx@alias@\zxCurrentDiagram @\tikzcd@ar@target\endcsname}% + \fi% + \edef\zx@tmp{% Make sure that the style exists and load it: + /zx/internals/preRunIfIamEndNode-\tikzcd@ar@target/.append style={},% + /zx/internals/preRunIfIamEndNode-\tikzcd@ar@target,% + }% + \pgfkeysalsofrom{\zx@tmp}% + \fi% + }% + },% /zx/defaultEnv/.style={ %tiny depends on the size of the font... which we want to keep consistent look column sep=\zxDefaultColumnSep, @@ -1678,18 +2072,87 @@ 1-row diagram/.style={}, %% usage: math baseline=wantedBaseline, where you have somewhere \zxX[a=wantedBaseline]{\beta} math baseline/.style={baseline={([yshift=-axis_height]##1)}}, + % math baseline row/.style={math baseline=\zxCurrentDiagram-##1-1}, + math baseline row/.code={% + \IfInteger{##1}{% + \pgfkeysalso{math baseline=\zxCurrentDiagram-##1-1}% + }{% + % We have a non-integer value like 1.5 that means between both values. + % We first extract these values: + \pgfmathtruncatemacro{\zx@first@index}{floor(##1)}% + \pgfmathtruncatemacro{\zx@second@index}{floor(##1)+1}% + \pgfmathsetmacro{\zx@percent}{##1-floor(##1)}% + \pgfkeysalso{math baseline/.expanded={$(\noexpand\zxCurrentDiagram-\zx@first@index-1)!\zx@percent!(\noexpand\zxCurrentDiagram-\zx@second@index-1)$}}% + }% + }, + math baseline row/.default={1}, + mbr/.style={math baseline row={##1}}, + mbr/.default={1}, + thick lines/.style={ + /tikz/zx thickness wires style/.style={thick, line cap=round}, + }, + % In circuits (mostly gates), the default separation feels too small, so we adjust it here + circuit/.style={ + column sep=\zxDefaultColumnSepCircuit, + row sep=\zxDefaultRowSepCircuit, + }, + bold/.style={ + /tikz/commutative diagrams/arrows={B}, + /zx/user overlay nodes/.style={ + zxSpiders/.append style={BBw}, + zxH/.append style={BBw}, + }, + /utils/exec={\def\zxEnableAllElementsBold{}}, + }, + B/.style={ + bold + }, + debug mode/.code={\def\zxDebugMode{}}, + no debug mode/.code={\let\zxDebugMode\undefined}, + amp/.style={ + ampersand replacement=\&, + }, %%% Include a diagram in another diagram. use diagram/.style 2 args={ execute at end picture={ - \node[fit=##2,inner sep=0pt,yshift=-axis_height]{\zxUseDiagram{##1}}; + \node[fit=##2,anchor=center,inner sep=0pt,yshift=-axis_height]{\zxUseDiagram{##1}}; + } + }, + %%% Include a diagram in another diagram. + use diagram advanced/.style n args={3}{ + execute at end picture={ + \node[fit=##2,anchor=center,inner sep=0pt,yshift=-axis_height,##3]{\zxUseDiagram{##1}}; } }, % Load (thanks ".search also") our own style /tikz/every node/.style={% + % Otherwise, the empty nodes take some space… and create weird bugs. But I don't know how to add empties + % https://tex.stackexchange.com/questions/675958/tikz-empty-nodes-with-different-style-coordinate + % ==> solved, see "empty" + nodes={ + zxAllNodes, + inner sep=0pt, + outer sep=0mm, + }, % For quickly adding alias, and displaying this alias in debug mode. a/.code={% \pgfkeysalso{% - alias=####1,% + % alias=####1,% + % alias seems to fail with nodes in pic… let's try another method. See also: + % https://tex.stackexchange.com/questions/679647/tikz-pic-alias-to-internal-node + %% TODO: according to the above discussion, this append after command should be done after the + %% add anchor to node is finished, as an alias is basically copying all the macros of the initial node, + %% so you want to do it once its finished (in particular to preserve the anchors). But maybe + %% append after command is already avoiding that issue. In any case it would be good to make it more + %% robust (\tikzlastnode might change, so defining my own \tikzlastnode might help, use link instead + %% of copy alias to be sure the anchors are preserved etc...) + append after command={\pgfextra{% + \pgfnodealias{####1}{\tikzlastnode}% + % There is no way anymore to remember the link between the alias and the non-alias. Let's rembember it + % manually + \expandafter\xdef\csname zx@alias@\zxCurrentDiagram @####1\endcsname{\tikzlastnode}% + }% + }, }% %% name path won't work with alias... So let's create two name path ^^ %% https://tex.stackexchange.com/questions/619622 @@ -1706,14 +2169,181 @@ }% \fi% }, + % runs a=foo only if we are at the origin (0,0) of a zxExecuteAtRegionRelative + a if origin/.code={% + \ifnum \the\pgfmatrixcurrentrow=\zxOriginalRow\relax% + \ifnum \the\pgfmatrixcurrentcolumn=\zxOriginalCol\relax% + \pgfkeysalso{a={####1}}% + \fi% + \fi% + }, + %% To allow blocks + block/.style={ + zx set execute at begin node={\begin{varwidth}{50cm}}, % 50cm is just hardcoded to be long enough so that any content fits inside + zx set execute at end node={\end{varwidth}}, + }, + %% This allows nodes to specify styles for the arrows that start/end from them. + %% This style will be loaded last as otherwise we don't know yet the starting and ending point. + %% See how we apply it on the arrow side using "every arrow post" + post arrow style if start node/.style={% + append after command={% This expects a path, but we want to write a code without any path: + \pgfextra% this syntax with \endpgfextra completely turns off the tikz syntax, that might be safer than \pgfextra{...}. + \def\zx@arguments{####1}% + \edef\zx@tmp{% + /zx/internals/postRunIfIamStartNode-\tikzlastnode/.append style={\unexpanded\expandafter{\zx@arguments}},% + }% https://tex.stackexchange.com/questions/47905/how-to-globally-tikzset-styles + {% + \globaldefs=1\relax% + \pgfkeysalsofrom{\zx@tmp}% + }% + \endpgfextra% + },% + }, + post arrow style if end node/.style={% + append after command={% This expects a path, but we want to write a code without any path: + \pgfextra% this syntax with \endpgfextra completely turns off the tikz syntax, that might be safer than \pgfextra{...}. + \def\zx@arguments{####1}% + \edef\zx@tmp{% + /zx/internals/postRunIfIamEndNode-\tikzlastnode/.append style={\unexpanded\expandafter{\zx@arguments}},% + }% https://tex.stackexchange.com/questions/47905/how-to-globally-tikzset-styles + {% + \globaldefs=1\relax% + \pgfkeysalsofrom{\zx@tmp}% + }% + \endpgfextra% + },% + },% + pre arrow style if start node/.style={% + append after command={% This expects a path, but we want to write a code without any path: + \pgfextra% this syntax with \endpgfextra completely turns off the tikz syntax, that might be safer than \pgfextra{...}. + \def\zx@arguments{####1}% + \edef\zx@tmp{% + /zx/internals/preRunIfIamStartNode-\tikzlastnode/.append style={\unexpanded\expandafter{\zx@arguments}},% + }% https://tex.stackexchange.com/questions/47905/how-to-globally-tikzset-styles + {% + \globaldefs=1\relax% + \pgfkeysalsofrom{\zx@tmp}% + }% + \endpgfextra% + },% + }, + pre arrow style if end node/.style={% + append after command={% This expects a path, but we want to write a code without any path: + \pgfextra% this syntax with \endpgfextra completely turns off the tikz syntax, that might be safer than \pgfextra{...}. + \def\zx@arguments{####1}% + \edef\zx@tmp{% + /zx/internals/preRunIfIamEndNode-\tikzlastnode/.append style={\unexpanded\expandafter{\zx@arguments}},% + }% https://tex.stackexchange.com/questions/47905/how-to-globally-tikzset-styles + {% + \globaldefs=1\relax% + \pgfkeysalsofrom{\zx@tmp}% + }% + \endpgfextra% + },% + }, /zx/default style nodes, /zx/user overlay nodes, }, every arrow/.style={% /zx/wires definition, /zx/default style wires, + /zx/every arrow pre, /zx/user overlay wires, + %%% Load the post arrow style at the end: + %% See also every arrow pre if you want to run it before the style of the arrow + /tikz/commutative diagrams/every arrow post/.append style={% + /utils/exec={% We provide a way to disable the default behavior + \ifdefined\zxDisablePostRunStart\else% + %%% If it is an alias, we replace it with the original node: + \ifcsname zx@alias@\zxCurrentDiagram @\tikzcd@ar@start\endcsname% This is an alias: let's rename it to the original node + \edef\tikzcd@ar@start{\csname zx@alias@\zxCurrentDiagram @\tikzcd@ar@start\endcsname}% + \fi% + %%% Load the arrow style set by the start node: + \edef\zx@tmp{% Make sure that the style exists and load it: + /zx/internals/postRunIfIamStartNode-\tikzcd@ar@start/.append style={},% + /zx/internals/postRunIfIamStartNode-\tikzcd@ar@start,% + }% + \pgfkeysalsofrom{\zx@tmp}% + \fi% + %%% Load the arrow style set by the end node: + \ifdefined\zxDisablePostRunEnd\else% + %%% If it is an alias, we replace it with the original node: + \ifcsname zx@alias@\zxCurrentDiagram @\tikzcd@ar@target\endcsname% This is an alias: let's rename it to the original node + \edef\tikzcd@ar@target{\csname zx@alias@\zxCurrentDiagram @\tikzcd@ar@target\endcsname}% + \fi% + \edef\zx@tmp{% Make sure that the style exists and load it: + /zx/internals/postRunIfIamEndNode-\tikzcd@ar@target/.append style={},% + /zx/internals/postRunIfIamEndNode-\tikzcd@ar@target,% + }% + \pgfkeysalsofrom{\zx@tmp}% + \fi% + }% + },% + disable post run start/.code={\def\zxDisablePostRunStart{}}, + disable post run end/.code={\def\zxDisablePostRunEnd{}}, + disable post run/.style={ + disable post run start, + disable post run end, + }, + enable post run start/.code={\let\zxDisablePostRunStart\undefined}, + enable post run end/.code={\let\zxDisablePostRunEnd\undefined}, + enable post run/.style={ + enable post run start, + enable post run end, + }, + enable post run, + }, + %% We add an empty coordinate in every node. This has multiple advantages: first this avoids errors about + %% single ampersand when the matrix does not start with None, and it also avoids using \zxN{} everywhere. + %% However, we can't just use 'nodes in empty cells=true' or it will add nodes that might take some space: + % https://tex.stackexchange.com/questions/696622/tikz-allow-the-style-syntax-in-execute-at-empty-cells?noredirect=1#comment1729912_696622 + % /tikz/replace empty cell with/.code={% + % \def\tikz@at@emptycell{% + % \tikz@lib@matrix@start@cell + % #1% + % \tikz@lib@matrix@end@cell + % }% + % }, + % /tikz/replace empty cell with={% + % /tikz/execute at empty cell/.code={% + % \expandafter\def\expandafter\tikz@at@emptycell\expandafter + % {\tikz@at@emptycell\expandafter\expandafter\expandafter + % \tikz@lib@matrix@start@cell##1\tikz@lib@matrix@end@cell}}, + % This is started at the beginning of non-empty cells + every matrix/.append style={ + /tikz/execute at end cell={% + \ifcsname zxExecuteAtCell-\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname% + \csname zxExecuteAtCell-\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname% + \fi% + },% + },% + /tikz/execute at empty cell={% + % We want to check if there is a + \ifcsname zxExecuteAtCell-\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname% + % I wanted to allow a syntax with |[]| but first it seems to be quite hard (as it depends on the number of extensions): + % %% https://tex.stackexchange.com/questions/696622/tikz-allow-the-style-syntax-in-execute-at-empty-cells + % but anyway I guess it is better to turn everything into nodes so that \zxX{} can be inserted outside of a matrix. + \csname zxExecuteAtCell-\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname% + \else% + \ifdefined\zxCustomExecuteAtEmptyCell\zxCustomExecuteAtEmptyCell% + \else% + \coordinate[ + % yshift=axis_height, % We already do that elsewhere + name=\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn];% + \fi% + \fi% }, + % When an arrow is present, it will not detect it as an empty cell… The below code tries to avoid this issue, but actually has another issue as it removes all nodes without text in it, like |[circle, draw, inner sep=3pt]|, so + % we disable it for now. + %% https://tex.stackexchange.com/questions/675958/tikz-empty-nodes-with-different-style-coordinate/675971#675971 + % /tikz/every node/.append code={% + % \tikz@addoption{% + % \ifdim\wd\pgfnodeparttextbox=0pt + % \pgfutil@ifx\tikz@shape\tikz@coordinate@text{}{% + % \def\tikz@shape{coordinate}% + % \pgftransformyshift{axis_height}}% + % \fi}% + % }, %%% To be used only in \zx{...} environment. %%% Exemple: phase in content/.style={ @@ -1723,38 +2353,49 @@ }, phase in label/.style={ /zx/post preparation labels/.append style={ - phase in label=##1, + phase in label={##1}, } }, phase in label above/.style={ /zx/post preparation labels/.append style={ - phase in label above=##1, + phase in label above={##1}, } }, phase in label below/.style={ /zx/post preparation labels/.append style={ - phase in label below=##1, + phase in label below={##1}, } }, phase in label right/.style={ /zx/post preparation labels/.append style={ - phase in label right=##1, + phase in label right={##1}, } }, phase in label left/.style={ /zx/post preparation labels/.append style={ - phase in label left=##1, + phase in label left={##1}, } }, % for "Phase In Label" - pil/.style={phase in label=##1}, - pilb/.style={phase in label below=##1}, - pila/.style={phase in label above=##1}, - pilr/.style={phase in label right=##1}, - pill/.style={phase in label left=##1}, + pil/.style={phase in label={##1}}, + pilb/.style={phase in label below={##1}}, + pila/.style={phase in label above={##1}}, + pilr/.style={phase in label right={##1}}, + pill/.style={phase in label left={##1}}, + % Load the global options style-specific + /zx/default style nodes preload, + /zx/user overlay, }, } +% % Call \zxSetStyleWhenEndingHere{your, zx, style} when you want to configure a particular style when arriving on a particular cell +% \NewExpandableDocumentCommand{\zxSetStyleWhenEndingHere}{m}{% +% \pgfkeys{ +% /zx/internals/postRunIfIamEndNode-\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn/.append code={#1}, +% /zx/internals/postRunIfIamEndNode-\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn +% }% +% } + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Helper functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1782,7 +2423,8 @@ \def\node@on@layer{\aftergroup\node@@on@layer} %%% Declare a symbol for a short minus (useful in fractions) -\DeclareMathSymbol{\zxMinus}{\mathbin}{AMSa}{"39}% Requires amssymb +\DeclareMathSymbol{\zxShortMinus}{\mathbin}{AMSa}{"39}% Requires amssymb. This version should not be redefined by the user to obtain a normal minus (or "small minus" won't work anymore) +\def\zxMinus{\zxShortMinus} %%% Checks if a function is a point or a node. %%% Not sure if best solution (needed to dig into source of TeX), but can't find anything better in manual @@ -1797,7 +2439,7 @@ % shape anchor name if exists if not. Works, while doing \pgfutil@ifundefined{pgf@anchor@\shapenode{}@#2} fails. % I guess it has to do with the way macro are expanded... -\def\ifAnchorExistsFromShape#1#2#3#4{ +\def\ifAnchorExistsFromShape#1#2#3#4{% \pgfutil@ifundefined{pgf@anchor@#1@#2}{% #4% }{% @@ -1809,10 +2451,135 @@ \def\ifAnchorExists#1#2#3#4{% %%% First we extract the shape of the node: \edef\pgf@node@name{#1}% - \edef\shapenode{\csname pgf@sh@ns@\pgf@node@name\endcsname}% - \ifAnchorExistsFromShape{\shapenode}{#2}{#3}{#4} + \edef\shapenode{\csname pgf@sh@ns@\pgf@node@name\endcsname}% e.g. rectangle + \ifAnchorExistsFromShape{\shapenode}{#2}{#3}{#4}% +} + +%% If we manually add an anchor to a note, \ifAnchorExists will not work. Hence this improved version: +%% Note that #3 and #4 will run in a group +\def\ifAnchorExistsNodeSpecific#1#2#3#4{% + \let\zxcalculus@tmp\undefined% This is used to run #3 and #4 outside the group + {% group not to pollute stuff with pgf@sh@ma + \ifcsname pgf@sh@ma@#1\endcsname% per node config + \csname pgf@sh@ma@#1\endcsname% we run the config + \fi% + %%% First we extract the shape of the node: + \edef\pgf@node@name{#1}% + \edef\shapenode{\csname pgf@sh@ns@\pgf@node@name\endcsname}% e.g. rectangle + \ifAnchorExistsFromShape{\shapenode}{#2}{\gdef\zxcalculus@tmp{}}{}% + }% + \ifdefined\zxcalculus@tmp% + #3% + \else% + #4% + \fi% +} + +% \zxGetSubnodeOfNode{\tikzcd@ar@start}{mysubnode}{True branch}{False branch} will set \zx@result to the corresponding node if it exits and run True branch +% otherwise it will run False branch, where \zx@error will contain more details on why it failed. This function also try to use \zxOriginalRow to find +% a possible parent. +\def\zxGetSubnodeOfNode#1#2#3#4{% + \edef\zx@result{#1}% + % First we try to see if there is an alias: + \edef\zx@tmp{zx@alias@\zxCurrentDiagram @#1}% + % First, rewrite #1 so that it equals the name of the current node without alias + \ifcsname \zx@tmp\endcsname% There exists an alias + \edef\zx@tmp@alias{(alias \zx@tmp) }% Mostly for the error message + \edef\zx@result{\csname zx@alias@\zxCurrentDiagram @#1\endcsname}% + \else% + \edef\zx@tmp@alias{(no alias) }% Mostly for the error message + \fi + % First, we check if there is a node with this name on this node. If not, we will try with the parent node + \@ifundefined{pgf@sh@ns@\zx@result #2}{% + % The current node has no such subnode name: let's start its parent. + \@ifundefined{\zx@result -zxOriginalRow}{% + % There is no original coordinate: error + \def\zx@error{the subnode #2 of node \zx@result \zx@tmp@alias does not exist.}% + #4% + }{% + % There is an original coordinate: we try to see if the original node admits a subnode. + \edef\zx@tmp@originalRow{\csname \zx@result -zxOriginalRow\endcsname}% + \edef\zx@tmp@originalCol{\csname \zx@result -zxOriginalCol\endcsname}% + \@ifundefined{pgf@sh@ns@\zxCurrentDiagram-\zx@tmp@originalRow-\zx@tmp@originalCol #2}{% + \def\zx@error{the subnode #2 of aliased node \zx@result {} \zx@tmp@alias does not exist (even in the parent node at coordinate \zx@tmp@originalRow - \zx@tmp@originalCol).}% + #4% + }{% + \edef\zx@result{\zxCurrentDiagram-\zx@tmp@originalRow-\zx@tmp@originalCol #2}%% + #3% + }% + }% + }{% There exists a subnode in the current name + \edef\zx@result{\zx@result #2}%% + #3% + }% } +% \zxTryFirstSubnodeThenAnchorThenNode{\tikztostart}{true north}{north} will set \zx@result to the corresponding subnode if it exists, otherwise the true north anchor, +% otherwise the north anchor +\def\zxTryFirstSubnodeThenAnchorThenNode#1#2#3{% + \zxGetSubnodeOfNode{#1}{#2}{% + % The subnode exists: we forward \zx@result + }{% + % No submode exists: + % Test if it is a point or a node, and define StartPoint accordingly. + \ifPgfpointOrNode{#1}{% + \edef\zx@result{#1}% + }{% This is a node + % "zx add anchor to node" might define per-node anchors, and they are stored in + % a macro called like \pgf@sh@ma@tikz@f@3-2-2, so we need to read this first: + % TODO: maybe use pp@name everywhere? (see comment beginning of this file) + \begingroup% This group avoids pollution done by executing pgf@sh@ma@NODENAME + \pgfutil@ifundefined{pgf@sh@ma@\tikz@pp@name{##1}}{}{% + % We the per-node macro exists, we run it. + \csname pgf@sh@ma@\tikz@pp@name{##1}\endcsname% + }% + % Test if "true north" etc exists: + \ifAnchorExistsNodeSpecific{#1}{#2}{% + \xdef\zx@result{#1.#2}% + }{% + \xdef\zx@result{#1.#3}% + }% + \endgroup% + }% + } +} + +% Like zxTryFirstSubnodeThenAnchorThenNodeToCoordinate but \zx@result will contain coordinates of the final point. +\def\zxTryFirstSubnodeThenAnchorThenNodeToCoordinate#1#2#3{% + \zxGetSubnodeOfNode{#1}{#2}{% + % The subnode exists: we forward \zx@result after turning it in a coordinate + \ifPgfpointOrNode{\zx@result}{}{% + % this is a node, so we take the center + \pgfpointanchor{\zx@result}{#3}% + \def\zx@result{\the\pgf@x,\the\pgf@y}% + }% + }{% + % No submode exists: + % Test if it is a point or a node, and define StartPoint accordingly. + \ifPgfpointOrNode{#1}{% + \edef\zx@result{#1}% + }{% This is a node + % "zx add anchor to node" might define per-node anchors, and they are stored in + % a macro called like \pgf@sh@ma@tikz@f@3-2-2, so we need to read this first: + % TODO: maybe use pp@name everywhere? (see comment beginning of this file) + \begingroup% This group avoids pollution done by executing pgf@sh@ma@NODENAME + \pgfutil@ifundefined{pgf@sh@ma@\tikz@pp@name{#1}}{}{% + % We the per-node macro exists, we run it. + \csname pgf@sh@ma@\tikz@pp@name{#1}\endcsname% + }% + % Test if "true north" etc exists: + \ifAnchorExistsNodeSpecific{#1}{#2}{% + \pgfpointanchor{#1}{#2}% + }{% + \pgfpointanchor{#1}{#3}% + }% + \xdef\zx@result{\the\pgf@x,\the\pgf@y}% + \endgroup% + }% + } +} + + %%% Create different kinds of dots... %% https://tex.stackexchange.com/questions/617959 %% https://tex.stackexchange.com/questions/528774/excess-vertical-space-in-vdots/528775#528775 @@ -1842,44 +2609,1599 @@ \DeclareRobustCommand{\cvdots}{\cvdotsCenterMathline} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Practical functions to define multirow/multicols gates +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% We provide a generic set of functions to execute code later +% (in a later cell, or at the end of the picture), together with +% a way to pass any kind of variables for later + +\NewExpandableDocumentCommand{\zxCoordinateMain}{O{}m}{ + \coordinate[#1,#2](\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn); +} + +\NewExpandableDocumentCommand{\zxCoordinateSubnode}{O{}m}{ + \coordinate[#1](\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn#2); +} + +\NewDocumentCommand{\zxMainNodeAlreadySet}{m}{\def\zxMainNodeAlreadySetMacro{}} + +\tikzset{ + % When using the \node{}; instead of |[foo]| bar structure, no name is given to the node. This is fixed with + % this: + zx main node/.code={% + % If we are in a matrix, we can give it the name of the current column + \ifdefined\zxCurrentDiagram% + % Useful to temporarily disable this, for instance useful in matrix to change the size of a single cell. + \ifdefined\zxMainNodeAlreadySetMacro\else% + \tikzset{name=\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn}% + \fi% + \fi% + }, + zx at origin/.style={at={(0,0)}}, + zx subnode/.code={ + % we forbid empty subnode as otherwise it will be equivalent to "zx main node" due to the way we handle subnodes for now. + % and most of the time when it is empty it just means that the user does not want to set a subnode. + % test if empty: https://tex.stackexchange.com/questions/53068/how-to-check-if-a-macro-value-is-empty-or-will-not-create-text-with-plain-tex-co + \if\relax\detokenize{#1}\relax% + \message{Empty subnode name}% + \else% + \ifdefined\zxCurrentDiagram% + \ifdefined\zxOriginalRow% + \tikzset{alias=\zxCurrentDiagram-\zxOriginalRow-\zxOriginalCol#1}% + % \tikzset{name=\zxCurrentDiagram-\zxOriginalRow-\zxOriginalCol#1}% + \else% + \tikzset{alias=\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn#1}% + % \tikzset{name=\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn#1}% + \fi% + \else% + \message{Warning: you or outside of a tikzcd environment, so you will not be able to implement subnodes for now. But you might want to try to define zxCurrentDiagram, pgfmatrixcurrentrow and pgfmatrixcurrentcolumn yourself, you might be lucky.}% + \fi% + \fi% + }, + zx independent subnode/.style={ + name=\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn#1,% + }, + zx apply style/.code={\tikzset{/tikz/.cd,#1}}, + zx style from variable/.style={% + zx apply style/.expand twice={\csname zxGateMultiVariable-\zxCurrentDiagram-\zxOriginalRow-\zxOriginalCol-#1\endcsname}, + % \expandafter\scantokens\expandafter{\zx@tmp}% + % \zx@tmp% + }, +} + +\NewExpandableDocumentCommand{\zxGetNameAbsoluteNode}{mm}{% + \tikzcdmatrixname-#1-#2% +}% + +%% here you can use previously defined variables if you created them +%% will only work inside environments where \zxOriginalRow/Col are defined +\NewExpandableDocumentCommand{\zxGetNameRelativeNode}{mm}{% + \ifdefined\zxOriginalRow% + \zxCurrentDiagram-\the\numexpr\zxOriginalRow+#1\relax-\the\numexpr\zxOriginalCol+#2\relax% + \else% + \zxCurrentDiagram-\the\numexpr\the\pgfmatrixcurrentrow+#1\relax-\the\numexpr\the\pgfmatrixcurrentcolumn+#2\relax% + \fi% +}% + +\NewExpandableDocumentCommand{\zxGetNameRelativeNodeStartOne}{mm}{% + \zxGetNameRelativeNode{\numexpr #1-1\relax}{\numexpr #2-1\relax}% +}% + + +% \zxExecuteAtEndPicture{\node{A};} will execute \node{A}; at the end of the picture (or rather after the draw of the matrix, but before the draw of the wires) +\NewExpandableDocumentCommand{\zxExecuteAtEndPicture}{m}{% + \edef\zx@tmp@args{\unexpanded{#1}}% + \edef\zx@tmp{\noexpand\pgfutil@g@addto@macro\noexpand\tikzcd@before@paths@hook{% + % We give random value just to avoid having errors when it is not yet defined, but you should always specify the + % to and from. + \noexpand\def\noexpand\tikzcd@currentrow{In execute at end picture}% + \noexpand\def\noexpand\tikzcd@currentcolumn{In execute at end picture}% + \noexpand\def\noexpand\tikzcd@lineno{In zxArrowNow}% + \noexpand\def\noexpand\zxOriginalRow{\the\pgfmatrixcurrentrow}% + \noexpand\def\noexpand\zxOriginalCol{\the\pgfmatrixcurrentcolumn}% + \expandonce\zx@tmp@args% + }% + }% + \zx@tmp% +} + +\NewExpandableDocumentCommand{\zxExecuteWhenDrawingArrows}{m}{% + \edef\zx@tmp@args{\unexpanded{#1}}% + \edef\zx@tmp{\noexpand\pgfutil@g@addto@macro\noexpand\tikzcd@savedpaths{% + \noexpand\def\noexpand\zxOriginalRow{\the\pgfmatrixcurrentrow}% + \noexpand\def\noexpand\zxOriginalCol{\the\pgfmatrixcurrentcolumn}% + \expandonce\zx@tmp@args% + }% + }% + \zx@tmp% +} + +% like \ar but run it directly. Usually run it in \zxExecuteWhenDrawingArrows. +\NewExpandableDocumentCommand{\zxArrowNow}{O{}m}{% + \path[/tikz/commutative diagrams/.cd,every arrow,#1] (\tikzcd@ar@start\tikzcd@startanchor) to (\tikzcd@ar@target\tikzcd@endanchor);% +} + +% \zxExecuteAtCellAbsolute{1}{2}{\node{A};} will execute at cell row 1, column 2 the code \node{A};, just make sure that nothing is already present in that cell +\NewExpandableDocumentCommand{\zxExecuteAtCellAbsolute}{mmm}{% + \def\zx@tmp@args{#3}% + \edef\zx@tmp{zxExecuteAtCell-\zxCurrentDiagram-#1-#2}% + % Make sure to define the macro as we can't add to it if it does not exist + \ifcsname \zx@tmp\endcsname\else\expandafter\gdef\csname \zx@tmp\endcsname{}\fi% + \edef\zx@tmp@code{ + \noexpand\expandafter\noexpand\pgfutil@g@addto@macro\noexpand\csname zxExecuteAtCell-\zxCurrentDiagram-#1-#2\noexpand\endcsname{% + \noexpand\def\noexpand\zxOriginalRow{\the\pgfmatrixcurrentrow}% + \noexpand\def\noexpand\zxOriginalCol{\the\pgfmatrixcurrentcolumn}% + % To allow to recover \zxOriginalRow from the name of the node later, we create a new macro "namenode-zxOriginalRow" with the value of the original row, same for Col + \noexpand\expandafter\noexpand\xdef\noexpand\csname\zxCurrentDiagram-\noexpand\the\noexpand\pgfmatrixcurrentrow-\noexpand\the\noexpand\pgfmatrixcurrentcolumn-zxOriginalRow\endcsname{\noexpand\zxOriginalRow}% + \noexpand\expandafter\noexpand\xdef\noexpand\csname\zxCurrentDiagram-\noexpand\the\noexpand\pgfmatrixcurrentrow-\noexpand\the\noexpand\pgfmatrixcurrentcolumn-zxOriginalCol\endcsname{\noexpand\zxOriginalCol}% + \expandonce{\zx@tmp@args}% + }% + }% + \zx@tmp@code% +} + +% TODO: maybe use instead /tikz/every cell={n}{m} that is always run even if the cell is not empty? Or execute at begin cell that applies to non-empty cells? +% \zxExecuteAtCellRelative{1}{2}{\node{A};} will execute at cell current row + 1, current column + 2 the code \node{A};, just make sure that nothing is already present in that cell +\NewExpandableDocumentCommand{\zxExecuteAtCellRelative}{mmm}{% + \def\zx@tmp@args{#3}% + % putting this in the csname directly does not work + \edef\zx@tmp{zxExecuteAtCell-\zxCurrentDiagram-\the\numexpr \the\pgfmatrixcurrentrow+#1\relax-\the\numexpr\the\pgfmatrixcurrentcolumn+#2\relax}% + % \noexpand\expandafter\noexpand\gdef\noexpand\csname \zx@tmp\noexpand\endcsname{% + % Make sure to define the macro as we can't add to it if it does not exist + \ifcsname \zx@tmp\endcsname\else\expandafter\gdef\csname \zx@tmp\endcsname{}\fi% + \edef\zx@tmp@code{% + \noexpand\expandafter\noexpand\pgfutil@g@addto@macro\noexpand\csname \zx@tmp\noexpand\endcsname{% + \noexpand\def\noexpand\zxOriginalRow{\the\pgfmatrixcurrentrow}% + \noexpand\def\noexpand\zxOriginalCol{\the\pgfmatrixcurrentcolumn}% + % To allow to recover \zxOriginalRow from the name of the node later, we create a new macro "namenode-zxOriginalRow" with the value of the original row, same for Col + \noexpand\expandafter\noexpand\xdef\noexpand\csname\zxCurrentDiagram-\noexpand\the\noexpand\pgfmatrixcurrentrow-\noexpand\the\noexpand\pgfmatrixcurrentcolumn-zxOriginalRow\endcsname{\noexpand\zxOriginalRow}% + \noexpand\expandafter\noexpand\xdef\noexpand\csname\zxCurrentDiagram-\noexpand\the\noexpand\pgfmatrixcurrentrow-\noexpand\the\noexpand\pgfmatrixcurrentcolumn-zxOriginalCol\endcsname{\noexpand\zxOriginalCol}% + \expandonce{\zx@tmp@args}% + }% + }% + \zx@tmp@code% + % \edef\zx@tmp{}% + % \expandafter\gdef\csname \zx@tmp\endcsname{#3}% +} + +% \zxExecuteAtRegionRelative{n}{m}{code} will execute code \zxExecuteAtCellRelative in all cells starting from the current cell (note that +% it will have no effect on the (0,0) cell since this cell is not empty and already processed +\NewExpandableDocumentCommand{\zxExecuteAtRegionRelative}{mmm}{% + \pgfmathparse{#1-1}% + \foreach \i in {0,...,\pgfmathresult}{% + \pgfmathparse{#2-1}% + \foreach \j in {0,...,\pgfmathresult}{% + \zxExecuteAtCellRelative{\i}{\j}{#3}% + }% + }% +} + +\NewExpandableDocumentCommand{\zxExecuteAtRegionRelativeAndOrigin}{mmm}{% + % Just a trick or the tikz matrix parser will not understand that we are in a node if we start with def: + \coordinate(zx@Useless); + \def\zxOriginalRow{\the\pgfmatrixcurrentrow}% + \def\zxOriginalCol{\the\pgfmatrixcurrentcolumn}% + %#3% + \zxExecuteAtRegionRelative{#1}{#2}{#3}% +} + +%%% +%%% Variables that you can create in one cell and reuse later +%% + +% \zxGateMultiNewVariable{my variable}{value} +\NewExpandableDocumentCommand{\zxSetVariable}{mm}{% + % For some reasons it fails inside the csname directly + \edef\zx@tmp{zxGateMultiVariable-\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn-#1}% + \expandafter\gdef\csname \zx@tmp\endcsname{% + #2% + }% +} + +\NewExpandableDocumentCommand{\zxSetVariableExpandOnce}{mm}{% + % For some reasons it fails inside the csname directly + \edef\zx@tmp{zxGateMultiVariable-\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn-#1}% + \expandafter\xdef\csname \zx@tmp\endcsname{% + \expandonce{#2}% + }% +} + +\NewExpandableDocumentCommand{\zxSetVariableExpand}{mm}{% + % For some reasons it fails inside the csname directly + \edef\zx@tmp{zxGateMultiVariable-\zxCurrentDiagram-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn-#1}% + \expandafter\xdef\csname \zx@tmp\endcsname{% + #2% + }% +} + +\def\zxGetVariable#1{% + \csname zxGateMultiVariable-\zxCurrentDiagram-\zxOriginalRow-\zxOriginalCol-#1\endcsname% +} + +\def\zxShowVariable#1{% + \expandafter\show\csname zxGateMultiVariable-\zxCurrentDiagram-\zxOriginalRow-\zxOriginalCol-#1\endcsname% +} + +%%%%%%%%%% +%%% Slices +%%%%%%%%%% + +\tikzset{ + /zx/slice label style/.style={ + align=center,pos=0, black, anchor=south,zxTinyFont, + }, + /zx/slice line style/.style={ + dashed, red, thick, + }, +} + +\NewDocumentCommand{\zxSlice}{O{}O{}O{.5}m}{% + \zxExecuteAtEndPicture{ + \draw[/zx/slice line style,#2] + (\tikzcdmatrixname.north-|{$(\zxCurrentDiagram-1-\zxOriginalCol)!#3!(\zxCurrentDiagram-1-\the\numexpr\zxOriginalCol+1\relax)$}) + -- (\tikzcdmatrixname.south-|{$(\zxCurrentDiagram-1-\zxOriginalCol)!#3!(\zxCurrentDiagram-1-\the\numexpr\zxOriginalCol+1\relax)$}) + node[rotated/.style={anchor=south west,yshift=-.5ex,rotate=##1},rotated/.default=30, /zx/slice label style,#1]{#4}; + } +} + +\tikzset{ + /zx/vertical slice label style/.style={ + align=center,pos=1, black, anchor=west,zxTinyFont, + }, + /zx/vertical slice line style/.style={ + dashed, red, thick, + }, +} + +\NewDocumentCommand{\zxVSlice}{O{}O{}m}{% + \zxExecuteAtEndPicture{% + % \pgfextra{ + \pgfpointanchor{\tikzcdmatrixname}{west}% + \pgfgetlastxy{\zx@tmp@west@x}{\zx@tmp@west@y}% + \pgfpointanchor{\tikzcdmatrixname}{east}% + \pgfgetlastxy{\zx@tmp@east@x}{\zx@tmp@east@y}% + \pgfmathparse{\zx@tmp@east@x-\zx@tmp@west@x}% + \edef\zxMatrixWidth{\pgfmathresult pt}% + % }% + \draw[/zx/vertical slice line style,#2] + (\tikzcdmatrixname.west|-{$(\zxCurrentDiagram-\zxOriginalRow-1)!.5!(\zxCurrentDiagram-\the\numexpr\zxOriginalRow+1\relax-1)$}) + -- (\tikzcdmatrixname.east|-{$(\zxCurrentDiagram-\zxOriginalRow-1)!.5!(\zxCurrentDiagram-\the\numexpr\zxOriginalRow+1\relax-1)$}) + node[rotated/.style={anchor=south west,yshift=-.5ex,rotate=####1},rotated/.default=30, /zx/vertical slice label style,#1]{#3}; + } +} + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Practical functions to nest diagrams %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \NewDocumentCommand{\zxSaveDiagram}{mO{}m}{ \newsavebox{#1}% - \savebox{#1}{\begin{ZX}[ampersand replacement=\&,#2]#3\end{ZX}}% + \savebox{#1}{% + \ifdefined\tikz@library@external@loaded% Library external is loaded... + \tikzset{external/optimize=false}% Otherwise, tikz will try to optimize and replace the box with a text + \fi% + \begin{ZX}[#2]#3\end{ZX} + }% } \NewDocumentCommand{\zxUseDiagram}{m}{ \usebox{#1}% } +%%%%%%%%%%%%%%%%%%%%% +%%% Main environments +%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%% Practical macros to automatically choose appropriate style and arrows -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% /!\ Warning: you should add {} at the end of all macros (except arrows)! -% Not using that may work for now, but it may break later... -% TODO: define them only in \zx environment. +% Quantikz has a bug which adds space automatically. +% https://tex.stackexchange.com/questions/618330 +% Fixing that by copying the original (unpatched) functions, and reusing them later. +% Warning: you must load this package **before** quantikz otherwise the fix will not work. +\let\tikzcd@@originalCopyZx\tikzcd@ +\let\endtikzcd@originalCopyZx\endtikzcd -% % Example: \leftManyDots{n} -% Useful to put on the left of a node like "n \vdots", linked to the next node. Example: \leftManyDots{n}. -% First optional argument is scale of text, second is scale of =. -\NewExpandableDocumentCommand{\leftManyDots}{O{1}O{\zxScaleDots}m}{% - |[zxNone+,inner xsep=0pt]| \scalebox{#1}{$#3$\,}\makebox[0pt][l]{\scalebox{#2}{$\cvdotsCenterMathline$}} \ar[r,-N.,start anchor=north east] \ar[r,-N',start anchor=south east] \pgfmatrixnextcell[\zxwCol]% +%%%%% Main environment \begin{ZX}...\end{ZX}. However, we call it ZXNoExt because when using +%%%%% externalization (to save compilation time), we need to wrap it around a figure. +\NewDocumentEnvironment{ZXNoExt}{O{}}{% + \bgroup% + % Do not change the font size here or it will change axis_height... Use \fontsize{10}{12}\selectfont + % when drawing some texts instead. + % Add a switch in case someone really wants the current tikzcd version: + \ifdefined\doNotPatchQuantikz% Do not patch tikzcd. + \else% Restore locally original tikzcd. + \let\tikzcd@\tikzcd@@originalCopyZx% + \let\endtikzcd\endtikzcd@originalCopyZx% + \fi% + % we need to reset this or it will get data from previous pictures + \global\let\tikzcd@before@paths@hook\pgfutil@empty% + \global\let\tikzcd@savedpaths\pgfutil@empty% + \ifdefined\zxDoNotPatchArrows% Do not patch arrows (we need sometimes "every arrow post") + \else% Copy/pasted from https://github.com/astoff/tikz-cd/blob/master/tikzlibrarycd.code.tex, just added "every arrow post". + %% I'm not sure which method is more resilient: patchcmd is likely to fail on minor library update, + %% while redefining \tikzcd@ar@new might not apply some major library upgrades (note that we redefine it + %% only locally). Since I don't know what is better, I do both depending on this macro + \ifdefined\zxUsePatchCmdToPatchArrows% + \patchcmd\tikzcd@ar@new% + {\path[/tikz/commutative diagrams/.cd,every arrow,#1]}% + {\path[/tikz/commutative diagrams/.cd,every arrow,#1,every arrow post]}% + {}% + {}% + \else% + \def\tikzcd@ar@new[##1]{% Make sure to turn #1 into ##1 as the command is nested + \pgfutil@g@addto@macro\tikzcd@savedpaths{% + \path[/tikz/commutative diagrams/.cd,every arrow,##1,every arrow post]%<--- we added every arrow post + (\tikzcd@ar@start\tikzcd@startanchor) to (\tikzcd@ar@target\tikzcd@endanchor); }}% + \fi% + \fi% + % We make sure "every arrow post" exists: + \tikzset{% + /tikz/commutative diagrams/every arrow post/.append style={}% + }% + \pgfsetlayers{background,belownodelayer,edgelayer,nodelayer,main,abovenodelayer,box,labellayer,foreground}% Layers are defined locally to avoid to disturb other drawings + %% Provide a way to reference the current diagram. This way it is for instance possible to do + %% \ar[from=Zbotright, to=\zxCurrentDiagram-1-1] + %% For this to work, you should not modify the name of the matrix. + %% Old way + % \def\zxCurrentDiagram{tikz@f@\the\tikz@fig@count}%Does not exists yet... Hopefully it's updated soon enough + % Should be equivalent but might even work if we change the name of the matrix, hopefully we only use it at the right time. + % Also, when drawing the lines, we are not anymore inside the tikzmatrix, but tikzcdmatrixname contains the name of the matrix instead: + \def\zxCurrentDiagram{\ifdefined\tikzmatrixname\tikzmatrixname\else\tikzcdmatrixname\fi}% + % \pgfutil@g@addto@macro\tikzcd@before@paths@hook{% + % \def\zxCurrentDiagram{\tikzcdmatrixname}% + % }% + % the problem with \tikzcdmatrixname is that it is only defined at the end, once the matrix is built + % We provide a way to get the current matrix name: + \begin{tikzcd}[% + /zx/defaultEnv,% + #1]% + }{\end{tikzcd}% + \global\let\tikzcd@before@paths@hook\pgfutil@empty% + \global\let\tikzcd@savedpaths\pgfutil@empty% + \egroup} + +% https://tex.stackexchange.com/a/619983/116348 +\ExplSyntaxOn +%%%%% Shortcut macro \zxNoExt{...} equivalent to \begin{ZX}...\end{ZX} +%%%%% We will create an alias \zx, but when we use externalization we +%%%%% wrap it around a figure. +\NewDocumentCommand{\zxNoExt}{O{}+m}{% Warning, expl syntax removes space. + \tl_rescan:nn { \char_set_catcode_active:N \& } { \begin{ZXNoExt}[#1] #2 \end{ZXNoExt} } } +\ExplSyntaxOff -% Useful to link two nodes and put a vdots in between. -\NewExpandableDocumentCommand{\middleManyDots}{}{% - \ar[r,3 vdots] \ar[o',r] \ar[o.,r]% +%% Version to use when using externalize (it wraps it around a +\NewDocumentCommand{\zxExt}{O{}O{}O{}+m}{% Warning, expl syntax removes space. + \begin{tikzpicture}[baseline=(zxlibrarymainnode.base),#2]% + \node(zxlibrarymainnode)[inner sep=0pt,outer sep=0pt,#3]{\zxNoExt[#1]{#4}};% + \end{tikzpicture}% } -% Like \leftManyDots but on the right. Do *not* create a new node, like in |[zxShortZ]| \alpha \rightManyDots{m} -\NewExpandableDocumentCommand{\rightManyDots}{O{1}O{\zxScaleDots}m}{% - \ar[r,N'-,end anchor=north west] \ar[r,N.-,end anchor=south west] \pgfmatrixnextcell[\zxwCol] |[zxNone+,inner xsep=0pt]| \makebox[0pt][r]{\scalebox{#2}{$\cvdotsCenterMathline$}}\scalebox{#1}{\,$#3$} +\NewDocumentEnvironment{ZXExt}{O{}O{}O{}b}{% + \zxExt[#1][#2][#2]{#4}% +}{}% + +\NewDocumentEnvironment{ZX}{O{}O{}O{}b}{% + \zx[#1][#2][#3]{#4}% +}{} + +% The external library is not compatible with tikzcd directly. +% So if: +% \zx@external@mode is enabled, we wrap the figure into another figure to be compatible with tikz externalize +% otherwise, we check if the external library is loaded, and disable it temporarily. +\NewDocumentCommand\zx{O{}O{}O{}+m}{% + {% + % Suffix for pictures made only with zx when using the external library + \ifdefined\tikz@library@external@loaded% Library external is loaded... + \ifdefined\zx@external@suffix% + \tikzappendtofigurename{\zx@external@suffix}% + \fi% + \fi% + \ifdefined\zx@external@mode% + % We wrap everything around figures and enable tikz external (useful when many figures + % are not compatible with external): + \ifthenelse{\equal{\zx@external@mode}{wrapForceExt}}{% + {\tikzexternalenable\zxExt[#1][#2][#3]{#4}}% + }{% + \ifthenelse{\equal{\zx@external@mode}{wrap}}{% We wrap everything around figures to be compatible with external + \zxExt[#1][#2][#3]{#4}% + }{% We don't wrap anything inside figures, so we lose external compatibility. + \ifthenelse{\equal{\zx@external@mode}{noWrapNoExt}}{% + % We disable the tikz external library temporarily (tikzcd is not compatible with it) + \ifdefined\tikz@library@external@loaded% Library external is loaded... + \tikzexternaldisable% + \message{WARNING: you chose to disable temporarily the tikz external library.}% + \fi% + }{}% + \zxNoExt[#1]{#4}% + }% + }% + \else% Mode auto enabled + {% If the tikz library is loaded: + \ifdefined\tikz@library@external@loaded% Library external is loaded... + \zxExt[#1][#2][#3]{#4}% + \else% + \zxNoExt[#1]{#4}% + \fi% + }% + \fi% + }% +} + +%% By default, the error displayed when compiling using "external" +%% is not meaningful and does not stop if a picture already exists. +%% https://tex.stackexchange.com/questions/633100/stop-at-error-meaningfull-errors-with-shell-escape-and-tikz-externalize/633121#633121 +%% See also this bug, that shows that if you have an error and compile twice, the error disappears, but the old file is used instead. +%% https://github.com/pgf-tikz/pgf/issues/1137 +\NewDocumentCommand\zxConfigureExternalSystemCall{O{}}{ + %% Code inspired by https://github.com/pgf-tikz/pgf/blob/a7b45b35e99af11bf7156aa3697b897b98870e5b/tex/generic/pgf/frontendlayer/tikz/libraries/tikzexternalshared.code.tex#L277 + \expandafter\def\csname zx@driver@pgfsys-luatex.def\endcsname{% + \pgfkeyssetvalue{/tikz/external/system call}{% + lualatex \tikzexternalcheckshellescape #1 -jobname "\image" "\texsource"% + }% + }% + \expandafter\def\csname zx@driver@pgfsys-pdftex.def\endcsname{% + \pgfutil@IfUndefined{directlua}{% + \pgfkeyssetvalue{/tikz/external/system call}{% + pdflatex \tikzexternalcheckshellescape #1 -jobname "\image" "\texsource"% + }% + }{% + \pgfkeyssetvalue{/tikz/external/system call}{% + lualatex \tikzexternalcheckshellescape #1 -jobname "\image" "\texsource"% + }% + }% + }% + \expandafter\def\csname zx@driver@pgfsys-xetex.def\endcsname{% + \pgfkeyssetvalue{/tikz/external/system call}{% + xelatex \tikzexternalcheckshellescape #1 -jobname "\image" "\texsource"% + }% + }% + \expandafter\def\csname zx@driver@pgfsys-dvips.def\endcsname{% + \pgfkeyssetvalue{/tikz/external/system call}{% + latex \tikzexternalcheckshellescape #1 -jobname "\image" "\texsource" % + && dvips -o "\image".ps "\image".dvi % + }% + }% + % Auto-select a suitable default value fo 'system call': + \pgfutil@ifundefined{tikzexternal@driver@\pgfsysdriver}{% + % fallback. We do not know the driver here. + \csname zx@driver@pgfsys-pdftex.def\endcsname + }{% + \csname zx@driver@\pgfsysdriver\endcsname + }% +} + +% Call zxConfigureExternalSystemCall with the same system call as the calling program +% Useful otherwise the error may be missed (for instance errorstopmode works in pdflatex but not in +% emacs, and nonstopmode works in emacs, but not in pdflatex). +% The current mode is stored in \interactionmode, 0, 1, 2, 3 corresponding respectively to batch, nonstop, scroll or errorstop. +% https://tex.stackexchange.com/questions/91592/where-to-find-official-and-extended-documentation-for-tex-latexs-commandlin +\NewDocumentCommand\zxConfigureExternalSystemCallAuto{}{% + \ifnum\interactionmode=0 % + \zxConfigureExternalSystemCall[-interaction=batchmode]% + \fi% + \ifnum\interactionmode=1 % + \zxConfigureExternalSystemCall[-interaction=nonstopmode]% emacs + \fi% + \ifnum\interactionmode=2 % + \zxConfigureExternalSystemCall[-interaction=scrollmode]% + \fi% + \ifnum\interactionmode=3 % + \zxConfigureExternalSystemCall[-interaction=errorstopmode]% pdflatex by default + \fi% +} + + +\ifdefined\zxDoNotPatchSystemCall\else% + \zxConfigureExternalSystemCallAuto +\fi + +% \zx@external@mode can be undefined (=auto), wrap or nowrap. + +%% Automatically check if the external library is loaded, and use it. +\NewDocumentCommand\zxExternalAuto{}{% + \let\zx@external@mode\undefined% +} + +%% Force to wrap the ZX figures around a figure to ensure compatibility with external. +\NewDocumentCommand\zxExternalWrap{}{% + \def\zx@external@mode{wrap}% +} + +%% Do not wrap the ZX figures around another figure (not compatible with external) +\NewDocumentCommand\zxExternalNoWrap{}{% + \def\zx@external@mode{nowrap}% +} + +%% Do not wrap the ZX figures, but disable external for these figures (semi-compatible with external) +\NewDocumentCommand\zxExternalNoWrapNoExt{}{% + \def\zx@external@mode{noWrapNoExt}% +} + +%% Wrap the ZX figures, and enable external for these figures (useful when most other environments +%% are not compatible with tikz external) +\NewDocumentCommand\zxExternalWrapForceExt{}{% + \def\zx@external@mode{wrapForceExt}% } +% Mode auto is enabled by default +\zxExternalAuto + +\NewDocumentCommand\zxExternalSuffix{m}{ + \ifthenelse{\equal{#1}{}}{% Nothing submitted: we erase the suffix + \let\zx@external@suffix\undefined% + }{% + \def\zx@external@suffix{#1} + }% +} + +\zxExternalSuffix{zx} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Custom nodes from Pic +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% It is quite complicated to define custom node shapes, especially when using anchors. Here, we define a +%% Way to easily create a custom node from a picture. + +%% This code allows to add a new anchor to a given node: +%% https://tex.stackexchange.com/a/676090/116348 +\tikzset{ + zx add anchor to node/.code n args={3}{% + \edef\tikz@temp##1{% \tikz@pp@name/\tikzlastnode needs to be expanded + %% This codes does the following thing: + %% First, it modifies the "\pgf@anchor@rectangle@fake center west" macro (rectangle might be another shape, + %% same for anchor). But since this macro might be different between nodes sharing the same shape, + %% it adds it to a per-node macro called like \pgf@sh@ma@tikz@f@3-2-2 (tikz@f@3-2-2 is the name of the + %% node). + \noexpand\pgfutil@g@addto@macro\expandafter\noexpand\csname pgf@sh@ma@\tikz@pp@name{#1}\endcsname{% + \def\expandafter\noexpand\csname pgf@anchor@\csname pgf@sh@ns@\tikz@pp@name{#1}\endcsname @#2\endcsname{##1}% + }% + }% + \tikz@temp{#3}% + }, + zx add anchor to pic default/.style={/tikz/zx add anchor to pic={#1}{#1}}, + zx add anchor to pic/.code 2 args={% + % If base coordinate isn't created yet, do so at (0,0) + % in the current coordinate system! + \pgfutil@ifundefined{pgf@sh@ns@\tikz@pp@name{}}{% + \pgfcoordinate{\tikz@pp@name{}}{\pgfpointorigin}% + }{}% + \begingroup + % What is the distance between coordinate and base? + % We have to do this in the coordinate system of the base coordinate. + \pgfsettransform{\csname pgf@sh@nt@\tikz@pp@name{}\endcsname}% + \pgf@process{\pgfpointanchor{\tikz@pp@name{#2}}{center}}% + % This distance is the new anchors coordinate + % in the base's coordinate system. + % Adding an anchor to a node must be global + % which is why we can do this inside the group. + \pgfkeysalso{ + /tikz/zx add anchor to node/.expanded=% + {}{#1}{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + }% + \endgroup + }% +} + +%%% Create automatically a new pic-based node +%%% \zxNewNodeFromPic{nameOfNode}[default style before user][default style after user]{content of the pic} +%%% - In 'default style before user', we can put any style that is given to the pic (e.g. colors, rotate, scale…) +%%% or even custom properties that will be read by the pic (e.g. to allow the define the number of spikes of a +%%% star). This style can notably have "zx create anchors={a, list, of, coordinates, to, turn, into, anchors}" +%%% that will automatically turn any coordinate in the pic in the list of coordinates into an anchor of the +%%% parent node. +%%% - In 'default style after user', the style is run after the code provided by the user. In particular, you can +%%% use "invert top bottom" to invert the "top" version with the "bottom" version (rotation is minus 90 instead +%%% of 90 for instance). +\NewDocumentCommand{\zxNewNodeFromPic}{mO{}O{}O{}O{}m}{% + \tikzset{% + #1Pic/.pic={% + #6% + % The user can even add more stuff to draw after if needed by redefining this macro: + \ifdefined\zxCustomPicAdditionalPic\zxCustomPicAdditionalPic\fi% + \tikzset{% + % We store the list of anchors to create into \zxListOfNewAnchors. If it does not exist we create it: + /utils/exec={\ifdefined\zxListOfNewAnchors\else\def\zxListOfNewAnchors{}\fi}, + % We add the coordinates in \zxListOfNewAnchors as anchors for the node + zx add anchor to pic default/.list/.expanded={\zxListOfNewAnchors}}% + },% + #1/.style={% + %shape=coordinate, %yshift=axis_height, %% already applied + #4, + append after command={% + pic[ + % We configure the name and position of the pic + at=(\tikzlastnode), name=\tikzlastnode, + % We create a command to add anchors via zx create anchors={my, list, of, anchors}. This way, it also allows dynamic anchors using + % the default style after user. + zx create anchors/.store in={\zxListOfNewAnchors}, + zx create anchors={}, + % We create a new style to apply to the main node + zx main node/.style={ + name=, + zx forward to node/.append style={}, + zx forward to node, + }, + % We load the other default arguments: + #2, + % We try to load a potentially global style configured by the user (mostly used to override this library) + /zx/picCustomStyleBeforeUser#1/.append style={}, % Make sure it exists to avoid errors + /zx/picCustomStyleBeforeUser#1, + % We load the per-instance arguments: + ##1, + % We try to load a potentially global style configured by the user (mostly used to override this library) + /zx/picCustomStyleAfterUser#1/.append style={}, % Make sure it exists to avoid errors + /zx/picCustomStyleAfterUser#1, + #3, + % We try to load a potentially global style configured by the user (mostly used to override this library) + /zx/picCustomStyleLastPic#1/.append style={}, % Make sure it exists to avoid errors + /zx/picCustomStyleLastPic#1, + ]{#1Pic}% + }, + }% + }% + %% \ExpandArgs{c} is an equivalent of expandafter + csname, to expand the first argument before evaluating the function: + %% https://tex.stackexchange.com/a/676103/116348 + %% ##1: pic additional style + %% ##2: node additional style + %% ##3: text to consume with \tikzpictext + % \ExpandArgs{c}\NewExpandableDocumentCommand{zx#1}{t.t-t'O{}O{}m}{% + % |[#1={pic text={##6}, ##4}, ##5]|% + % }% + % Actually ExpandArgs is not available before ~2023? maybe, so let’s use expandafter + \expandafter\NewExpandableDocumentCommand\csname zx#1\endcsname{O{}O{}t.t-t't/t*e_m}{% + \node[zx main node, #1={ + pic text={##9}, + %% The alias=… should rather be called on the second element. But it's quite handy to write it here, so here we go: + a/.style={% + zx forward to node/.append style={ + a={########1}, + }, + }, + %% The mode stored in \zxRotationMode contains the current rotation mode (i.e. the angle between 0 and 359, typically 0,90,180,270), + %% to allow further tweaks (for instance, a pic might be mirrored instead of rotated by 180° when using the parameter -, and this + %% can be configured by reading this variable). + /utils/exec={% + \def\zxCurrentRotationMode{0}% + %%% Fake center is mostly for curves like <', and true north/ is mostly for curves like C, C'... + %%% These anchor name are changed depending on the rotation: the north/… is before the rotation. + \def\zxVirtualCenterNorth{fake center north}% + \def\zxVirtualCenterSouth{fake center south}% + \def\zxVirtualCenterEast{fake center east}% + \def\zxVirtualCenterWest{fake center west}% + \def\zxTrueNorth{true north}% + \def\zxTrueSouth{true south}% + \def\zxTrueEast{true east}% + \def\zxTrueWest{true west}% + \IfBooleanT{##3}{% + \def\zxCurrentRotationMode{90}% + \def\zxVirtualCenterNorth{fake center west}% + \def\zxVirtualCenterSouth{fake center east}% + \def\zxVirtualCenterEast{fake center north}% + \def\zxVirtualCenterWest{fake center south}% + \def\zxTrueNorth{true west}% + \def\zxTrueSouth{true east}% + \def\zxTrueEast{true north}% + \def\zxTrueWest{true south}% + }% + \IfBooleanT{##4}{% + \def\zxCurrentRotationMode{180}% + \def\zxVirtualCenterNorth{fake center south}% + \def\zxVirtualCenterSouth{fake center north}% + \def\zxVirtualCenterEast{fake center west}% + \def\zxVirtualCenterWest{fake center east}% + \def\zxTrueNorth{true south}% + \def\zxTrueSouth{true north}% + \def\zxTrueEast{true west}% + \def\zxTrueWest{true east}% + }% + \IfBooleanT{##5}{% + \def\zxCurrentRotationMode{270}% + \def\zxVirtualCenterNorth{fake center east}% + \def\zxVirtualCenterSouth{fake center west}% + \def\zxVirtualCenterEast{fake center south}% + \def\zxVirtualCenterWest{fake center north}% + \def\zxTrueNorth{true east}% + \def\zxTrueSouth{true west}% + \def\zxTrueEast{true south}% + \def\zxTrueWest{true north}% + }% + \IfBooleanT{##6}{% + \def\zxModeSlash{}% + }% + \IfBooleanT{##7}{% + \def\zxModeStar{}% + }% + % Embellishments can contain something like \zxMynode_{Text A}{Text B} + \IfNoValueTF{##8}{}{% + \def\zxModeUnderscore{##8}% + }% + }, + rotate=\zxCurrentRotationMode,% + %%% Sometimes it can be quite handy to invert the top and the bottom version if it does not match with the + %%% intuitive position it should have. + %%% Make sure to call this in the second optional parameter (after user style) + invert top bottom/.style={ + rotate=-\zxCurrentRotationMode, + /utils/exec={% + \ifnum\zxCurrentRotationMode=90\relax + \def\zxCurrentRotationMode{270}% + \else + \ifnum\zxCurrentRotationMode=270\relax + \def\zxCurrentRotationMode{90}% + \fi + \fi + }, + rotate=\zxCurrentRotationMode,% + },% + invert right left/.style={ + rotate=-\zxCurrentRotationMode, + /utils/exec={% + \ifnum\zxCurrentRotationMode=0\relax + \def\zxCurrentRotationMode{180}% + \else + \ifnum\zxCurrentRotationMode=180\relax + \def\zxCurrentRotationMode{0}% + \fi + \fi + }, + rotate=\zxCurrentRotationMode,% + },% + ##1}, #5, ##2]{};% + }% +}% + +%% Useful to increase or decrease the bounding box of a custom node. +%% Parameters are like extend=5mm (that extends on all directions), and similarly for top/bottom/left/right/horizontal/vertical +\NewExpandableDocumentCommand{\zxExtendBoundingBox}{m}{% + \pgfkeys{ + /zx/.cd, + left/.store in=\zx@left, + left=0pt, + right/.store in=\zx@right, + right=0pt, + top/.store in=\zx@top, + top=0pt, + bottom/.store in=\zx@bottom, + bottom=0pt, + horizontal/.style={ + left=##1, + right=##1, + }, + vertical/.style={ + /zx/top=##1, + /zx/bottom=##1, + }, + extend/.style={ + vertical=##1, + horizontal=##1, + }, + #1, + }% + \path[use as bounding box] ([xshift=-\zx@left,yshift=\zx@top]current bounding box.north west) + rectangle ([xshift=\zx@right,yshift=-\zx@bottom]current bounding box.south east);% +} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Some special nodes based on \zxNewNodeFromPic +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Ground symbol +\zxNewNodeFromPic{Ground}[scale=\zxGroundScale][invert top bottom]{ + \draw[line width=\zxDefaultLineWidth] + (0,0) -- (1mm,0) + -- +(0,1mm) -- +(0,-1mm) + ++(.4mm,0) + -- +(0,.7mm) -- +(0,-.7mm) + ++(.4mm,0) + -- +(0,.35mm) -- +(0,-.35mm); + \coordinate() at (0,0); % Empty coordinate make the center start at the right position +} + +%% From scalable ZX calculus +\zxNewNodeFromPic{Divider}[][ + % Because of the rounded corners, the lines will stop before touching the shape when arriving on the angle. So we force such nodes to be drawn below + % the shape, targeting a point inside the node. + %post arrow style if end node/.expanded={% we need to expand everything before setting the style, as this style will be executed much later in the arrow, + post arrow style if end node={% if the text contains macro like \zxVirtualCenterWest use post arrow style if end node/.expanded instead as these macro + % will not exist anymore once the line is drawn + on layer=edgelayer,% + end anchor if not set=fake center north, + },% + post arrow style if start node={% if the text contains macro like \zxVirtualCenterWest use post arrow style if end node/.expanded instead as these macro + % will not exist anymore once the line is drawn + on layer=edgelayer,% + start anchor if not set=fake center south, + },% + zx create anchors={\zxVirtualCenterWest, \zxVirtualCenterEast, \zxVirtualCenterNorth, \zxVirtualCenterSouth}, + every node/.append style={transform shape} +]{ + \node[regular polygon, regular polygon sides=3,shape border rotate=90, draw=black,fill=gray!50, inner sep=1.6pt, rounded corners=0.8mm,zx main node] {}; + \coordinate(\zxVirtualCenterEast) at (.2mm,0); % Used to start lines on the side of the shape + \coordinate(\zxVirtualCenterWest) at (-1mm,0); + \coordinate(\zxVirtualCenterNorth) at (\zxVirtualCenterWest); % Synonyme, useful to determine where to start + \coordinate(\zxVirtualCenterSouth) at (\zxVirtualCenterEast); % Synonyme, useful to determine where to start +} + +%% Matrix symbol +\zxNewNodeFromPic{Matrix} + [ + % As we want - to only swap the position of the label but not the rotation (we use * already for transpose) + % we disable the above rotation: + rotate=-\zxCurrentRotationMode, + % Otherwise the space between colums is too big + /utils/exec={\setlength\arraycolsep{1pt}}, + ][zx create anchors={true north,true south,true east,true west}]{ + \node[zx main node, draw, signal, fill=colorZxMatrix, inner sep=1pt, minimum height=6pt, transform shape, + % The direction of the shape is turned when using the * symbol (transpose). + signal to/.expanded={\ifdefined\zxModeStar west\else east\fi}, + signal from/.expanded={\ifdefined\zxModeStar east\else west\fi}, + % We disabled the default rotation (* is for transpose), but we still want to rotate it to read to/down: + rotate/.expanded={mod(-\zxCurrentRotationMode,180)}, + % If we want the syntax \zxMatrix{45:f} to put f at 45 degrees, we want to expand \tikzpictext + % *before* to read the key, hence the need for expanded. + label/.expanded={[ + inner sep=2pt, + % The position of the label is independent of the rotation, but depends on the rotation mode ('.-): + absolute, + label position=\ifdefined\zxLabelAngle \zxLabelAngle\else 90+\zxCurrentRotationMode\fi, + font=\noexpand\footnotesize, % We don't want to expand \footnotesize before defining the label + % we use the / decoration + overlay/.expanded={\ifdefined\zxModeSlash true\else false\fi}, + % Math mode by default: + execute at begin node=$, execute at end node=$, + /zx/picCustomStyleMatrixLabel/.append style={}, % Make sure it exists to avoid errors + /zx/picCustomStyleMatrixLabel, + ] + % We put as the label the text directly. Note that \unexpanded\expandafter expands the next token only once + % as if it gets expanded further, we can get errors (e.g.\ with pmatrix) + \unexpanded\expandafter{\tikzpictext} + \ifdefined\zxModeUnderscore\noexpand\begin{bmatrix}\noexpand\zxModeUnderscore\noexpand\end{bmatrix}\fi + }, + /zx/picCustomStyleMatrixMainNode/.append style={}, % Make sure it exists to avoid errors + /zx/picCustomStyleMatrixMainNode, + ]{}; + \coordinate(true east) at (.east); % Used to start lines on the side of the shape + \coordinate(true west) at (.west); + \coordinate(true north) at (true west); % Synonyme, useful to determine where to start + \coordinate(true south) at (true east); % Synonyme, useful to determine where to start +} + +%% Gates + +\pgfkeys{ + /zx/every box/.style={ + draw, + inner sep=1.3mm, + rectangle, + zx filling style, + zx thickness wires style, + % not sure why, but seems to be already in math mode (maybe global options), and writing it twice disturbs the system + % execute at begin node=$, execute at end node=$, + execute at begin node={\renewcommand{\arraystretch}{1}\setlength\arraycolsep{2pt}}, + zxNormalFont, + minimum width=\zxBoxMinimumWidth, + minimum height=\zxBoxMinimumHeight, + }, + % https://tex.stackexchange.com/questions/696958/simple-way-to-specify-a-pass-a-style-with-syntax-my-style-foo/697043 + /zx/boxes/.code={% + \scantokens{% + \pgfkeysalso{% + /zx/every box/.append style={#1}% + }% + }% + }, + /zx/box load style/.style={ + add label advanced/.style 2 args={ + label={[inner sep=1.8pt,zxTinyFont,##1]##2}, + }, + add label/.style={ + add label advanced={}{##1}, + }, + }, +} + +\NewExpandableDocumentCommand{\zxBox}{O{}m}{ + \node[% + zx main node, + zx at origin, + alias=zxTmp, + /zx/box load style, + /zx/every box,% + #1% + ]{#2};% + % Nicer if you want '> to work + \zxCoordinateSubnode[at={(zxTmp.center)}]{fake center north};% + \zxCoordinateSubnode[at={(zxTmp.center)}]{fake center south};% + \zxCoordinateSubnode[at={(zxTmp.center)}]{fake center east};% + \zxCoordinateSubnode[at={(zxTmp.center)}]{fake center west};% +} + + +\NewCommandCopy\zxGate\zxBox + +\pgfkeys{ + /zx/every elt/.style={ + zx main node, + minimum width=\zxEltMinimumWidth, + minimum height=\zxEltMinimumHeight, + }, + % https://tex.stackexchange.com/questions/696958/simple-way-to-specify-a-pass-a-style-with-syntax-my-style-foo/697043 + /zx/elts/.code={% + \scantokens{% + \pgfkeysalso{% + /zx/every elt/.append style={#1}% + }% + }% + }, + /zx/elt load style/.style={ + add label advanced/.style 2 args={ + label={[inner sep=1.8pt,zxTinyFont,##1]##2}, + }, + add label/.style={ + add label advanced={}{##1}, + }, + }, +} + +\NewExpandableDocumentCommand{\zxElt}{O{}m}{ + \node[% + zx main node, + zx at origin, + alias=zxTmp, + /zx/elt load style, + /zx/every elt,% + #1% + ]{#2};% + % Nicer if you want '> to work + \zxCoordinateSubnode[at={(zxTmp.center)}]{fake center north};% + \zxCoordinateSubnode[at={(zxTmp.center)}]{fake center south};% + \zxCoordinateSubnode[at={(zxTmp.center)}]{fake center east};% + \zxCoordinateSubnode[at={(zxTmp.center)}]{fake center west};% +} + + +% \NewExpandableDocumentCommand{\zxEltMulti}{O{}mmm}{ +% \zxGateMulti[#1]{#2}{#3}{#4} +% } + +%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Gate Multi (user part) +%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\NewExpandableDocumentCommand{\zxGenericMulti}{m}{% + \path;% + \pgfkeys{% + /zx/generic multi/.cd,% + %%% Some default styles + /tikz/cleanup style for measure node/.style={ + a/.style={},% + }, + cleanup style for fit node/.store in=\zx@cleanupStyleFitNode, + cleanup style for fit node={}, + %%% this part is mostly used by the wrapping macro (e.g. to create \zxGateMulti) + command to run to measure node/.store in=\zx@commandToRunToMeasureNode, + command to run to create inner nodes/.store in=\zx@commandToRunToCreateInnerNodes, + command to run to create the fit node/.store in=\zx@commandToCreateTheFitNode, + command to run to create the main label/.store in=\zx@commandToCreateTheMainLabel,% + minimum height inner nodes/.store in=\zx@minimumHeightInnerNodes, + minimum width inner nodes/.store in=\zx@minimumWidthInnerNodes, + number rows/.store in=\zx@nbRows, + number columns/.store in=\zx@nbColumns,% + %%% this part can be used by the end user, and may be used inside the above commands + %%% Note that the wrapping macro should also initialize these values that might be changed by the user + %%% It might seem like this part is redundant, but not really, as this part can be changed by the user + %%% and is more fine grained that the above commands + content inner nodes/.store in=\myContent, + %%% TODO: in the function: content inner nodes={#4}, + style inner nodes/.store in=\zx@genericMultiStyle, + style inner nodes={}, + % this will be set by fit content not to override the user value + before style inner nodes/.store in=\zx@genericBeforeStyleInnerNodes, + before style inner nodes={}, + % style for the main style + main/.store in=\zx@genericMultiMainStyle, + main={}, + main text/.store in=\zx@genericMultiMainTextStyle, + main text={}, + original content/.store in=\zx@GenericMultiOriginalContent, + % Run additional code after the last \node + additional code/.store in=\zx@genericMultiAdditionalCode, + additional code=, + do not run fit content/.code={\def\zx@donotrunfitcontent{}}, + run fit content/.code={\let\zx@donotrunfitcontent\undefined}, + run fit content, + % This will compute the size of the content, and adapt the width of the inner nodes + % leaving around a margin specified in the 2 first arguments (row/column), the last argument is the minimum width of the inner nodes + % note that we take as a reference the content of \pgfmatrixcolumnsep which might not be constant: if you change the width of the columns, + % you are on your own. + fit content/.code n args={4}{ + % New version: + \begin{lrbox}{\zx@tmp@box}% + \begin{pgfinterruptpicture}% + \begin{pgfpicture}% + \zx@commandToRunToMeasureNode% + \end{pgfpicture}% + \end{pgfinterruptpicture}% + \end{lrbox}% + % % we measure the content of the box (##x appears 2 times since we have left and right margins): + \edef\zx@totalheight{\the\dimexpr\ht\zx@tmp@box + \dp\zx@tmp@box + ##1 + ##1\relax}% + \edef\zx@width{\the\dimexpr\wd\zx@tmp@box + ##2 + ##2\relax}% + \edef\zx@width{\the\dimexpr\wd\zx@tmp@box\relax}% + % \show\zx@totalheight + % \show\zx@width + %% We compute now the width/total height of each node. Basically, we have #3 blocks, and #3-1 column separations, so we want to find x such that: + %% x*#2 + (#2-1)*\pgfmatrixcolumnsep = \zx@width, i.e. + %% x = (\zx@width - (#2-1)*\pgfmatrixcolumnsep)/#2, + \pgfmathsetmacro{\zx@final@width@block}{max(##4,(\zx@width - (\zx@nbColumns-1)*\pgfmatrixcolumnsep)/(\zx@nbColumns))}% + \pgfmathsetmacro{\zx@final@height@block}{max(##3,(\zx@totalheight - (\zx@nbRows-1)*\pgfmatrixrowsep)/(\zx@nbRows))}% + \pgfkeysalso{% + content inner nodes={}, + before style inner nodes/.expanded={ + inner sep=0pt, + outer sep=0pt, + % opacity=0, + minimum width=\zx@final@width@block pt, + minimum height=\zx@final@height@block pt, + }, + % we disable it not to run it more than once in case the user decided to run it + do not run fit content, + }% + }, + fit content/.default={0mm}{0mm}{\zx@minimumHeightInnerNodes}{\zx@minimumWidthInnerNodes}, + safe fit/.style={ + before style inner nodes={}, + content inner nodes/.expand once={\zx@GenericMultiOriginalContent}, + do not run fit content, + }, + #1, + /utils/exec={ + \ifdefined\zx@donotrunfitcontent\else% + \pgfkeysalso{fit content}% + \fi% + }, + }% + % Store the content for letter use + \zxSetVariableExpandOnce{content inner nodes}{\myContent}% + \zxSetVariableExpandOnce{style inner nodes}{\zx@genericMultiStyle}% + \zxSetVariableExpandOnce{before style inner nodes}{\zx@genericBeforeStyleInnerNodes}% + \zxSetVariableExpandOnce{style main node}{\zx@genericMultiMainStyle}% + \zxSetVariableExpandOnce{style main text node}{\zx@genericMultiMainTextStyle}% + \zxSetVariableExpandOnce{additional code}{\zx@genericMultiAdditionalCode}% + \zxSetVariableExpandOnce{command to run to create inner nodes}{\zx@commandToRunToCreateInnerNodes}% + \zxSetVariableExpandOnce{command to run to create the fit node}{\zx@commandToCreateTheFitNode}% + \zxSetVariableExpandOnce{command to run to create the main label}{\zx@commandToCreateTheMainLabel}% + \zxSetVariableExpandOnce{cleanup style for fit node}{\zx@cleanupStyleFitNode}% + \zxExecuteAtRegionRelativeAndOrigin{\zx@nbRows}{\zx@nbColumns}{% + \zxGetVariable{command to run to create inner nodes}% + }% + \zxExecuteAtEndPicture{% + % We cannot use fit directly as it misplace the text. According to the doc, we should place the text using another intermediate node: + \scantokens{% + \zxGetVariable{command to run to create the fit node}% + \zxGetVariable{command to run to create the main label}% + \zxGetVariable{additional code}% + }% + } +} + +% the first style is kind of the style that is applied by default to the elements when +% it makes sense, but for most precise stuff use the second argument that can individually address other +% elements +\NewExpandableDocumentCommand{\zxGateMulti}{O{}O{}mmm}{% + \zxGenericMulti{ + command to run to measure node={% + \zxBox[% + % we disable a here since we do not want to use alias when measuring the node + cleanup style for measure node, + % Similarly, measuring nodes should not be done here + add label advanced/.style 2 args={}, + % label already exists + add label/.style={}, + #1% + ]{#5}% + }, + original content={#5}, + command to run to create inner nodes={ + \zxBox[% + opacity=0, + zx style from variable={before style inner nodes}, + zx style from variable={style inner nodes}, + ]{\zxGetVariable{content inner nodes}} + }, + command to run to create the fit node={% + \node[ + /zx/box load style, + /zx/every box,% + zx style from variable={cleanup style for fit node}, + add label advanced/.style 2 args={ + label={[align=center,inner sep=1.8pt,zxTinyFont,####1]####2}, + }, + % label already exists + add label/.style={ + add label advanced={}{####1}, + }, + #1,% this can set the alias for instance + inner sep=0pt, + minimum width=0pt, + minimum height=0pt, + alias=zxMainNode,%needed to place the main label + fit=(\zxGetNameRelativeNode{0}{0})(\zxGetNameRelativeNode{\the\numexpr#3-1\relax}{\the\numexpr#4-1\relax}), + zx style from variable={style main node}, + ]{};% + }, + command to run to create the main label={ + \node[ + rectangle, + zxNormalFont, + execute at begin node=$, + execute at end node=$, + % alias should be set on the fit node, not here: + a/.style={}, + alias/.style={}, + % Similarly, measuring nodes should not be done here + add label advanced/.style 2 args={}, + % label already exists + add label/.style={}, + #1,% needed for instance for the block stuff + % We disable stuff that should rather be set for the fit node + draw=none, + fill=none, + at=(zxMainNode.center), + alias=zxMainNodeText, + zx style from variable={style main text node}]{#5}; + },% + minimum height inner nodes={\zxBoxMinimumHeight}, + minimum width inner nodes={\zxBoxMinimumWidth}, + number rows={#3}, + number columns={#4}, + #2, + } +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Circuit-related gates +%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\tikzset{ + zx filling style/.style={ + fill=white + }, + % To change the thickness of wires and boxes at the same time + zx thickness wires style/.style={ + }, +} + +\NewExpandableDocumentCommand{\zxCtrl}{O{}m}{% + \node[zx main node, circle, inner sep=2pt, fill=black, #1]{}; +} + +% white ctrl +\NewExpandableDocumentCommand{\zxOCtrl}{O{}m}{% + \node[zx main node, circle, inner sep=2pt, zx filling style, zx thickness wires style, draw, #1]{}; +} + +\NewExpandableDocumentCommand{\zxNot}{O{}m}{% + \node[zx main node, circle, inner sep=2.5pt, draw, zx filling style, zx thickness wires style, append after command={(\tikzlastnode.north) edge[zx thickness wires style] (\tikzlastnode.south) (\tikzlastnode.east) edge[zx thickness wires style] (\tikzlastnode.west)}, #1]{}; +} + +\NewExpandableDocumentCommand{\zxCross}{O{}m}{% + \zxCoordinateMain{} + \node[at={(0,0)}, rectangle, inner sep=3pt, append after command={(\tikzlastnode.north east) edge[line cap=round,zx thickness wires style] (\tikzlastnode.south west) (\tikzlastnode.south east) edge[line cap=round,zx thickness wires style] (\tikzlastnode.north west)}, #1]{}; +} + +% Loosely inspired by +% https://tex.stackexchange.com/questions/416055/measurement-meter-quantum-circuit-with-tikz +% Avoid nesting tikz pictures, more efficient, more configurable +\newsavebox\zxMeterBox +\begin{lrbox}{\zxMeterBox}% + \begin{tikzpicture}[line width=.5,scale=.5]% + \draw[line cap=round] (0,0) to[bend left=50] (1,0);% + % \draw[line cap=round,-latex] (.5,-.2) to (.7,.8); + \draw[line cap=round,-{Stealth[length=6, round]}] (.5,-.15) to (.9,.75);% + %\useasboundingbox (-0.1,-.16) (1.1,.9); + \end{tikzpicture}% +\end{lrbox} + +\NewExpandableDocumentCommand{\zxMeter}{O{1}m}{% + \pgfmathparse{.8*\zxMeterScale*#1}% + \scalebox{\pgfmathresult}{\usebox{\zxMeterBox}}% +} + +% --------------------------------- +% --- (Circuit/Gate) inputs/outputs +% --------------------------------- +% I found no great way to pass the style to the label... but it seems like somehow the font color +% of the parent node is automatically transferred to the label, so the interface is not too bad + +\pgfkeys{ + /zx/input style/.style={ + align=center, + inner sep=2pt, + zxNormalFont, + anchor=east, + }, +} + +\def\zx@call@enlarge@brace#1{ + \ifnum#1=1% + \pgfkeysalso{enlarge brace={\zxDefaultEnlargeBraceOne}}% + \else% + \pgfkeysalso{enlarge brace={\zxDefaultEnlargeBraceMulti}}% + \fi% +} + +\NewExpandableDocumentCommand{\zxInput}{O{}m}{% + \zxExecuteAtEndPicture{\node[/zx/input style,#1] at (\zxGetNameRelativeNode{0}{0}){$#2$};}% +} + +\pgfkeys{ + /zx/output style/.style={ + align=center, + inner sep=2pt, + zxNormalFont, + anchor=west, + }, +} + +\NewExpandableDocumentCommand{\zxOutput}{O{}m}{% + \zxExecuteAtEndPicture{\node[/zx/output style,#1] at (\zxGetNameRelativeNode{0}{0}){$#2$};}% +} + +\pgfkeys{ + /zx/input multi style/.style={ + decorate, + decoration={brace, mirror, raise=2pt}, + }, + /zx/input multi label style/.style={swap,outer sep=5pt,zxNormalFont}, +} + +% https://tex.stackexchange.com/questions/696958/simple-way-to-specify-a-pass-a-style-with-syntax-my-style-foo/697043 +% +\NewExpandableDocumentCommand{\zxInputMulti}{O{}O{}mm}{% + \zxExecuteWhenDrawingArrows{% + \zxArrowNow[ + from=\zxGetNameRelativeNode{0}{0}, + to=\zxGetNameRelativeNodeStartOne{#3}{1}, + /zx/input multi style/.try, + enlarge brace/.style={ + start anchor={[yshift=####1]}, + end anchor={[yshift=-####1]}, + }, + /utils/exec={\zx@call@enlarge@brace{#3}}, + #1, + "#4" {/zx/input multi label style, #2}, + ]{} + }% +} + +\pgfkeys{ + /zx/output multi style/.style={ + decorate, + decoration={brace, raise=2pt}, + }, + /zx/output multi label style/.style={outer sep=5pt,zxNormalFont}, +} + +% https://tex.stackexchange.com/questions/696958/simple-way-to-specify-a-pass-a-style-with-syntax-my-style-foo/697043 +% +\def\zxDefaultEnlargeBraceMulti{.75mm} +\def\zxDefaultEnlargeBraceOne{2mm} +\NewExpandableDocumentCommand{\zxOutputMulti}{O{}O{}mm}{% + \zxExecuteWhenDrawingArrows{% + \zxArrowNow[ + from=\zxGetNameRelativeNode{0}{0}, + to=\zxGetNameRelativeNodeStartOne{#3}{1}, + enlarge brace/.style={ + start anchor={[yshift=####1]}, + end anchor={[yshift=-####1]}, + }, + /utils/exec={\zx@call@enlarge@brace{#3}}, + /zx/output multi style/.try, + #1, + "#4" {/zx/output multi label style, #2}, + ]{} + }% +} + + +\pgfkeys{ + /zx/gate input multi style/.style={ + decorate, + decoration={brace, raise=2pt}, + }, + /zx/gate input multi label style/.style={ + outer sep=4pt, + zxTinyFontAndSpacing + }, +} + + +\NewExpandableDocumentCommand{\zxGateInputMulti}{O{}O{}mm}{% + \zxExecuteWhenDrawingArrows{% + \zxArrowNow[ + from=\zxGetNameRelativeNode{0}{0}.west, + to=\zxGetNameRelativeNodeStartOne{#3}{1}.west, + /zx/gate input multi style/.try, + enlarge brace/.style={ + start anchor={[yshift=####1]}, + end anchor={[yshift=-####1]}, + }, + /utils/exec={\zx@call@enlarge@brace{#3}}, + #1, + "#4" {/zx/gate input multi label style, #2}, + ]{} + }% +} + +\pgfkeys{ + /zx/gate output multi style/.style={ + decorate, + decoration={brace, mirror, raise=2pt}, + }, + /zx/gate output multi label style/.style={ + swap, + outer sep=4pt, + zxTinyFontAndSpacing + }, +} + +% https://tex.stackexchange.com/questions/696958/simple-way-to-specify-a-pass-a-style-with-syntax-my-style-foo/697043 +% +\NewExpandableDocumentCommand{\zxGateOutputMulti}{O{}O{}mm}{% + \zxExecuteWhenDrawingArrows{% + \zxArrowNow[ + from=\zxGetNameRelativeNode{0}{0}.east, + to=\zxGetNameRelativeNodeStartOne{#3}{1}.east, + /zx/gate output multi style/.try, + enlarge brace/.style={ + start anchor={[yshift=####1]}, + end anchor={[yshift=-####1]}, + }, + /utils/exec={\zx@call@enlarge@brace{#3}}, + #1, + "#4" {/zx/gate output multi label style, #2}, + ]{} + }% +} + + +\pgfkeys{ + /zx/gate output style/.style={ + align=center, + inner sep=2pt, + zxTinyFontAndSpacing, + anchor=east, + }, +} + +\NewExpandableDocumentCommand{\zxGateOutput}{O{}m}{% + \zxExecuteAtEndPicture{\node[/zx/gate output style,#1] at (\zxGetNameRelativeNode{0}{0}.east){$#2$};}% +} + +\pgfkeys{ + /zx/gate input style/.style={ + align=center, + inner sep=2pt, + zxTinyFontAndSpacing, + anchor=west, + }, +} + +\NewExpandableDocumentCommand{\zxGateInput}{O{}m}{% + \zxExecuteAtEndPicture{\node[/zx/gate input style,#1] at (\zxGetNameRelativeNode{0}{0}.west){$#2$};}% +} + +% --- Same, but reading bottom to top + +\pgfkeys{ + /zx/vertical input style/.style={ + align=center, + inner sep=2pt, + zxNormalFont, + anchor=north, + }, +} + +\NewExpandableDocumentCommand{\zxVInput}{O{}m}{% + \zxExecuteAtEndPicture{\node[/zx/vertical input style,#1] at (\zxGetNameRelativeNode{0}{0}){$#2$};}% +} + +\pgfkeys{ + /zx/vertical output style/.style={ + align=center, + inner sep=2pt, + zxNormalFont, + anchor=south, + }, +} + +\NewExpandableDocumentCommand{\zxVOutput}{O{}m}{% + \zxExecuteAtEndPicture{\node[/zx/vertical output style,#1] at (\zxGetNameRelativeNode{0}{0}){$#2$};}% +} + +\pgfkeys{ + /zx/vertical input multi style/.style={ + decorate, + decoration={brace, mirror, raise=2pt}, + }, + /zx/vertical input multi label style/.style={swap,outer sep=5pt,zxNormalFont}, +} + +% https://tex.stackexchange.com/questions/696958/simple-way-to-specify-a-pass-a-style-with-syntax-my-style-foo/697043 +% +\NewExpandableDocumentCommand{\zxVInputMulti}{O{}O{}mm}{% + \zxExecuteWhenDrawingArrows{% + \zxArrowNow[ + from=\zxGetNameRelativeNode{0}{0}, + to=\zxGetNameRelativeNodeStartOne{1}{2}, + % to=\zxGetNameRelativeNodeStartOne{1}{#3}, + /zx/vertical input multi style/.try, + enlarge brace/.style={ + start anchor={[xshift=-####1]}, + end anchor={[xshift=####1]}, + }, + /utils/exec={\zx@call@enlarge@brace{#3}}, + #1, + "#4" {/zx/vertical input multi label style, #2}, + ]{} + }% +} + +\pgfkeys{ + /zx/vertical output multi style/.style={ + decorate, + decoration={brace, raise=2pt}, + }, + /zx/vertical output multi label style/.style={outer sep=5pt,zxNormalFont}, +} + +% https://tex.stackexchange.com/questions/696958/simple-way-to-specify-a-pass-a-style-with-syntax-my-style-foo/697043 +% +\NewExpandableDocumentCommand{\zxVOutputMulti}{O{}O{}mm}{% + \zxExecuteWhenDrawingArrows{% + \zxArrowNow[ + from=\zxGetNameRelativeNode{0}{0}, + to=\zxGetNameRelativeNodeStartOne{1}{#3}, + /zx/vertical output multi style/.try, + enlarge brace/.style={ + start anchor={[xshift=-####1]}, + end anchor={[xshift=####1]}, + }, + /utils/exec={\zx@call@enlarge@brace{#3}}, + #1, + "#4" {/zx/vertical output multi label style, #2}, + ]{} + }% +} + + +\pgfkeys{ + /zx/vertical gate input multi style/.style={ + decorate, + decoration={brace, raise=2pt}, + }, + /zx/vertical gate input multi label style/.style={ + outer sep=4pt, + zxTinyFontAndSpacing + }, +} + + +\NewExpandableDocumentCommand{\zxVGateInputMulti}{O{}O{}mm}{% + \zxExecuteWhenDrawingArrows{% + \zxArrowNow[ + from=\zxGetNameRelativeNode{0}{0}.south, + to=\zxGetNameRelativeNodeStartOne{1}{#3}.south, + /zx/vertical gate input multi style/.try, + enlarge brace/.style={ + start anchor={[xshift=-####1]}, + end anchor={[xshift=####1]}, + }, + /utils/exec={\zx@call@enlarge@brace{#3}}, + #1, + "#4" {/zx/vertical gate input multi label style, #2}, + ]{} + }% +} + +\pgfkeys{ + /zx/vertical gate output multi style/.style={ + decorate, + decoration={brace, mirror, raise=2pt}, + }, + /zx/vertical gate output multi label style/.style={ + swap, + outer sep=4pt, + zxTinyFontAndSpacing + }, +} + +% https://tex.stackexchange.com/questions/696958/simple-way-to-specify-a-pass-a-style-with-syntax-my-style-foo/697043 +% +\NewExpandableDocumentCommand{\zxVGateOutputMulti}{O{}O{}mm}{% + \zxExecuteWhenDrawingArrows{% + \zxArrowNow[ + from=\zxGetNameRelativeNode{0}{0}.north, + to=\zxGetNameRelativeNodeStartOne{1}{#3}.north, + /zx/vertical gate output multi style/.try, + enlarge brace/.style={ + start anchor={[xshift=-####1]}, + end anchor={[xshift=####1]}, + }, + /utils/exec={\zx@call@enlarge@brace{#3}}, + #1, + "#4" {/zx/vertical gate output multi label style, #2}, + ]{} + }% +} + +\pgfkeys{ + /zx/vertical gate output style/.style={ + align=center, + inner sep=2pt, + zxTinyFontAndSpacing, + anchor=north, + }, +} + +\NewExpandableDocumentCommand{\zxVGateOutput}{O{}m}{% + \zxExecuteAtEndPicture{\node[/zx/vertical gate output style,#1] at (\zxGetNameRelativeNode{0}{0}.north){$#2$};}% +} + +\pgfkeys{ + /zx/vertical gate input style/.style={ + align=center, + inner sep=2pt, + zxTinyFontAndSpacing, + anchor=south, + }, +} + +\NewExpandableDocumentCommand{\zxVGateInput}{O{}m}{% + \zxExecuteAtEndPicture{\node[/zx/vertical gate input style,#1] at (\zxGetNameRelativeNode{0}{0}.south){$#2$};}% +} + +%% If people prefer to read from top: + +\let\zxTOutput\zxVInput +\let\zxTInput\zxVOutput +\let\zxTOutputMulti\zxVInputMulti +\let\zxTInputMulti\zxVOutputMulti +\let\zxTGateOutputMulti\zxVGateInputMulti +\let\zxTGateInputMulti\zxVGateOutputMulti +\let\zxTGateInput\zxVGateOutput +\let\zxTGateOutput\zxVGateInput + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% Now using a special command for fractions (easier to code, and more customizable) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%%%%% Like \zx but uses \& instead of &. This WAS useful for instance in "align" environments +%%%%% since \zx{} was given an error (even without using &, changing the catcode was enough to +%%%%% break the function). However, in recent versions, \zx should work as it in align, and +%%%%% \begin{ZX}...\end{ZX} seems to always work in align without any issues. +%%%%% Anyway, if at some points you have troubles, either use +%%%%% \begin{ZX}[amp] ... \end{ZX} (amp is shortcut for "ampersand replacement=\&") or this function: +\NewDocumentCommand{\zxAmp}{O{}+m}{% + \begin{ZX}[ampersand replacement=\&, #1]% + #2% + \end{ZX}% +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Practical macros to automatically choose appropriate style and arrows +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% /!\ Warning: you should add {} at the end of all macros (except arrows)! +% Not using that may work for now, but it may break later... +% TODO: define them only in \zx environment. + % A swap on one line... Practical mostly to gain space. Must be used with large nodes tough... % \NewExpandableDocumentCommand{\OneLineSwap}{}{% % \ar[r,s,start anchor=south,end anchor=north] \ar[r,s,start anchor=north,end anchor=south] @@ -1891,7 +4213,7 @@ } \NewExpandableDocumentCommand{\zxLoopAboveDots}{O{20}O{}m}{% - \ar[loop,in=90-#1,out=90+#1,looseness=8,min distance=3mm,"\cvdotsCenterMathline" {scale=.6,anchor=north,yshift=-0.25mm},#2] + \ar[loop,in=90-#1,out=90+#1,looseness=8,min distance=3mm,"\cvdotsCenterMathline" {zxNormalFont,scale=.6,anchor=north,yshift=-0.25mm},#2] } @@ -1899,49 +4221,62 @@ % and vertical, \zxNone-{} is only horizontal space, \zxNone|{} is only vertical space. \NewExpandableDocumentCommand{\zxNone}{t+t-t|O{}m}{ \IfBooleanTF{#1}{% \zxNone+ - |[zxNone+,#4]| #5% + \node[zx main node, zxNone+,#4] {#5};% }{ \IfBooleanTF{#2}{% \zxNone- - |[zxNone-,#4]| #5% + \node[zx main node, zxNone-,#4] {#5};% }{ \IfBooleanTF{#3}{% \zxNone - |[zxNoneI,#4]| #5% + \node[zx main node, zxNoneI,#4] {#5};% }{% \zxNone - |[zxNone,#4]| #5% - } - } - } + \node[zx main node, zxNone,#4] {#5};% + }% + }% + }% } % Usage: alias of \zxNone... To bad token can't be easily forwarded to another function. \NewExpandableDocumentCommand{\zxN}{t+t-t|O{}m}{ \IfBooleanTF{#1}{% \zxNone+ - |[zxNone+,#4]| #5% + \node[zx main node, zxNone+,#4] {#5};% }{ \IfBooleanTF{#2}{% \zxNone- - |[zxNone-,#4]| #5% + \node[zx main node, zxNone-,#4]{#5};% }{ - \IfBooleanTF{#3}{% \zxNone - |[zxNoneI,#4]| #5% + \IfBooleanTF{#3}{% \zxNone| + \node[zx main node, zxNoneI,#4]{#5};% }{% \zxNone - |[zxNone,#4]| #5% - } - } - } + \node[zx main node, zxNone,#4]{#5};% + }% + }% + }% } + +% Usage: can be used without {}. Wait, actually it MUST be used without {} which is disturbing… to fix +\def\zxNL{ + \zxN{} \rar \pgfmatrixnextcell[\zxwCol]% +} + +% Usage: can be used without {} +\def\zxNR{ + \pgfmatrixnextcell[\zxwCol] \zxN{} \ar[l] +} + + + % Cf \zxNone, but with larger space. \NewExpandableDocumentCommand{\zxNoneDouble}{t+t-t|O{}m}{ \IfBooleanTF{#1}{% \zxNoneDouble+ - |[zxNoneDouble+,#4]| #5% + \node[zx main node, zxNoneDouble+,#4]{#5};% }{ \IfBooleanTF{#2}{% \zxNoneDouble- - |[zxNoneDouble-,#4]| #5% + \node[zx main node, zxNoneDouble-,#4]{#5};% }{ \IfBooleanTF{#3}{% \zxNoneDouble - |[zxNoneDoubleI,#4]| #5% + \node[zx main node, zxNoneDoubleI,#4]{#5};% }{% \zxNoneDouble - |[zxNoneDouble,#4]| #5% + \node[zx main node, zxNoneDouble,#4]{#5};% } } } @@ -1950,77 +4285,187 @@ %% For maximum styling liberty, the content is given directly to the style. % It allows the style to put the phase in a label. \NewExpandableDocumentCommand{\zxZ}{O{}t*t-m}{ - |[zxZ4={#1}{\IfBooleanTF{#3}{-}{}}{\IfBooleanTF{#2}{*}{}}{#4}]| % + \node[zx main node, zxZ4={#1}{\IfBooleanTF{#3}{-}{}}{\IfBooleanTF{#2}{*}{}}{#4}] {}; % } %% For maximum styling liberty, the content is given directly to the style. %% It allows the style to put the phase in a label. \NewExpandableDocumentCommand{\zxX}{O{}t*t-m}{ - |[zxX4={#1}{\IfBooleanTF{#3}{-}{}}{\IfBooleanTF{#2}{*}{}}{#4}]| % + \node[zx main node, zxX4={#1}{\IfBooleanTF{#3}{-}{}}{\IfBooleanTF{#2}{*}{}}{#4}]{};% } \NewExpandableDocumentCommand{\zxH}{O{}m}{ - |[zxH,#1]| {}% + \node[zx main node, zxH,#1]{};% } % Use like: \zxFracX{\pi}{4} for positive values or for negative \zxFracX-{\pi}{4} \NewExpandableDocumentCommand{\zxFracZ}{O{}t-moom}{% \IfNoValueTF{#5}{% 2 arguments like: \zxFracZ{\pi}{2} - |[zxFracZ6={#1}{\IfBooleanTF{#2}{\zxMinus}{}}{#3}{#6}{#3}{#6}]| % + \node[zx main node, zxFracZ6={#1}{\IfBooleanTF{#2}{\zxMinus}{}}{#3}{#6}{#3}{#6}]{};% }{% 4 arguments like \zxFracZ{a+b}[(a+b)][(c+d)]{c+d} - |[zxFracZ6={#1}{\IfBooleanTF{#2}{\zxMinus}{}}{#3}{#6}{#4}{#5}]| % + \node[zx main node, zxFracZ6={#1}{\IfBooleanTF{#2}{\zxMinus}{}}{#3}{#6}{#4}{#5}]{};% }% } % Use like: \zxFracX{\pi}{4} for positive values or for negative \zxFracX-{\pi}{4} \NewExpandableDocumentCommand{\zxFracX}{O{}t-moom}{% \IfNoValueTF{#5}{% 2 arguments like: \zxFracZ{\pi}{2} - |[zxFracX6={#1}{\IfBooleanTF{#2}{\zxMinus}{}}{#3}{#6}{#3}{#6}]| % + \node[zx main node, zxFracX6={#1}{\IfBooleanTF{#2}{\zxMinus}{}}{#3}{#6}{#3}{#6}]{};% }{% 4 arguments like \zxFracZ{a+b}[(a+b)][(c+d)]{c+d} - |[zxFracX6={#1}{\IfBooleanTF{#2}{\zxMinus}{}}{#3}{#6}{#4}{#5}]| % + \node[zx main node, zxFracX6={#1}{\IfBooleanTF{#2}{\zxMinus}{}}{#3}{#6}{#4}{#5}]{};% }% } \NewExpandableDocumentCommand{\zxEmptyDiagram}{}{ - |[zxEmptyDiagram]| {}% + \node[zx main node, zxEmptyDiagram]{};% } -% Quantikz has a bug which adds space automatically. -% https://tex.stackexchange.com/questions/618330 -% Fixing that by copying the original (unpatched) functions, and reusing them later. -% Warning: you must load this package **before** quantikz otherwise the fix will not work. -\let\tikzcd@@originalCopyZx\tikzcd@ -\let\endtikzcd@originalCopyZx\endtikzcd -%%%%% Main environment \begin{ZX}...\end{ZX} -\NewDocumentEnvironment{ZX}{O{}}{% - \bgroup% - \fontsize{10}{12}\selectfont% Normalize the font size to have consistent drawings everywhere. - % Add a switch in case someone really wants the current tikzcd version: - \ifdefined\doNotPatchQuantikz% Do not patch tikzcd. - \else% Restore locally original tikzcd. - \let\tikzcd@\tikzcd@@originalCopyZx% - \let\endtikzcd\endtikzcd@originalCopyZx% - \fi% - \pgfsetlayers{background,edgelayer,nodelayer,main,box,labellayer,foreground}% Layers are defined locally to avoid to disturb other drawings - \begin{tikzcd}[% - /zx/defaultEnv,% - #1]% - }{\end{tikzcd}\egroup} - -%%%%% Shortcut macro \zx{...} equivalent to \begin{ZX}...\end{ZX} -\newcommand\zx{% - \begingroup% To avoid ampersand issues https://tex.stackexchange.com/a/611535/116348 - \NewDocumentCommand{\tmpZX}{O{}+m}{% - \endgroup% - \begin{ZX}[##1]% - ##2% - \end{ZX}% +% % Example: \leftManyDots{n} +% Useful to put on the left of a node like "n \vdots", linked to the next node. Example: \leftManyDots{n}. +% First optional argument is scale of text, second is scale of =. +\NewExpandableDocumentCommand{\leftManyDots}{O{1}O{\zxScaleDots}m}{% + \node[zx main node, zxNone+,inner xsep=0pt]{\scalebox{#1}{$#3$\,}\makebox[0pt][l]{\scalebox{#2}{$\cvdotsCenterMathline$}}}; \ar[r,-N.,start anchor=north east] \ar[r,-N',start anchor=south east] \pgfmatrixnextcell[\zxwCol]% +} + +% Useful to link two nodes and put a vdots in between. +\NewExpandableDocumentCommand{\middleManyDots}{}{% + \ar[r,3 vdots] \ar[o',r] \ar[o.,r]% +} + +% Like \leftManyDots but on the right. Do *not* create a new node, like in |[zxShortZ]| \alpha \rightManyDots{m} +\NewExpandableDocumentCommand{\rightManyDots}{O{1}O{\zxScaleDots}m}{% + \ar[r,N'-,end anchor=north west] \ar[r,N.-,end anchor=south west] \pgfmatrixnextcell[\zxwCol] \node[zx main node, zxNone+,inner xsep=0pt]{\makebox[0pt][r]{\scalebox{#2}{$\cvdotsCenterMathline$}}\scalebox{#1}{\,$#3$}}; +} + +% Shortcut for frequent wires +\NewExpandableDocumentCommand{\zxDoubleO}{O{}m}{% + \ar[r,o.,#1] \ar[r,o',#1] +} + +% Version going down +\NewExpandableDocumentCommand{\zxDoubleOD}{O{}m}{% + \ar[r,o-,#1] \ar[r,-o,#1] +} + +\NewExpandableDocumentCommand{\zxTtripleO}{O{}m}{% + \rar \ar[r,o.,#1] \ar[r,o',#1] +} + +\NewExpandableDocumentCommand{\zxTripleOD}{O{}m}{% + \rar \ar[r,-.,#1] \ar[r,o-,#1] +} + + +\NewExpandableDocumentCommand{\zxOneOverSqrtTwo}{O{}m}{% + \zxZ{} \rar[#1] \ar[r,o.,#1] \ar[r,o',#1] \pgfmatrixnextcell \zxX{} +} + +\NewExpandableDocumentCommand{\zxSqrtTwo}{O{}m}{% + \zxZ{} \rar[#1] \pgfmatrixnextcell \zxX{} +} + + +%% Need AfterEndPreamble otherwise there is an error when using tikzexternalize. +\AfterEndPreamble{ + \zxSaveDiagram{\zxCteOneOverSqrtTwo}{\zxZ{} \rar \ar[r,o.] \ar[r,o'] \pgfmatrixnextcell \zxX{}} + \zxSaveDiagram{\zxCteSqrtTwo}{\zxZ{} \rar \pgfmatrixnextcell \zxX{}} +} + +%% Useful to give name to box +%% \namedBox{(node1)(node2)}{text} +%% \namedBox[additional style][color]{(node1)(node2)}[additional label options]{optional position:text} +%% \begin{ZX}[ +%% execute at end picture={ +%% \zxNamedBox{(measZ)(measZ)}{right:Bell measure} +%% } +%% ] +%% \zxN{} \dar[C] \ar[rrr] & & & \zxN{} \\ +%% \zxN{} \ar[rr] &&\zxX[a=measX]{x\pi} \dar[C-]\\ +%% & \zxX{r\pi} \rar& \zxZ[a=measZ]{z\pi} +%% \end{ZX} + +%% Helper +%% https://tex.stackexchange.com/questions/523579/tikz-fit-inner-sep-seperate-values-for-all-4-directions +% \tikzset{fit margins/.style={ +% /tikz/afit/.cd, +% #1, +% /tikz/.cd, +% inner xsep=\pgfkeysvalueof{/tikz/afit/left}+\pgfkeysvalueof{/tikz/afit/right}, +% inner ysep=\pgfkeysvalueof{/tikz/afit/top}+\pgfkeysvalueof{/tikz/afit/bottom}, +% xshift=-\pgfkeysvalueof{/tikz/afit/left}+\pgfkeysvalueof{/tikz/afit/right}, +% yshift=-\pgfkeysvalueof{/tikz/afit/bottom}+\pgfkeysvalueof{/tikz/afit/top}, +% afit/.cd, +% left/.initial=1pt,right/.initial=1pt,bottom/.initial=1pt,top/.initial=1pt +% }} + +\tikzset{ + fit margins/.style={ + /tikz/afit/.cd,#1, + /tikz/.cd, + inner xsep=\pgfkeysvalueof{/tikz/afit/left}+\pgfkeysvalueof{/tikz/afit/right}, + inner ysep=\pgfkeysvalueof{/tikz/afit/top}+\pgfkeysvalueof{/tikz/afit/bottom}, + %/utils/exec={\message{Last xishft is \pgfkeysvalueof{/tikz/afit/last xshift} and \pgfkeysvalueof{/tikz/afit/last yshift}}}, + xshift/.evaluated=-\pgfkeysvalueof{/tikz/afit/last xshift} + -\pgfkeysvalueof{/tikz/afit/left}+\pgfkeysvalueof{/tikz/afit/right}, + yshift/.evaluated=-\pgfkeysvalueof{/tikz/afit/last yshift} + -\pgfkeysvalueof{/tikz/afit/bottom}+\pgfkeysvalueof{/tikz/afit/top}, + /tikz/afit/last xshift/.evaluated=-\pgfkeysvalueof{/tikz/afit/left}+\pgfkeysvalueof{/tikz/afit/right}, + /tikz/afit/last yshift/.evaluated=-\pgfkeysvalueof{/tikz/afit/bottom}+\pgfkeysvalueof{/tikz/afit/top}, + }, + afit/.cd, + % used to save the last xshift done by fit margins, so that applying it twice does not shift twice + % since xshift=2cm,xshift=2cm is like xshift=4cm + last xshift/.initial=0pt, + last yshift/.initial=0pt, + % actual values + left/.initial=1pt, + right/.initial=1pt, + bottom/.initial=1pt, + top/.initial=1pt, + horizontal/.style={ + left=#1, + right=#1, + }, + vertical/.style={ + top=#1, + bottom=#1, + }, + all/.style={ + horizontal=#1, + vertical=#1, + }, + /tikz/.cd +} + +\NewExpandableDocumentCommand{\zxNamedBox}{O{}O{blue}mO{}m}{ + \node[l/.style={fit margins={all=1mm}},inner sep=2pt, node on layer=background, rounded corners, draw=#2,dashed, fill={#2!50!white}, opacity=.5, fit=#3,label={[#4]#5},#1]{}; +} + +% Cont is for container, equivalent of zxNamedBox but inside the matrix directly +\NewExpandableDocumentCommand{\zxCont}{O{}O{blue}mmO{}O{}m}{% + \zxExecuteAtEndPicture{% + \zxNamedBox[zx subnode=wrapper,#1][#2]{(\zxGetNameRelativeNode{0}{0})(\zxGetNameRelativeNode{\numexpr #3-1\relax}{\numexpr #4-1\relax})#6}[#5]{#7}% + }% +} + +% Cont is for container, equivalent of zxNamedBox but inside the matrix directly +\NewExpandableDocumentCommand{\zxGroupGates}{O{}mmO{}O{}m}{% + \zxCont[fill=none,rounded corners=0pt,solid,opacity=1,zx thickness wires style,draw=black,rectangle, + fit margins={all=.5mm}, + #1]{#2}{#3}[#4][#5]{#6} +} + +% Cont is for container, equivalent of zxNamedBox but inside the matrix directly +% this is the version where you specify the name of the node and not the relative pos +\NewExpandableDocumentCommand{\zxContName}{O{}O{blue}mO{}m}{% + \zxExecuteAtEndPicture{% + \zxNamedBox[#1][#2]{(\zxGetNameRelativeNode{0}{0})#3}[#4]{#5}% }% - \catcode`&=13% - \tmpZX% } + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Old code that tried to automatically find if zxShort or zxLong should be used... %%% Now using a special command for fractions (easier to code, and more customizable) @@ -2050,3 +4495,4 @@ }% }% } + diff --git a/Master/texmf-dist/tex/latex/zx-calculus/zx-calculus.sty b/Master/texmf-dist/tex/latex/zx-calculus/zx-calculus.sty index cb6a983c1f3..4cb629b5138 100644 --- a/Master/texmf-dist/tex/latex/zx-calculus/zx-calculus.sty +++ b/Master/texmf-dist/tex/latex/zx-calculus/zx-calculus.sty @@ -2,8 +2,9 @@ % Written by Léo Colisson. Report bugs on https://github.com/leo-colisson/zx-calculus/issues % Published under the MIT license. \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{zx-calculus}[2021/10/22 A package to typeset ZX calculus in directly in LaTeX, based on tikz/tikzcd.] +\ProvidesPackage{zx-calculus}[v2.0 A package to typeset ZX calculus and circuits directly in LaTeX, based on tikz/tikzcd.] \RequirePackage{tikz} +\RequirePackage{tikz-cd} \usetikzlibrary{zx-calculus} % See library in "tikzlibraryzx.code.tex". |