%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Version: 2021/10/22 %%% 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,intersections} % 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}{2mm} \newcommand{\zxWRow}{2mm} %% Same as zxWCol, but when a single empty node is connected to a non-empty node. \newcommand{\zxwCol}{1mm} \newcommand{\zxwRow}{1mm} %% When vdots/dots are used in lines \newcommand{\zxDotsCol}{3mm} \newcommand{\zxDotsRow}{3mm} %% Default separation between rows and columns \newcommand{\zxDefaultColumnSep}{1.5mm} \newcommand{\zxDefaultRowSep}{1.5mm} % To cancel the default tow separation \newcommand{\zxZeroCol}{-\zxDefaultColumnSep} \newcommand{\zxZeroRow}{-\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} \newcommand{\zxNRow}{-\zxDefaultRowSep,.5mm} % Angles by default for s and o related arrows \def\zxDefaultSoftAngleS{30} \def\zxDefaultSoftAngleN{60} \def\zxDefaultSoftAngleO{40} \def\zxDefaultSoftAngleChevron{60} % Angles by default for s and o related arrows \def\zxDefaultSoftAngleS{30} \def\zxDefaultSoftAngleN{60} \def\zxDefaultSoftAngleO{40} \def\zxDefaultSoftAngleChevron{60} % Angles by default for s and o related arrows (in/out version) \def\zxDefaultSoftAngleN{60} \def\zxDefaultSoftAngleO{40} \def\zxDefaultSoftAngleChevron{60} % Styles for O,N,... (new bezier version) \tikzset{ /zx/args/-andL/.cd, defaultO/.style={-=.2,L=.4}, defaultN/.style={-=.2,L=.8}, defaultN-/.style={1-=.4,1L=0}, defaultNN/.style={}, defaultNIN/.style={1-=0,1L=.6}, defaultChevron/.style={}, % < should be stronger than N- also in ui mode. defaultChevronDown/.style={}, % The ^ v versions (default NN and default NIN will be loaded before). defaultS/.style={-=.8,L=0}, defaultS'/.style={-=.8,L=.2}, default-S/.style={1-=.8,1L=0}, defaultSIS/.style={1-=0,1L=.8}, % Loads the default styles for the "use intersection" method. /zx/args/-andL/ui/.style={ /zx/args/-andL/defaultO/.style={-=.2,L=.17}, /zx/args/-andL/defaultN/.style={-=.2,L=.7}, /zx/args/-andL/defaultN-/.style={1-=.5,1L=.2,2-=.2,2L=.5}, %% Todo: write a different style for < /zx/args/-andL/defaultNN/.style={}, /zx/args/-andL/defaultChevron/.style={1-=.2,1L=0,2-=.2,2L=.8}, /zx/args/-andL/defaultChevronDown/.style={1L=.2,1-=0,2L=.2,2-=.8}, /zx/args/-andL/defaultNIN/.style={1-=0,1L=.66,2-=.55,2L=.16}, /zx/args/-andL/defaultS/.style={-=.8,L=0}, /zx/args/-andL/defaultS'/.style={-=.8,L=.3}, /zx/args/-andL/default-S/.style={1-=.8,1L=0}, /zx/args/-andL/defaultSIS/.style={1-=0,1L=.8,2-=.15,2L=.6}, }, } % 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% } % Minus sign to use in \zxZ-{\alpha} %\NewExpandableDocumentCommand{\zxMinusInShort}{}{-} \NewExpandableDocumentCommand{\zxMinusInShort}{}{-} % The library tries to find intersection between fake center east/... and the border of the node % to draw the nodes directly on the border. % To enable this function (can also be set locally), enable this macro: % \def\zxEnableIntersectionsNodes{} %% To add the "name shape" on each node % \def\zxEnableIntersectionsWires{} %% For wires only (can't work without \zxEnableIntersectionsNodes) \newcommand{\zxEnableIntersections}{% \def\zxEnableIntersectionsWires{}% \def\zxEnableIntersectionsNodes{}% } % to disable intersections, undefined it: \let\zxEnableIntersectionsNodes\undefined \let\zxEnableIntersectionsWires\undefined \newcommand{\zxDisableIntersections}{% \let\zxEnableIntersectionsNodes\undefined% \let\zxEnableIntersectionsWires\undefined% } % Now, if it cannot find a good intersection (either because "name path" is disabled, or % because no intersection is found, or because intersections are disabled anyway) we need to % have a fallback mechanism. Either we choose instead the "fake center" (or center if fake % 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. % \let\zxWireInsideIfNoIntersectionName\undefined %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Adding anchors %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % We add anchors "fake center {north, south, east, west}" to the nodes. The wires will leave from these anchors (except in IO mode) depending on the direction. If the anchor does not exist, center is picked. % https://tex.stackexchange.com/questions/14769/add-more-anchors-to-standard-tikz-nodes \def\zx@pgfaddtoshape#1#2{% \begingroup \def\pgf@sm@shape@name{#1}% \let\anchor\pgf@sh@anchor #2% \endgroup } \def\zx@useanchor#1#2{\csname pgf@anchor@#1@#2\endcsname} \zx@pgfaddtoshape{rounded rectangle}{% \anchor{fake center east}{% \zx@useanchor{rounded rectangle}{north east}% \pgf@yc=.5\pgf@y% final y = 0.5*this y + 0.5*other y. \zx@useanchor{rounded rectangle}{south east}% \pgf@y=.5\pgf@y% \advance\pgf@y by \pgf@yc% }% \anchor{fake center west}{% \zx@useanchor{rounded rectangle}{north west}% \pgf@yc=.5\pgf@y% final y = 0.5*this y + 0.5*other y. \zx@useanchor{rounded rectangle}{south west}% \pgf@y=.5\pgf@y% \advance\pgf@y by \pgf@yc% }% \anchor{fake center north}{% \zx@useanchor{rounded rectangle}{center}% }% \anchor{fake center south}{% \zx@useanchor{rounded rectangle}{center}% }% } \zx@pgfaddtoshape{coordinate}{% \anchor{fake center east}{% \zx@useanchor{coordinate}{center}% }% \anchor{fake center west}{% \zx@useanchor{coordinate}{center}% }% \anchor{fake center north}{% \zx@useanchor{coordinate}{center}% }% \anchor{fake center south}{% \zx@useanchor{coordinate}{center}% }% } \zx@pgfaddtoshape{circle}{% \anchor{fake center east}{% \zx@useanchor{circle}{center}% }% \anchor{fake center west}{% \zx@useanchor{circle}{center}% }% \anchor{fake center north}{% \zx@useanchor{circle}{center}% }% \anchor{fake center south}{% \zx@useanchor{circle}{center}% }% } \zx@pgfaddtoshape{rectangle}{ \anchor{fake center east}{% \zx@useanchor{rectangle}{center}% }% \anchor{fake center west}{% \zx@useanchor{rectangle}{center}% }% \anchor{fake center north}{% \zx@useanchor{rectangle}{center}% }% \anchor{fake center south}{% \zx@useanchor{rectangle}{center}% }% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Tikz styles %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% For arguments later: \tikzset{ /zx/args/-andL/.cd, % - is "towards the point", or "x value", % L is "perpendicular to the line going towards the point" (L is for the perpendicular shape), or "y value". 1-/.initial=.5, % random value, defaultO... will change that. 2-/.initial=.5, -/.style={ 1-=#1, 2-=#1, }, 1L/.initial=.5, 2L/.initial=.5, L/.style={ 1L=#1, 2L=#1, }, symmetry-L/.code={% 1- <-> 1L, 2- <-> 2L \edef\zx@tmpone{\pgfkeysvalueof{/zx/args/-andL/1-}}% \edef\zx@tmptwo{\pgfkeysvalueof{/zx/args/-andL/2-}}% \pgfkeysalso{% 1-/.evaluated=\pgfkeysvalueof{/zx/args/-andL/1L}, 2-/.evaluated=\pgfkeysvalueof{/zx/args/-andL/2L}, 1L/.evaluated=\zx@tmpone, 2L/.evaluated=\zx@tmptwo, }% }, symmetry/.code={% 1- <-> 2-, 1L <-> 2L \edef\zx@tmpone{\pgfkeysvalueof{/zx/args/-andL/1-}}% \edef\zx@tmptwo{\pgfkeysvalueof{/zx/args/-andL/1L}}% \pgfkeysalso{ 1-/.evaluated=\pgfkeysvalueof{/zx/args/-andL/2-}, 1L/.evaluated=\pgfkeysvalueof{/zx/args/-andL/2L}, 2-/.evaluated=\zx@tmpone, 2L/.evaluated=\zx@tmptwo, }% }, negate1L/.style={ /zx/args/-andL/1L/.evaluated=-\pgfkeysvalueof{/zx/args/-andL/1L}, }, negate2L/.style={ /zx/args/-andL/2L/.evaluated=-\pgfkeysvalueof{/zx/args/-andL/2L}, }, negateL/.style={ negate1L, negate2L, }, negate1-/.style={ /zx/args/-andL/1-/.evaluated=-\pgfkeysvalueof{/zx/args/-andL/1-}, }, negate2-/.style={ /zx/args/-andL/2-/.evaluated=-\pgfkeysvalueof{/zx/args/-andL/2-}, }, negate-/.style={ negate1-, negate2-, }, negateL/.style={ negate1L, negate2L, }, oneMinus1-/.style={ /zx/args/-andL/2-/.evaluated=1-\pgfkeysvalueof{/zx/args/-andL/2-}, }, oneMinus2-/.style={ /zx/args/-andL/2-/.evaluated=1-\pgfkeysvalueof{/zx/args/-andL/2-}, }, oneMinus1L/.style={ /zx/args/-andL/1L/.evaluated=1-\pgfkeysvalueof{/zx/args/-andL/1L}, }, oneMinus2L/.style={ /zx/args/-andL/2L/.evaluated=1-\pgfkeysvalueof{/zx/args/-andL/2L}, }, % Angle/length: 1 angle and length/.code 2 args={% \pgfmathparse{#2*cos(#1)}% \pgfkeysalso{1-/.expand once=\pgfmathresult}% \pgfmathparse{#2*sin(#1)}% \pgfkeysalso{1L/.expand once=\pgfmathresult}% }, 2 angle and length/.code 2 args={% \pgfmathparse{#2*cos(#1)}% \pgfkeysalso{2-/.expand once=\pgfmathresult}% \pgfmathparse{#2*sin(#1)}% \pgfkeysalso{2L/.expand once=\pgfmathresult}% }, 1al/.style 2 args={ 1 angle and length={#1}{#2} }, 2al/.style 2 args={ 2 angle and length={#1}{#2} }, al/.style 2 args={ 1 angle and length={#1}{#2}, 2 angle and length={#1}{#2}, }, 1 angle/.style={ 1 angle and length={#1}{.6} }, 2 angle/.style={ 2 angle and length={#1}{.6} }, 1a/.style={ 1 angle={#1}, }, 2a/.style={ 2 angle={#1}, }, angle/.style={ 1 angle={#1}, 2 angle={#1}, }, a/.style={ 1 angle and length={#1}{.6}, 2 angle and length={#1}{.6}, }, } %%% Useful debug functions %% This function will be called when debugging the library. \def\zx@message#1{} % The ^^J adds a new line: \def\zx@verbose@message#1{\message{#1^^J}} % For more important messages. Like to show the code is not looping forever % To enable debugging: % WARNING: if you use in code, do not forget the makeatletter! %\def\zx@message#1{\message{#1^^J}} % To display stroke of while trying to compute the intersections: % WARNING: if you use in code, do not forget the makeatletter! %\def\zx@draw@stroke@inter@debug{} %% This function checks if the node has a "name path", if so it computes the intersection between %% if not if \zxWireInsideIfNoIntersectionName is defined it defines the \tikzto* to the %% new@center (argument #2), otherwise it does nothing. % #1: Node to consider: \tikztostart or \tikztotarget % #2: name of the new@center node corresponding to #1 % #3: name of the other new@center node % #4: result will be stored in this macro... if there is something to change. % #5: 1 if start, 2 if end % Result will be moved back into #1 \def\zx@find@intersection@fakecenter#1#2#3#4#5{% % First, we check if the user wants to compute the intersection: \ifdefined\zxEnableIntersectionsWires% %% We compute the intersection \edef\tikz@intersect@path@a{zx@name@path@#1}% \ifcsname tikz@intersect@path@name@\tikz@intersect@path@a \endcsname% \zx@verbose@message{[ZX] I will start computing intersections}% \pgfintersectionofpaths{% \begin{pgfinterruptboundingbox}% %%%% /!\ This lines is the one I'm not sure how to write: \expandafter\pgfsetpath\csname tikz@intersect@path@name@\tikz@intersect@path@a\endcsname% \pgfgetpath\temppath% \ifdefined\zx@draw@stroke@inter@debug% \pgfusepath{stroke} % We draw it, useful to debug, and realize the shape is moved. \fi% \pgfsetpath\temppath% \end{pgfinterruptboundingbox}% }{% The first path is moved to the center... So we need to shift it also here. %%% 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}}% \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. %% Parse once the control points for efficiency reasons: %% First parse the fake centers. \tikz@scan@one@point\pgf@process(#2)% \edef\zx@tmp@current@fake@x{\the\pgf@x}% \edef\zx@tmp@current@fake@y{\the\pgf@y}% \zx@message{The input fakes are #2 and #3.}% \tikz@scan@one@point\pgf@process(#3)% \edef\zx@tmp@other@fake@x{\the\pgf@x}% \edef\zx@tmp@other@fake@y{\the\pgf@y}% \zx@message{The parsed input fakes are (\zx@tmp@current@fake@x , \zx@tmp@current@fake@y) and (\zx@tmp@other@fake@x , \zx@tmp@other@fake@y).}% %% Reorder the controls to compute. #5 = 1 if "start fake center" is "current fake center". \ifnum#5=1 % <-- important space!!! \edef\zx@tmp@start@fake@x{\zx@tmp@current@fake@x}% \edef\zx@tmp@start@fake@y{\zx@tmp@current@fake@y}% \edef\zx@tmp@end@fake@x{\zx@tmp@other@fake@x}% \edef\zx@tmp@end@fake@y{\zx@tmp@other@fake@y}% \else% \edef\zx@tmp@end@fake@x{\zx@tmp@current@fake@x}% \edef\zx@tmp@end@fake@y{\zx@tmp@current@fake@y}% \edef\zx@tmp@start@fake@x{\zx@tmp@other@fake@x}% \edef\zx@tmp@start@fake@y{\zx@tmp@other@fake@y}% \fi% \zx@message{We computed: start fake (\zx@tmp@start@fake@x , \zx@tmp@start@fake@y) end fake (\zx@tmp@end@fake@x , \zx@tmp@end@fake@y )}% \pgfkeysalso{/zx/tmp/zx@getControlPoints={\zx@tmp@start@fake@x}{\zx@tmp@start@fake@y}{\zx@tmp@end@fake@x}{\zx@tmp@end@fake@y}}% % Now results are in controlOne, and controlTwo \ifnum#5=1 \relax% \def\zx@control{\controlOne}% \else% \def\zx@control{\controlTwo}% \fi% %%% Parse new control \tikz@scan@one@point\pgf@process(\zx@control)% \edef\zx@tmp@current@ctrl@x{\the\pgf@x}% \edef\zx@tmp@current@ctrl@y{\the\pgf@y}% \zx@message{[ZX] Current control is number #5, i.e. \zx@control (both are \controlOne and \controlTwo)}% % We store the center coordinates since it's used several times \pgfpointanchor{#1}{center}% \edef\zx@tmp@real@center@x{\the\pgf@x}% \edef\zx@tmp@real@center@y{\the\pgf@y}% %%% Go to current fake center, except that real center is the new origin. \pgfpointdiff{\pgfpoint{\zx@tmp@real@center@x}{\zx@tmp@real@center@y}}{\pgfpoint{\zx@tmp@current@fake@x}{\zx@tmp@current@fake@y}}% \pgfpathmoveto{\pgfpoint{\pgf@x}{\pgf@y}}% %% What, now both axis are inverted??? If someone can explain me this... %% We scale the point to force it to cross the boundary. \pgfpathlineto{% \pgfpointadd{% \pgf@process{% \pgfpointscale{10}{% \pgf@process{% \pgfpointdiff{% \pgfpoint{\zx@tmp@current@fake@x}{\zx@tmp@current@fake@y}% }{% \pgfpoint{\zx@tmp@current@ctrl@x}{\zx@tmp@current@ctrl@y}% }% }% }% }% }{% \pgfpointdiff{% \pgfpoint{\zx@tmp@real@center@x}{\zx@tmp@real@center@y}% }{% \pgfpoint{\zx@tmp@current@fake@x}{\zx@tmp@current@fake@y}% }% }% }% \fi% \pgfgetpath\temppath% \ifdefined\zx@draw@stroke@inter@debug% \pgfusepath{stroke}% We draw it, useful to debug, and realize the shape is moved. \fi% \pgfsetpath\temppath% \end{pgfinterruptboundingbox}% }% \pgfintersectionsolutions% \pgfpointintersectionsolution{1}% \ifnum\pgfintersectionsolutions=1%% The good number of solution has been found! \zx@message{[ZX] Cool, just found one solution!} %% Store the intersection (warning: the center of the shape is moved to the center!) \edef\zx@relinter@x{\the\pgf@x}% \edef\zx@relinter@y{\the\pgf@y}% %% Because the shape was moved to center, we shift it back by adding the coord of the shape: \pgfextractx\pgf@xa{\pgfpointanchor{#1}{center}}% \pgfextractx\pgf@xb{\pgfpointanchor{#1}{center}}% % WARNING! pgfmath removes the dimension (converted in pt). Make sure to put them back after \pgfmathsetmacro{\zx@inter@x}{\pgf@x+\zx@relinter@x}% \pgfmathsetmacro{\zx@inter@y}{\pgf@y+\zx@relinter@y}% \edef#4{\zx@inter@x pt,\zx@inter@y pt}% \else% The bad number of solution has been found \zx@message{[ZX] WARNING: expecting one solution, found \pgfintersectionsolutions}% \ifdefined\zxWireInsideIfNoIntersectionName% % No intersection was found, but still want to use fake center (or center). % ==> The wire will be inside the shape % Basically \tikztostart := tikztostart@new@center \edef#4{#2}% \fi% Otherwise, do nothing \fi% \else% \zx@message{ZX: no path named \tikz@intersect@path@a was found.}% \ifdefined\zxWireInsideIfNoIntersectionName% % No intersection was found, but still want to use fake center (or center). % ==> The wire will be inside the shape % Basically \tikztostart := tikztostart@new@center \edef#4{#2}% \fi% Otherwise, do nothing \fi% \else% \zx@message{[ZX]: intersection mechanism disabled}% \ifdefined\zxWireInsideIfNoIntersectionName% % No intersection was found, but still want to use fake center (or center). % ==> The wire will be inside the shape % Basically \tikztostart := tikztostart@new@center \edef#4{#2}% \fi% Otherwise, do nothing \fi% }% % 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...) in IO mode between none/.style={ looseness wires only, wire centered }, bn/.style={ between none }, % To debug the bezier curve. edge above/.code={% \def\zxEdgesAbove{}% },% edge not above/.code={% \let\zxEdgesAbove\undefined% }, control points visible/.code={% \def\zxControlPointsVisible{}% },% control points not visible/.code={% \let\zxControlPointsVisible\undefined% }, % See explaination at the beginning where we define \def\zxEnableIntersectionsWires{} % Rouhgly, tries to start the wires on the border of the shape on the line between the % fake anchors. use intersections/.code={% \def\zxEnableIntersectionsWires{}% }, dont use intersections/.code={% \let\zxEnableIntersectionsWires\undefined% }, ui/.style={ use intersections, /zx/args/-andL/ui }, intersections mode between start end/.code={% \def\zxIntersectionLineBetweenStartEnd{}% }, intersections mode bezier controls/.code={% \let\zxIntersectionLineBetweenStartEnd\undefined% }, wires behind nodes/.code={% \def\zxWireInsideIfNoIntersectionName{}% }, no wires behind nodes/.code={% \let\zxWireInsideIfNoIntersectionName\undefined% }, intersection between start end/.code={ \def\zxIntersectionLineBetweenStartEnd{}% }, intersection bezier control/.code={ \let\zxIntersectionLineBetweenStartEnd\undefined% }, % ------------------------------ % 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 } }, % At the first version, styles were defined using in=... out=... looseness=... However % it gives sometimes bad results (like the curve goes forward at some points) when nodes are % 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 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, %%% bezier{px1}{py1}{px2}{py2} creates a bezier curve where px1/py1 are the %%% coordinates of the first control (in "percentage" 0 1 - (2-) oneMinus2-, }, }, o./.style={% left to right, bezier x={% /zx/args/-andL/.cd, defaultO, ##1, %% 2- --> 1 - (2-) oneMinus2-, negate1L, negate2L, },% }, -o/.style={% up to down, bezier y={% /zx/args/-andL/.cd, defaultO, ##1, /zx/args/-andL/2-/.evaluated=1-\pgfkeysvalueof{/zx/args/-andL/2-}, symmetry-L, } }, o-/.style={% up to down, bezier y={% /zx/args/-andL/.cd, defaultO, ##1, /zx/args/-andL/2-/.evaluated=1-\pgfkeysvalueof{/zx/args/-andL/2-}, /zx/args/-andL/1L/.evaluated=-\pgfkeysvalueof{/zx/args/-andL/1L}, /zx/args/-andL/2L/.evaluated=-\pgfkeysvalueof{/zx/args/-andL/2L}, symmetry-L, }, }, % Similar to o, but can be used also for diagonal items. Combine it with % The dot versions are mode logic in "left to right", and the others for up to down (possible to change) % Can combine with "force left to right"... (/.style={ bend right=##1, }, (/.default=30, )/.style={ bend left=##1, }, )/.default=30, ('/.style={ bend left=##1 }, ('/.default=30, (./.style={ bend right=##1 }, (./.default=30, %%%% 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). %% Nbase will be reused later by < > shapes as well. It's useful to make a distinction between N and %% Nbase when user will want to overwrite N without overwritting < >. Nbase/.style={ left to right, bezier={ /zx/args/-andL/.cd, defaultN, ##1, oneMinus2-, oneMinus2L, }, }, N/.style={Nbase={##1}}, % With this model, we don't need differences between N' and N. so we can also call it N. % But keep other notations to allow easy style change (to use IO again for instance). N'/.style={N={##1}}, N./.style={N={##1}}, -N/.style={N={defaultN-,##1}}, -N'/.style={-N={##1}}, -N./.style={-N={##1}}, N-/.style={-N'={symmetry,##1}}, N'-/.style={N-={##1}}, N.-/.style={N-={##1}}, %% Up to down version NN/.style={N'={symmetry-L,defaultNN,##1},up to down}, NN./.style={NN={##1}}, .NN/.style={NN={##1}}, NIN/.style={NN={defaultNIN,##1}}, INN/.style={NIN={symmetry,##1}}, NNI/.style={INN={##1}}, %%% <' is basically like -N' (historically < was first), we just put an anchor on the east/.... <'/.style={Nbase={defaultN,defaultN-,defaultChevron,symmetry,##1},end anchor=west}, <./.style={<'={##1}}, % Don't use <>^ alone char as style name, it could be useful later for other shortcuts % (replacement directions) '>/.style={Nbase={defaultN,defaultN-,defaultChevron,##1},start anchor=east}, .>/.style={'>={##1}}, ^./.style={ Nbase={defaultN,defaultN-,defaultChevron,symmetry-L,defaultNN,defaultNIN,defaultChevronDown,symmetry,##1}, end anchor=north }, .^/.style={^.={##1}}, 'v/.style={ Nbase={defaultN,defaultN-,defaultChevron,symmetry-L,defaultNN,defaultNIN,defaultChevronDown,##1}, start anchor=south }, v'/.style={'v={##1}}, %%%% Links with a s-like shape. s/.style={ left to right, bezier={% /zx/args/-andL/.cd, defaultS, ##1, oneMinus2-, oneMinus2L, } }, % like S, but with anchor east and west S/.style={ s={##1}, start anchor=east, end anchor=west }, % -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={s={defaultS',##1}}, s./.style={s'={##1}}, -s/.style={s'={default-S,##1}}, -s'/.style={-s={##1}}, % To fit with s' notation -s./.style={-s={##1}}, s-/.style={-s'={symmetry,##1}}, s'-/.style={s-={##1}}, s.-/.style={s-={##1}}, % Anchor more marked S/.style={s={##1}, start anchor=east, end anchor=west,}, -S/.style={-s'={##1},start anchor=east}, -S'/.style={-S={##1}}, -S./.style={-S={##1}}, S-/.style={s'-={##1},end anchor=west}, S'-/.style={S-={##1}}, S.-/.style={S-={##1}}, %%%% Doubling = up to down. % Links with a s-like shape... but read from top to bottom ss/.style={s={symmetry-L,##1},up to down}, SS/.style={ss={##1}, start anchor=south, end anchor=north}, % -s'.- shapes are like s, but with a soften (customizable like o) angle. % The '. say if you are going up or down, and 'I' forces a sharp angle (I is flat) on the side of the I ss./.style={s.={symmetry-L,##1},up to down}, .ss/.style={ss.={##1}}, sIs/.style={ss={defaultSIS,##1}}, sIs./.style={ss.={defaultSIS,##1}}, .sIs/.style={sIs.={##1}}, Iss/.style={sIs={symmetry,##1}}, ssI/.style={Iss={##1}}, ss.I/.style={sIs.={symmetry,##1}}, I.ss/.style={ss.I={##1}}, SIS/.style={sIs={##1},start anchor=south}, .SIS/.style={.sIs={##1},start anchor=south}, ISS/.style={ssI={##1},end anchor=north}, SS.I/.style={ss.I={##1},end anchor=north}, I.SS/.style={SS.I={##1}}, SSI/.style={ISS={##1}}, % At the first version, styles were defined using in=... out=... looseness=... However % it gives sometimes bad results (like the curve goes forward at some points) when nodes are % 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]. IO/.style={ 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}{$\cvdotsCenterMathline$}" 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,##1}}, H/.default={}, Z/.style={"" {zxNoPhaseSmallZ,anchor=center,##1}}, 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 % 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, }, % Used to compute the intersection with the node's boundary allow boundary intersection/.code={% \ifdefined\zxEnableIntersectionsNodes% \edef\zx@name@path{zx@name@path@\tikz@fig@name}% \zx@message{[ZX] The name of the path will be \zx@name@path.}% \pgfkeysalso{ name path=\zx@name@path, % Used by intersection library }% \fi% }, % Will be specific to all spiders zxSpiders/.style={ draw=black, allow boundary intersection,% Used later to do math on it. }, % 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}$ or $- \alpha$ 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{emptyStyle}{ShortStyle}{LongStyle}{label style}{node content} add@Phase@Spider/.style n args={5}{% zx@emptyStyle/.style={##1}, zx@shortStyle/.style={##2}, zx@notEmptyStyle/.style={##3}, zx@labelStyle/.style={##4}, /zx/zx@content/.initial={##5}, 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={5}{ zx@commandToExecuteVeryEnd/.try={##1}{##2}{##3}{##4}{##5}, }, 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={5}{% execute at begin node={####5},% ####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,% }% }{% We check if we need to force "short mode" (zxShort instead of zxLong) \ifthenelse{\equal{\pgfkeysvalueof{/zx/zx@shortModeForced}}{true}}{% \pgfkeysalso{% zx@shortStyle,% }% }{% Otherwise, just use the default style. \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={5}{% ####4: label style, ####5: content % Checks if the content (stored by add@Phase@Spider in /zx/zx@content) is empty or not \ifthenelse{\equal{####5}{}}{% Content is empty }{% Content is not empty \pgfkeysalso{ label={[####4,##1] ####5},% }% }% },% 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 \zxZ4{...} and \zxX4{...} 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 the minus mode: "-" for minus sign, which forces short mode. %%% Third argument is "*" for forced short mode. %%% 4th argument is content of node. zx@spider/.code n args={8}{ %% ##1: zxnophase style %% ##2: zxshort style %% ##3: zxlong style %% ##4: label style %% user provided: %% ##5: additional tikz options %% ##6: minus "-" or empty, like "-alpha" %% ##7: star "*" or empty, to force short mode %% ##8: content %%% The argument is a minus. Like \zxZ-{\alpha}, goal is to typeset "-\alpha" in short mode. \ifthenelse{\equal{##6}{-}}{% It's a minus! \pgfkeysalso{% We update the content to "-content" /zx/zx@shortModeForced/.initial={true},% }% }{}% \ifthenelse{\equal{##7}{*}}{% We force short mode! \pgfkeysalso{% /zx/zx@shortModeForced/.initial={true},% }% }{}% % It's a minus, and LaTeX is... grrrr. How to get a cleaner code? Tried def/let, not working. \ifthenelse{\equal{##6}{-}}{% \pgfkeysalso{% add@Phase@Spider={##1}{##2}{##3}{##4}{\zxMinusInShort##8},% }% }{% \pgfkeysalso{% add@Phase@Spider={##1}{##2}{##3}{##4}{##8},% }% }% \pgfkeysalso{% /zx/post preparation labels, /zx/user post preparation labels, % /zx/user overlay nodes, ##5, }% \ifthenelse{\equal{##6}{-}}{% It's a minus, and LaTeX is... grrrr \pgfkeysalso{% zx@Execute@Very@End={##1}{##2}{##3}{##4}{\zxMinusInShort##8},% }% }{% \pgfkeysalso{% zx@Execute@Very@End={##1}{##2}{##3}{##4}{##8},% }% }% }, %% ##1: additional tikz options %% ##2: minus "-" or empty, like "-alpha" %% ##3: star "*" or empty, to force short mode %% ##4: content zxZ4/.style n args={4}{ zx@spider={zxNoPhaseZ}{zxShortZ}{zxLongZ}{stylePhaseInLabelZ}{##1}{##2}{##3}{##4} }, zxX4/.style n args={4}{ zx@spider={zxNoPhaseX}{zxShortX}{zxLongX}{stylePhaseInLabelX}{##1}{##2}{##3}{##4} }, %% 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={ %tiny depends on the size of the font... which we want to keep consistent look column sep=\zxDefaultColumnSep, row sep=\zxDefaultRowSep, zx column sep/.code={% \def\zxDefaultColumnSep{##1}% \pgfkeysalso{ column sep=##1, }% }, zx row sep/.code={% \def\zxDefaultRowSep{##1}% \pgfkeysalso{% row sep=##1, }% }, %column sep=tiny, %row sep=tiny, % center on the math axis baseline={([yshift=-axis_height]current bounding box.center)}, % Fix 1-row diagram baseline % By default, 1-row diagrams have a different baseline... This package does not want a special case for 1-row diagrams. 1-row diagram/.style={}, %% usage: math baseline=wantedBaseline, where you have somewhere \zxX[a=wantedBaseline]{\beta} math baseline/.style={baseline={([yshift=-axis_height]##1)}}, %%% 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}}; } }, % 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,% }% %% name path won't work with alias... So let's create two name path ^^ %% https://tex.stackexchange.com/questions/619622 \ifdefined\zxEnableIntersectionsNodes% \edef\zx@name@path{zx@name@path@####1}% \zx@message{[ZX] Name given using an alias: \zx@name@path.}% \pgfkeysalso{ name path=\zx@name@path, % Used by intersection library }% \fi% \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% }% } % 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{ \pgfutil@ifundefined{pgf@anchor@#1@#2}{% #4% }{% #3% }% } % node name, anchor name, if exists, if not. \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} } %%% 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 functions to nest diagrams %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \NewDocumentCommand{\zxSaveDiagram}{mO{}m}{ \newsavebox{#1}% \savebox{#1}{\begin{ZX}[ampersand replacement=\&,#2]#3\end{ZX}}% } \NewDocumentCommand{\zxUseDiagram}{m}{ \usebox{#1}% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% 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}{$\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] |[zxNone+,inner xsep=0pt]| \makebox[0pt][r]{\scalebox{#2}{$\cvdotsCenterMathline$}}\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,"\cvdotsCenterMathline" {scale=.6,anchor=north,yshift=-0.25mm},#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{}t*t-m}{ |[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}]| % } \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% \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}% }% \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 }% }% }