%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Version: 2021/10/15 %%% License: MIT %%% Author: Léo Colisson %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 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}. \RequirePackage{amssymb} % For short minus \RequirePackage{etoolbox} \RequirePackage{ifthen} % For conditions \RequirePackage{xparse} % For NewDocumentComments \RequirePackage{bm} % For bold math fonts \usetikzlibrary{cd,backgrounds,positioning,shapes,calc} % 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{main} \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. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% User modifiable variables %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Define colors, can be redefine by user \definecolor{colorZxZ}{RGB}{204,255,204} \definecolor{colorZxX}{RGB}{255,136,136} \definecolor{colorZxH}{RGB}{255,255,0} %%% Some wires (the one having an intermediate H, X, or S gate) may need some additional space for %%% specific columns. %%% Use these spaces like &[\zxHCol] or \\[\zxHRow] in that case %% Defines the space to add for columns and rows containing a connection with Hadamard % This is for "curved" wires \newcommand{\zxHCol}{1mm} \newcommand{\zxHRow}{1mm} % This is for "flat" wires (usually takes more space) \newcommand{\zxHColFlat}{1.5mm} \newcommand{\zxHRowFlat}{1.5mm} %% Defines the space to add for columns and rows containing a connection with small X/Z \newcommand{\zxSCol}{1mm} \newcommand{\zxSRow}{1mm} \newcommand{\zxSColFlat}{1.5mm} \newcommand{\zxSRowFlat}{1.5mm} %% Defines the space to add for columns having both H and Spiders \newcommand{\zxHSCol}{1mm} \newcommand{\zxHSRow}{1mm} \newcommand{\zxHSColFlat}{1mm} \newcommand{\zxHSRowFlat}{1mm} %% Wires only: when adding only wires with empty nodes, the space between columns can be too small. Useful not to shrink swap gates... \newcommand{\zxWCol}{.55em} \newcommand{\zxWRow}{.55em} %% When vdots/dots are used in lines \newcommand{\zxDotsCol}{3mm} \newcommand{\zxDotsRow}{3mm} % Angles by default for s and o related arrows \def\zxDefaultSoftAngleS{30} \def\zxDefaultSoftAngleN{60} \def\zxDefaultSoftAngleO{40} \def\zxDefaultSoftAngleChevron{60} % Scale to use when scaling 3 dots \def\zxScaleDots{.7} % 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} % For phase in content: How to convert sign ("-" for minus, nothing for "+", anything else should be inserted directly), % above fraction (no parens), below fraction (no parens), above fraction (with parens), below fraction (with parens) \NewExpandableDocumentCommand{\zxConvertToFracInContent}{mmmmm}{% \ifthenelse{\equal{#1}{-}}{\zxMinus}{#1}\frac{#2}{#3}% } % For phase in label: How to convert sign ("-" for minus, nothing for "+", anything else should be inserted directly), % above fraction (no parens), below fraction (no parens), above fraction (with parens), below fraction (with parens) \NewExpandableDocumentCommand{\zxConvertToFracInLabel}{mmmmm}{% \ifthenelse{\equal{#1}{-}}{\zxMinus}{#1}#4/#5% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Tikz styles %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 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 % - "/zx/default style wires" to change the wire style % - "/zx/user overlay wires/" to add stuff on wire style % The user is not supposed to use node styles directly (use \zxZ{}, \zxZ{\alpha+\beta}, \zxFrac-{\pi}{4}...) % but is free (and encouraged) to use the styles in "wires definition" like \ar[r,o']. \tikzset{ /zx/wires definition/.style={ %%% Basic default properties draw, -, line width=\zxDefaultLineWidth, %%% 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}, % Use this when you are drawing lines between none nodes only (like swap gates...) between none/.style={ looseness wires only, wire centered }, bn/.style={ between none }, % ------------------------------ % Practical stuff to draw lines easily: % Prefer to use these are they can be easily customized for each style and shorter to type. % Note that the letter is supposed to represent the shape of the link % dots/dashes are used to specify the position of the arrow. % Typically ' means top, . bottom, X- is right to X (or should arrive with angle 0), % -X is left to X (or should leave with angle zero). These shapes are usually designed to % work when the starting node is left most (or above of both nodes have the same column). % But they may work both way for some of them. % ------------------------------ %%% Cup/Cap % Like a C shape (with without a perfect half circle). Useful maybe when perfect circles are too big. % If only tex was a functional language... https://tex.stackexchange.com/questions/618955 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 % 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}% }% }% (\StartPoint) % <- the path starts at StartPoint %%% Get x coordinate of left-most point let \p1=(\StartPoint), \p2=(\TargetPoint), \n1={##1(##51,##52)}, % coordinate of the most left part (when ##1=min and ##5=\x: ##52 goes to \x2) \n3={abs(##61-##62)/2} % Radius of circle in % Warning: no comma after last line before in %%%% We go on the left if needed (we check that we do move, otherwise we break the arrows tip if %%%% we stay on place %%%% First go to the left if needed \pgfextra{% %% We check if we are moving or not (required to preserve arrow tip direction) \pgfmathapproxequalto{##51}{\n1}% }% \ifpgfmathcomparison\else -- ##7\fi %%%% Version 1: \pgfextra{ \pgfmathparse{ ifthenelse(##61<##62, % if end angle < angle, draw clockwis "arc[start angle=##3,end angle=##2,##8]",% "arc[start angle=##2,end angle=##3,##8]"% )% } } \pgfmathresult \pgfextra{% %% We check if we are moving or not (required to preserve arrow tip direction) \pgfmathapproxequalto{##52}{\n1}% }% \ifpgfmathcomparison\else -- (\TargetPoint)\fi \tikztonodes % All to path finishes with that to deal with futur nodes I think } }, %% 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 C-/.style={C@generic={max}{90}{-90}{east}{\x}{\y}{(\n1,\y1)}{y radius=\n3, x radius=##1*\n3}}, C-/.default=1, C'/.style={C@generic={max}{0}{180}{north}{\y}{\x}{(\x1,\n1)}{x radius=\n3, y radius=##1*\n3}}, C'/.default=1, C./.style={C@generic={min}{0}{-180}{south}{\y}{\x}{(\x1,\n1)}{x radius=\n3, y radius=##1*\n3}}, C./.default=1, % Like a C shape (with without a perfect half circle). This was the old definition of C... % Hopefully not useful anymore. c/.style={/tikz/in=180,/tikz/out=180,looseness=2}, % Like C, but symetric c-/.style={/tikz/in=0,/tikz/out=0,looseness=2}, c'/.style={/tikz/in=90,/tikz/out=90,looseness=2}, c./.style={/tikz/in=-90,/tikz/out=-90,looseness=2}, % Similar to C, but with a softer angle. The '.- marker represents the portion of % the circle (hence the o) to keep (top, bottom,left/right). % Angle is customizable, for instance o'=50. o'/.style={/tikz/out=##1,/tikz/in=180-##1}, o'/.default=\zxDefaultSoftAngleO, o./.style={/tikz/out=-##1,/tikz/in=180+##1}, o./.default=\zxDefaultSoftAngleO, -o/.style={/tikz/out=-90-##1,/tikz/in=90+##1}, -o/.default=\zxDefaultSoftAngleO, o-/.style={/tikz/out=-90+##1,/tikz/in=90-##1}, o-/.default=\zxDefaultSoftAngleO, % Similar to o, but can be used also for diagonal items. % Why ()? Visualize fixing the top part and moving the bottom part. (/.style={bend right=##1}, (/.default=30, )/.style={bend left=##1}, )/.default=30, ('/.style={bend left=##1}, ('/.default=30, (./.style={bend right=##1}, (./.default=30, <'/.style={out=##1,in=180,looseness=0.65}, <'/.default=\zxDefaultSoftAngleChevron, <./.style={out=-##1,in=180,looseness=0.65}, <./.default=\zxDefaultSoftAngleChevron, '>/.style={out=0,in=180-##1,looseness=0.65}, '>/.default=\zxDefaultSoftAngleChevron, .>/.style={out=0,in=180+##1,looseness=0.65}, .>/.default=\zxDefaultSoftAngleChevron, ^./.style={out=-90+##1,in=90,looseness=0.65}, ^./.default=\zxDefaultSoftAngleChevron, .^/.style={out=-90-##1,in=90,looseness=0.65}, .^/.default=\zxDefaultSoftAngleChevron, 'v/.style={out=90+##1,in=-90,looseness=0.65}, 'v/.default=\zxDefaultSoftAngleChevron, v'/.style={out=90-##1,in=-90,looseness=0.65}, v'/.default=\zxDefaultSoftAngleChevron, % Links with a s-like shape. s/.style={/tikz/out=0,/tikz/in=180,looseness=0.6}, % -s'.- shapes are like s, but with a soften (customizable like o) angle. % The '. say if you are going up or down, and - forces a sharp angle (- is flat) on the side of the - s'/.style={/tikz/out=##1,/tikz/in=180+##1}, s'/.default=\zxDefaultSoftAngleS, s./.style={/tikz/out=-##1,/tikz/in=180-##1}, s./.default=\zxDefaultSoftAngleS, -s'/.style={/tikz/out=0,/tikz/in=180+##1}, -s'/.default=\zxDefaultSoftAngleS, -s./.style={/tikz/out=0,/tikz/in=180-##1}, -s./.default=\zxDefaultSoftAngleS, s'-/.style={/tikz/out=##1,/tikz/in=180}, s'-/.default=\zxDefaultSoftAngleS, s.-/.style={/tikz/out=-##1,/tikz/in=180}, s.-/.default=\zxDefaultSoftAngleS, % Links with a s-like shape... but read from top to bottom ss/.style={/tikz/out=0-90,/tikz/in=180-90,looseness=0.6}, % -s'.- shapes are like s, but with a soften (customizable like o) angle. % The '. say if you are going up or down, and - forces a sharp angle (- is flat) on the side of the - ss./.style={/tikz/out=##1-90,/tikz/in=180-90+##1}, ss./.default=\zxDefaultSoftAngleS, .ss/.style={/tikz/out=-##1-90,/tikz/in=180-90-##1}, .ss/.default=\zxDefaultSoftAngleS, sIs./.style={/tikz/out=0-90,/tikz/in=180-90+##1}, sIs./.default=\zxDefaultSoftAngleS, .sIs/.style={/tikz/out=0-90,/tikz/in=180-90-##1}, .sIs/.default=\zxDefaultSoftAngleS, ss.I/.style={/tikz/out=##1-90,/tikz/in=180-90}, ss.I/.default=\zxDefaultSoftAngleS, I.ss/.style={/tikz/out=-##1-90,/tikz/in=180-90}, I.ss/.default=\zxDefaultSoftAngleS, %%%% Links with a N-shape, i.e. like s shape, but symetric against the diagonal. Equivalently, it's a soft 's' shape with a much wider angle (>45). N'/.style={/tikz/out=##1,/tikz/in=180+##1}, N'/.default=\zxDefaultSoftAngleN, N./.style={/tikz/out=-##1,/tikz/in=180-##1}, N./.default=\zxDefaultSoftAngleN, -N'/.style={/tikz/out=0,/tikz/in=180+##1}, -N'/.default=\zxDefaultSoftAngleN, -N./.style={/tikz/out=0,/tikz/in=180-##1}, -N./.default=\zxDefaultSoftAngleN, N'-/.style={/tikz/out=##1,/tikz/in=180}, N'-/.default=\zxDefaultSoftAngleN, N.-/.style={/tikz/out=-##1,/tikz/in=180}, N.-/.default=\zxDefaultSoftAngleN, % No line but vdots/dots in between. 3 vdots/.style={draw=none, "\makebox[0pt][r]{##1}\scalebox{\zxScaleDots}{$\cvdots$}" anchor=center}, 3 vdots/.default={}, 3 dots/.style={draw=none, "\makebox[0pt][r]{##1}\scalebox{\zxScaleDots}{$\chdots$}" anchor=center}, 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] % for columns and \\[\zxHRow] for rows (for Z/X style, use zxSCol and sxSRow), if you have both spiders % and Hadamard, use \zxHSCol and \zxHSRow. H/.style={"" {zxHSmall,anchor=center}}, Z/.style={"" {zxNoPhaseSmallZ,anchor=center}}, X/.style={"" {zxNoPhaseSmallX,anchor=center}}, % Arrow will go out from the center of the shape instead of from the border. Useful % when connecting nodes with different shapes, it will give back a symetric connection. wire centered/.style={ on layer=edgelayer, /tikz/commutative diagrams/start anchor=center, /tikz/commutative diagrams/end anchor=center, }, wire centered start/.style={ on layer=edgelayer, /tikz/commutative diagrams/start anchor=center, }, wire centered end/.style={ on layer=edgelayer, /tikz/commutative diagrams/end anchor=center, }, wc/.style={wire centered}, wcs/.style={wire centered start}, wce/.style={wire centered end}, wire not centered/.style={ /tikz/commutative diagrams/start anchor=, /tikz/commutative diagrams/end anchor=, }, }, /zx/styles/rounded style/.style={ %% Can be redefined by user % Style for empty nodes 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 +/-... }, % Use this to denote an empty diagram zxEmptyDiagram/.style={ zxAllNodes, draw, dashed, minimum size=4mm, }, % Style to use when no node is drawn zxNone/.style={ zxAllNodes, shape=coordinate, % A coordinate has just a center. Nothing more. }, % Style to use when no node is drawn, but a bit of space is required not to make the diagram too small zxNone+/.style={ zxAllNodes, inner sep=1mm, outer sep=0mm }, % Like zxNone+, but without width (wold prefer |, but special car in |[]|... zxNoneI/.style={ zxNone+, inner xsep=0mm, }, % Like zxNone+, but without height zxNone-/.style={ zxNone+, inner ysep=0mm, }, % Style to use when no node is drawn, but a large space must be reserved (typically used to fake two % nodes on a single line) (for +I- versions) zxNoneDouble/.style={ shape=coordinate }, % Style to use when no node is drawn, but a bit of space is required not to make the diagram too small zxNoneDouble+/.style={ zxAllNodes, inner sep=.6em, outer sep=0mm }, % Like zxNoneDouble+, but without width (wold prefer |, but special car in |[]|... zxNoneDoubleI/.style={ zxNoneDouble+, inner xsep=0mm, }, % Like zxNoneDouble+, but without height zxNoneDouble-/.style={ zxNoneDouble+, inner ysep=0mm, }, % Will be specific to all spiders zxSpiders/.style={ draw=black, }, % Will use this style when drawing a X/Z node without phase (not for end user directly) zxNoPhase/.style={ zxAllNodes, zxSpiders, inner sep=0mm, minimum size=2mm, shape=circle, }, % Used only in decoration of wires, to add small empty X/Z nodes. zxNoPhaseSmall/.style={ zxNoPhase }, % Style for nodes that are small enough to fit in a circle, like $\zxMinus \frac{\pi}{4}$ zxShort/.style={ zxAllNodes, zxSpiders, minimum size=5mm, font={\fontsize{8}{10}\selectfont\boldmath}, rounded rectangle, inner sep=0.0mm, scale=0.8, }, % negative outer sep would draw lines from inside... % Style for nodes that are bigger, like $\alpha+\beta$ or $(a\oplus b)\pi$ zxLong/.style={zxShort, inner xsep=1.2mm}, %%% Styles of the label when |phase in label| is used stylePhaseInLabel/.style={ font={\fontsize{8}{10}\selectfont\boldmath}, inner sep=2pt, outer sep=0pt, rounded rectangle, % node on layer=labellayer, %% Fails in tikzcd: https://tex.stackexchange.com/questions/618823/node-on-layer-style-in-tikz-matrix-tikzcd }, stylePhaseInLabelZ/.style={ stylePhaseInLabel, fill=green!20!white }, stylePhaseInLabelX/.style={ stylePhaseInLabel, fill=red!20!white }, %%%%%%%%%%% Style defined depending on above ones. Feel free to redefine. zxNoPhaseZ/.style={zxNoPhase,fill=colorZxZ}, zxNoPhaseX/.style={zxNoPhase,fill=colorZxX}, zxNoPhaseSmallZ/.style={zxNoPhaseSmall,fill=colorZxZ}, zxNoPhaseSmallX/.style={zxNoPhaseSmall,fill=colorZxX}, zxShortZ/.style={zxShort,fill=colorZxZ}, zxShortX/.style={zxShort,fill=colorZxX}, zxLongZ/.style={zxLong,fill=colorZxZ}, zxLongX/.style={zxLong,fill=colorZxX}, %%%%%%%%%%% %%% Instead of adding directly the style as the node's content (which would make %%% impossible styles that adds the phase in a label outside of the node) %%% add@Phase@Spider{,Z,X}={phase of the node} will be in charge of adding it. add@Phase@Spider/.style n args={4}{ % add@Phase@Spider{emptyStyle}{NotEmptyStyle}{node content} zx@emptyStyle/.style={##1}, zx@notEmptyStyle/.style={##2}, zx@labelStyle/.style={##3}, /zx/zx@content/.initial={##4}, phase in content, }, add@Phase@Spider@Frac/.style n args={8}{ % add@Phase@Spider{emptyStyle}{NotEmptyStyle}{labelstyle}{sign}{above fraction (no parens)}{below fraction (no parens)}{above fraction (parens)}{below fraction (parens)} zx@emptyStyle/.style={##1}, zx@notEmptyStyle/.style={##2}, zx@labelStyle/.style={##3}, % Useful to help "phase in content" to know if we are in Frac or not. /zx/zx@isInFrac/.initial={true}, phase in content, }, % #1 is the node content. Seems that storing it in /zx/zx@content is not enough because keys % seems to be local to nodes and are not transfered to label. zx@Execute@Very@End/.style n args={4}{ zx@commandToExecuteVeryEnd/.try={##1}{##2}{##3}{##4}, }, zx@Execute@Very@End/.default={}{}{}{}, %% zx@Execute@Very@End@Frac={emptystyle}{contentstyle}{labelstyle}{sign}{above frac (no parens)}{below frac (no parens)}{above frac (parens)}{below frac (parens)} zx@Execute@Very@End@Frac/.style n args={8}{ zx@commandToExecuteVeryEndFrac/.try={##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}, }, zx@Execute@Very@End@Frac/.default={}{}{}{}{}{}{}{}, %% /!\ WARNING: the following styles "phase..." must be loaded by or *after* add@Phase@Spider... %% To load it on the whole picture, prefer to do: %% \zx[/zx/user post preparation labels/.style={phase in label}]{ %% \zxZ{\alpha} %% } phase in content/.code={% % Check if we are in a Frac or not \ifthenelse{\equal{\pgfkeysvalueof{/zx/zx@isInFrac}}{true}}{% %%% ### We are in a fraction node! %% Modifies zx@commandToExecuteVeryEnd (which is executed at the very end by zx@Execute@Very@End) %% in order to add the good style \pgfkeysalso{ % zx@commandToExecuteVeryEndFrac{emptystyle}{contentstyle}{labelstyle}{sign}{above frac (no parens)}{below frac (no parens)}{above frac (parens)}{below frac (parens)} zx@commandToExecuteVeryEndFrac/.style n args={8}{% execute at begin node={\zxConvertToFracInContent{####4}{####5}{####6}{####7}{####8}},% },% % Adds the style: zx@notEmptyStyle, }% }{ %%% ### We are NOT in a fraction node. %% Modifies zx@commandToExecuteVeryEnd (which is executed at the very end by zx@Execute@Very@End) %% in order to add the good style \pgfkeysalso{ zx@commandToExecuteVeryEnd/.style n args={4}{% execute at begin node={####4},% ####4 = content }% }% % Checks if the content (stored by add@Phase@Spider in /zx/zx@content) is empty or not \ifthenelse{\equal{\pgfkeysvalueof{/zx/zx@content}}{}}{% \pgfkeysalso{% zx@emptyStyle,% }% }{% \pgfkeysalso{% zx@notEmptyStyle,% }% }% }% }, phase in label/.code={ % Check if we are in a Frac or not \ifthenelse{\equal{\pgfkeysvalueof{/zx/zx@isInFrac}}{true}}{% %%% ### We are in a fraction node! \pgfkeysalso{% % zx@commandToExecuteVeryEndFrac{emptystyle}{contentstyle}{labelstyle}{sign}{above frac (no parens)}{below frac (no parens)}{above frac (parens)}{below frac (parens)} zx@commandToExecuteVeryEndFrac/.code n args={8}{% \pgfkeysalso{ label={[####3,##1] \zxConvertToFracInLabel{####4}{####5}{####6}{####7}{####8}},% }% },% zx@emptyStyle, }% }{% \pgfkeysalso{% % ##1 is the argument of "phase in label", i.e. the style of the label zx@commandToExecuteVeryEnd/.code n args={4}{% ####3: label style, ####4: content % Checks if the content (stored by add@Phase@Spider in /zx/zx@content) is empty or not \ifthenelse{\equal{####4}{}}{% Content is empty }{% Content is not empty \pgfkeysalso{ label={[####3,##1] ####4},% }% }% },% zx@emptyStyle, }% }% }, 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}, phase in label above/.style={ phase in label={label position=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}, phase in label left/.style={ phase in label={label position=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 \zxZ2{...} and \zxX2{...} commands % and zxShort is selected for fractions only like in \zxFracZ-{\pi}{4} % zxZ/.style={zxChoose={##1},fill=colorZxZ}, % zxX/.style={zxChoose={##1},fill=colorZxX}, %%% First argument is additional style. Second argument is content of node. zxZ2/.style 2 args={ add@Phase@Spider={zxNoPhaseZ}{zxLongZ}{stylePhaseInLabelZ}{##2}, /zx/post preparation labels, /zx/user post preparation labels, %/zx/user overlay nodes, ##1, zx@Execute@Very@End={zxNoPhaseZ}{zxLongZ}{stylePhaseInLabelZ}{##2}, }, %% ##1: other styles, ##2: content zxX2/.style 2 args={ add@Phase@Spider={zxNoPhaseX}{zxLongX}{stylePhaseInLabelX}{##2}, /zx/post preparation labels, /zx/user post preparation labels, ##1, zx@Execute@Very@End={zxNoPhaseX}{zxLongX}{stylePhaseInLabelX}{##2}, }, %% 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}, /zx/post preparation labels, /zx/user post preparation labels, ##1, zx@Execute@Very@End@Frac={zxNoPhaseZ}{zxShortZ}{stylePhaseInLabelZ}{##2}{##3}{##4}{##5}{##6}, }, zxFracX6/.style n args={6}{ add@Phase@Spider@Frac={zxNoPhaseX}{zxShortX}{stylePhaseInLabelX}{##2}{##3}{##4}{##5}{##6}, /zx/post preparation labels, /zx/user post preparation labels, ##1, zx@Execute@Very@End@Frac={zxNoPhaseX}{zxShortX}{stylePhaseInLabelX}{##2}{##3}{##4}{##5}{##6}, }, % For Hadamard zxH/.style={ zxAllNodes, outer sep=0pt, fill=colorZxH, draw, inner sep=0.6mm, minimum height=1.5mm, minimum width=1.5mm, shape=rectangle}, zxHSmall/.style={zxH}, }, % Default style. Can be changed by user /zx/default style nodes/.style={ /zx/styles/rounded style }, % User can put here any additional property /zx/user overlay nodes/.style={ }, % Any additional property that needs to be loaded after add@Phase@Spider (by script, not by user). /zx/post preparation labels/.style={ }, % User can put here any additional property that needs to be loaded after add@Phase@Spider /zx/user post preparation labels/.style={ }, % Default wire style. Can be changed by user. /zx/default style wires/.style={ }, % User can add stuff in this style to improve wire styles /zx/user overlay wires/.style={ }, /zx/defaultEnv/.style={ column sep=tiny, row sep=tiny, % center on the math axis baseline={([yshift=-axis_height]current bounding box.center)}, % Fix 1-row diagram baseline 1-row diagram/.style={% /tikz/baseline={([yshift=-axis_height]current bounding box.center)}% }, % Load (thanks ".search also") our own style /tikz/every node/.style={% % For quickly adding alias, and displaying this alias in debug mode. a/.code={% \pgfkeysalso{% alias=####1,% }% \ifdefined\zxDebugMode% \pgfkeysalso{% label={[inner sep=0pt,overlay,red,font={\fontsize{5}{6}}]-45:\scalebox{.5}{####1}} }% \fi% }, /zx/default style nodes, /zx/user overlay nodes, }, every arrow/.style={% /zx/wires definition, /zx/default style wires, /zx/user overlay wires, }, %%% To be used only in \zx{...} environment. %%% Exemple: phase in content/.style={ /zx/post preparation labels/.append style={ phase in content, } }, phase in label/.style={ /zx/post preparation labels/.append style={ phase in label=##1, } }, phase in label above/.style={ /zx/post preparation labels/.append style={ phase in label above=##1, } }, phase in label below/.style={ /zx/post preparation labels/.append style={ phase in label below=##1, } }, phase in label right/.style={ /zx/post preparation labels/.append style={ phase in label right=##1, } }, phase in label left/.style={ /zx/post preparation labels/.append style={ 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}, }, } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Helper functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Defines a "on layer=nameoflayer" style. TODO: check if better to move it in /zx/ % https://tex.stackexchange.com/questions/20425/z-level-in-tikz/20426#20426 % For path: on layer=namelayer, for nodes "node on layer=..." % /!\ node on layer fails in tikzcd: https://tex.stackexchange.com/questions/618823/node-on-layer-style-in-tikz-matrix-tikzcd \pgfkeys{% /tikz/on layer/.code={ \pgfonlayer{#1}\begingroup \aftergroup\endpgfonlayer \aftergroup\endgroup }, /tikz/node on layer/.code={ \gdef\node@@on@layer{% \setbox\tikz@tempbox=\hbox\bgroup\pgfonlayer{#1}\unhbox\tikz@tempbox\endpgfonlayer\egroup} \aftergroup\node@on@layer }, /tikz/end node on layer/.code={ \endpgfonlayer\endgroup\endgroup } } \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 %%% 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 %%% https://tex.stackexchange.com/questions/6189553 \def\ifPgfpointOrNode#1#2#3{% \pgfutil@ifundefined{pgf@sh@ns@#1}{% #2% }{% #3% }% } %%% Create different kinds of dots... %% https://tex.stackexchange.com/questions/617959 %% https://tex.stackexchange.com/questions/528774/excess-vertical-space-in-vdots/528775#528775 \DeclareRobustCommand\cvdotsAboveBaseline{% \vbox{\baselineskip4\p@ \lineskiplimit\z@% \hbox{.}\hbox{.}\hbox{.}} } \DeclareRobustCommand{\cvdotsCenterMathline}{% % vcenter is used to center the argument on the 'math axis', which is at half the height of an 'x', or about the position of a minus sign. \vcenter{\cvdotsAboveBaseline}% } \DeclareRobustCommand{\cvdotsCenterBaseline}{% \raisebox{-.5\height}{% $\cvdotsAboveBaseline$% }% } \DeclareRobustCommand{\chdots}{% \raisebox{-.5\height}{% \rotatebox{90}{% Maybe better options than rotatebox... $\cvdotsAboveBaseline$% }% }% } \DeclareRobustCommand{\cvdots}{\cvdotsCenterMathline} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% 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. % % 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}{$\cvdots$}} \ar[r,-s.,start anchor=north east] \ar[r,-s',start anchor=south east] \pgfmatrixnextcell% } % 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,s'-,end anchor=north west] \ar[r,s.-,end anchor=south west] \pgfmatrixnextcell |[zxNone+,inner xsep=0pt]| \makebox[0pt][r]{\scalebox{#2}{$\cvdots$}}\scalebox{#1}{\,$#3$} } % 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] % } \NewExpandableDocumentCommand{\zxLoop}{O{90}O{20}O{}m}{% \ar[loop,in=#1-#2,out=#1+#2,looseness=8,min distance=3mm,#3] } \NewExpandableDocumentCommand{\zxLoopAboveDots}{O{20}O{}m}{% \ar[loop,in=90-#1,out=90+#1,looseness=8,min distance=3mm,"\cvdots" {scale=.6,anchor=north,yshift=-0.4mm},#2] } % Usage: node without any style, but may have space. Default is no space, \zxNone+{} is both horizontal % 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% }{ \IfBooleanTF{#2}{ % \zxNone- |[zxNone-,#4]| #5% }{ \IfBooleanTF{#3}{ % \zxNone |[zxNoneI,#4]| #5% }{% \zxNone |[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% }{ \IfBooleanTF{#2}{ % \zxNone- |[zxNone-,#4]| #5% }{ \IfBooleanTF{#3}{ % \zxNone |[zxNoneI,#4]| #5% }{% \zxNone |[zxNone,#4]| #5% } } } } % Cf \zxNone, but with larger space. \NewExpandableDocumentCommand{\zxNoneDouble}{t+t-t|O{}m}{ \IfBooleanTF{#1}{ % \zxNoneDouble+ |[zxNoneDouble+,#4]| #5% }{ \IfBooleanTF{#2}{ % \zxNoneDouble- |[zxNoneDouble-,#4]| #5% }{ \IfBooleanTF{#3}{ % \zxNoneDouble |[zxNoneDoubleI,#4]| #5% }{% \zxNoneDouble |[zxNoneDouble,#4]| #5% } } } } %% 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{}m}{ |[zxZ2={#1}{#2}]| % } %% 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{}m}{ |[zxX2={#1}{#2}]| % } \NewExpandableDocumentCommand{\zxH}{O{}m}{ |[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}]| % }{% 4 arguments like \zxFracZ{a+b}[(a+b)][(c+d)]{c+d} |[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}]| % }{% 4 arguments like \zxFracZ{a+b}[(a+b)][(c+d)]{c+d} |[zxFracX6={#1}{\IfBooleanTF{#2}{\zxMinus}{}}{#3}{#6}{#4}{#5}]| % }% } \NewExpandableDocumentCommand{\zxEmptyDiagram}{}{ |[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% % 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}% }% \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) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newsavebox\zx@box % Temporary box to compute height/width/depth \newlength{\zxMaxDepthPlusHeight}\setlength{\zxMaxDepthPlusHeight}{2em} \def\zxMaxRatio{1.3} % Ratio width/(height+depth) \NewExpandableDocumentCommand{\zxChooseStyle}{mmmm}{% % #1=text,#2=empty style,#3=short style,#4=long style \savebox\zx@box{#1}% % Check if width is 0pt: \ifdimcomp{\wd\zx@box}{=}{0pt}{% Return empty style if box is empty #2% }{% Else compute size of thext % Check if height+depth < zxMaxDepthPlusHeight to see if short style applies \ifdimcomp{\dimexpr\dp\zx@box+\ht\zx@box\relax}{<}{\zxMaxDepthPlusHeight}{% % Check if width < ratio*(height+depth) to see if short style applies \ifdimcomp{\wd\zx@box}{<}{\dimexpr \zxMaxRatio\ht\zx@box + \zxMaxRatio\dp\zx@box\relax}{% #3% Short style is used }{ % Else #4% Long style is used } % }{ #4% Long style is used } }% }