Commutative diagrams and quantifiers

I encountered in Freyd and Scedrov's book "Categories, Allegories" a diagram of this sort: I wonder how to write this kind of diagram using tikz-cd, TikZ or any other combination of LaTeX packages.

EDIT:

Since I posted this question I came up with a more elementary solution (by means of a little research and a lot of monster bashing), because I needed a more straightforward way of producing this kind of diagram, but most of all, because I'm far from an expert at TikZ. I also forgot to mention that as the diagram is used for a definition, it can't be included as a figure, it has to be exactly where it's needed.

My solution is as follows:

\documentclass{tufte-book}

\usepackage{tikz-cd,scalerel,multirow}

%% Puncture mark for removing equations in diagrams

\def\punct{%
\tikz{
\draw (0.08,0) -- (0.18,0);
\draw (0,0.08) -- (0,0.18);
\draw (-0.08,0) -- (-0.18,0);
\draw (0,-0.08) -- (0,-0.18);
}
}

%quantifiers

\def\diagforall{%
\tikz{\draw (0,-1) -- (0,1);\node at (0,1.2) {$\forall$};}
}

\def\diagexists{%
\tikz{\draw (0,-1) -- (0,1);\node at (0,1.2) {$\exists$};}
}

\def\diagexun{%
\tikz{\draw (0,-1) -- (0,1);\node at (0,1.2) {$\exists !$};}
}

%% Larger \cdot

\def\Lcdot{%
\raisebox{-0.7ex}{\hstretch{2}{\vstretch{2}{\cdot}}}
}

\begin{document}

\begin{displaymath}
\begin{array}{ccccc}

%% Quantifiers

& \multirow{3}{*}{\diagforall} & & \multirow{3}{*}{\diagexun} & \\

%% Diagram in first column

\begin{tikzcd}

\Lcdot \ar{r} & \Lcdot \arrow[yshift=-0.9ex]{r}{\ast} \ar[yshift=0.9ex]{r} & \Lcdot

\end{tikzcd} & &

%% Diagram in third column

\begin{tikzcd}

& \Lcdot \ar{d}  & \\
\Lcdot \ar{r} & \Lcdot \arrow[yshift=-0.9ex]{r}{\ast} \ar[yshift=0.9ex]{r} & \Lcdot

\end{tikzcd}

& &

%% Diagram in last column

\begin{tikzcd}

& \Lcdot \ar{d} \ar{dl} & \\
\Lcdot \ar{r} & \Lcdot \arrow[yshift=-0.9ex]{r}{\ast} \ar[yshift=0.9ex]{r} & \Lcdot

\end{tikzcd} \\

%% This is padding

& & & & \\

\end{array}
\end{displaymath}

\end{document}

which produces the following output: By tweaking it a bit, I was able to produce which is what I was going for initially. Now, I had to change that puncture mark between the two horizontal arrows given that when I tried my little TikZ command it came out like this: Is there any way to make the little puncture mark work?

• Yes, add - as an option to the four lines. – Qrrbrbirlbel May 9 '15 at 21:37

Another solution, using MetaPost. I have included it in a LuaLaTeX program (MetaPost is sort of embedded in LuaTeX) for typesetting convenience. If you do not use LuaLaTeX, you can include the PDF figure resulting from this program in your own file, via the graphicx package. Or you can use the gmp package to include this code in a LaTeX/PDFLaTeX/XeLaTeX file.

Edit Following a remark of Barbara Beeton on Qrrbrbirlbel's answer, I have made the vertical lines and their markers bolder. To make the latter bold, I switched to the XITS fonts: contrary to the Latin Modern default fonts, the quantifiers symbols have a bold version in XITS.

\documentclass[border=2mm]{standalone}
\usepackage{unicode-math}
\setmainfont{XITS}
\setmathfont{XITS Math}
\usepackage{luamplib}
\begin{document}
\begin{mplibcode}
v := 1.75cm; len := 3bp; input boxes
def bullet = btex $\bullet$ etex enddef;
def cross = image(for angl = 0 step 90 until 270:
draw ((.5len, 0) -- (len, 0)) rotated angl; endfor)
enddef;
beginfig(1);
for i = 1 upto 9:
boxit.a[i](bullet); a[i].c = ((i-1)*v, 0); drawunboxed(a[i]);
endfor
for i = 1 upto 3:
boxit.cr[i](cross); cr[i].c = ((1.5+ 3(i-1))*v, 0); drawunboxed(cr[i]);
endfor
for i = 1 step 3 until 9:
drawarrow a[i].e -- a[i+1].w;
drawarrow a[i+1].ne -- a[i+2].nw; drawarrow a[i+1].se -- a[i+2].sw;
endfor
for i = 1,2:
boxit.u[i](bullet); u.[i]c = a[5+3(i-1)].c + (0, v);
drawunboxed(u[i]); drawarrow u[i].s -- a[5+3(i-1)].n;
endfor
drawarrow u2.sw -- a7.ne;
pickup pencircle;
draw (2.5v, 1.25v)--(2.5v, -.5v);
label.top(btex $\mathbf\forall$ etex, (2.5v, 1.25v));
draw (5.5v, 1.25v)--(5.5v, -.5v);
label.top(btex $\mathbf{\exists!}$ etex, (5.5v, 1.25v));
endfig;
\end{mplibcode}
\end{document} Here is a possible solution using xypic. Since I don't know that cross symbol for the double arrows, I used +. Afterwards, you can replace it.

\documentclass[11pt,a4paper]{report}
\usepackage{amsmath}
\usepackage[all,cmtip]{xy}
\usepackage{lipsum}

\begin{document}
\lipsum*
\begin{equation}
\begin{gathered}
\xymatrix@C=.5cm@R=.5cm{%
&&& \forall \ar@{-}[ddd] & &&& \exists! \ar@{-}[ddd] \\
&&& & & \bullet\ar[d]    & &&& \bullet\ar[d] \ar[dl]   \\
\bullet \ar[r] & \bullet \ar@<1ex>[r] \ar@<-1ex>[r] \ar@{}[r]|{+} &  \bullet &  & \bullet\ar[r] & \bullet \ar@<1ex>[r] \ar@<-1ex>[r] \ar@{}[r]|{+} & \bullet & & \bullet\ar[r] & \bullet \ar@<1ex>[r] \ar@<-1ex>[r] \ar@{}[r]|{+} & \bullet \\
&&& & &&&
}
\end{gathered}
\end{equation}
\lipsum*
\end{document} • It's better to use gathered for vertically centering an \xymatrix (it's more efficient). – egreg May 9 '15 at 9:16
• @egreg, thanks. I edited. Do you have some counter example? – Sigur May 9 '15 at 9:19
• The effect is the same, with gathered no alignment is used. – egreg May 9 '15 at 9:33
• in the original, the distance between the dots in the main line is uniform, and the long verticals sit halfway in between. in this rendition, the long verticals are positioned where a dot would be. not sure how easy that is to adjust with `xypic'. – barbara beeton May 9 '15 at 13:54
• @barbarabeeton, I don't think that the distance between the dots separated by the vertical rules are the same. But if I'm not wrong is possible to make a vertical line in the middle of the column in XYpic. I'll check. – Sigur May 9 '15 at 14:29

Code

\documentclass{standalone}
\usepackage{tikz-cd}
\usetikzlibrary{decorations.markings, arrows.meta, calc}
\tikzset{my Barb/.tip={Straight Barb[round,angle=45:1pt 3]}}
\tikzset{
plus mark/.style={-,
decorate, decoration={markings, mark=at position .5 with {
\draw[-,dash pattern=on #1 off 2*#1 on #1] (left:2*#1) -- (right:2*#1)
(up:2*#1) -- (down:2*#1);}}},
plus mark/.default=1pt}
\tikzcdset{
dots in cells/.style={
cells={nodes={shape=circle, fill, draw, inner sep=+0pt, minimum size=+3pt}}}}
\newcommand*\plar[r]{%
\arrow[#1, plus mark]
\arrow[#1, shift left=1.5]
\arrow[#1, shift right=1.5]}
\begin{document}
\begin{tikzcd}[dots in cells, cells={nodes={outer sep=+2pt}},
every arrow/.append style=-my Barb,
every matrix/.append style={name=M},
/tikz/execute at end picture={
\foreach \col/\t[evaluate={\Col=int(\col+1)}] in {3/\forall,6/\exists!}
\draw ([yshift=.2cm]perpendicular cs: horizontal line through={(M.north)},
vertical line through={($(M-2-\col)!.5!(M-2-\Col)$)})
node[above](@){$\t$}
-- ([yshift=-.3cm]@|-M.south);}]
&          &    &[-.5em]  & {} \dar  &    &[-.5em]    & {} \dar\dlar &   \\
{} \rar & {} \plar & {} & {} \rar & {} \plar & {} & {} \rar & {} \plar     & {}
\end{tikzcd}
\end{document}

Output • It is also possible to do the vertical lines in the same way as in Sigur’s answer (i.e. in seperate rows and columns of the matrix). – Qrrbrbirlbel May 9 '15 at 11:34
• i think the spacing to the left/right of the long verticals is closer here to the original; the distance between the horizontal dots in the main line is uniform there; there is no dot coincident with the long verticals. on the other hand, the long verticals and their "markers" appear bold(er) in the original. – barbara beeton May 9 '15 at 13:51