Matrix from graph description
Here is one way to do it (with much room for improvement). Given a list of node relations:
\newcommand{\NodeRelations}{%
(1,1),
(1,2),
(1,5),
(2,1),
(2,3),
(2,5),
(3,2),
(3,4),
(4,3),
(4,5),
(4,6),
(5,1),
(5,2),
(5,4),
(6,4)
}%
you use the MyMatrix
environment and pass in dummy data:
\begin{MyMatrix}{\NodeRelations}
- & - & - & - & - & - \\
- & - & - & - & - & - \\
- & - & - & - & - & - \\
- & - & - & - & - & - \\
- & - & - & - & - & - \\
- & - & - & - & - & - \\
\end{MyMatrix}
which gets replaced with a 1
or 0
:
Code:
\documentclass{article}
\usepackage{pgffor}
\usepackage{xstring}
\usepackage{collcell}
\usepackage{etoolbox}
\newcounter{RowCount}
\newcounter{ColCount}
\newcommand*{\NextColumn}[1]{%
\addtocounter{ColCount}{1}%
\IfIsInNodeRelations{\arabic{ColCount}}{\arabic{RowCount}}{1}{0}%
}
\newcommand*{\FirstColumn}[1]{%
\setcounter{ColCount}{0}%
\addtocounter{RowCount}{1}%
\NextColumn{#1}%
}
\newtoggle{IsInNodeRelations}
\newcommand*{\IfIsInNodeRelations}[4]{%
\global\togglefalse{IsInNodeRelations}%
\foreach \Node in \NodeRelations {%
\StrBetween{\Node}{(}{,}[\x]
\StrBetween{\Node}{,}{)}[\y]
\IfEq{\x}{#1}{%
\IfEq{\y}{#2}{%
\global\toggletrue{IsInNodeRelations}%
\breakforeach%
}{}%
}{}%
}%
\iftoggle{IsInNodeRelations}{#3}{#4}
}
\newcommand{\NodeRelations}{%
(1,1),
(1,2),
(1,5),
(2,1),
(2,3),
(2,5),
(3,2),
(3,4),
(4,3),
(4,5),
(4,6),
(5,1),
(5,2),
(5,4),
(6,4)
}%
\newcommand*{\ExtractedX}{}%
\newcommand*{\ExtractedY}{}%
\def\ExtractXY(#1,#2){%
\xdef\ExtractedX{#1}%
\xdef\ExtractedY{#2}%
}%
\newenvironment{MyMatrix}[1]{%
% #1 = List of node relations
\newcolumntype{F}{>{\collectcell\FirstColumn}c<{\endcollectcell}}%
\newcolumntype{C}{>{\collectcell\NextColumn}c<{\endcollectcell}}%
\setcounter{RowCount}{0}
\setcounter{ColCount}{0}
$\left[\begin{array}{F C C C C C}%
}{%
\end{array}\right]$%
}%
\begin{document}
\begin{MyMatrix}{\NodeRelations}
- & - & - & - & - & - \\
- & - & - & - & - & - \\
- & - & - & - & - & - \\
- & - & - & - & - & - \\
- & - & - & - & - & - \\
- & - & - & - & - & - \\
\end{MyMatrix}
\end{document}
Looks like Peter has you covered, so here's a LuaLaTeX option just for comparison. You can pass the pairs directly, or store them in a macro and pass that. I left the option of using whichever array environment you prefer (i.e. bmatrix
, array
, pmatrix
etc.) I'm certain that my Lua could be improved, but this does the trick anyway :)
\documentclass{article}
\usepackage{luacode}
\usepackage{mathtools}
\begin{luacode*}
function adjmat(lst)
local edges = {}
local n = 0
for hit in string.gmatch(lst,"%b()") do
for r,c in string.gmatch(hit, "%((.+),(.+)%)") do
edges[tonumber(r)] = edges[tonumber(r)] or {}
edges[tonumber(r)][tonumber(c)] = 1
n = math.max(n,r,c)
end
end
for i = 1,n do
local mat = ""
edges[i] = edges[i] or {}
for j = 1,n do
edges[i][j] = edges[i][j] or 0
mat = mat..edges[i][j].."&"
end
tex.sprint(string.sub(mat,1,-2))
tex.print("\\\\")
end
end
\end{luacode*}
\def\adjmat#1{\directlua{adjmat("\luatexluaescapestring{#1}")}}
\begin{document}
\def\mymattwo{(1, 1),(1, 2),(1, 5),(2, 1),(2, 3),(2, 5),(3, 2),(3, 4),(4, 3),(4, 5),(4, 6),(5, 1),(5, 2),(5, 4),(6, 4)}
\[
\begin{bmatrix}
\adjmat{(1,1),(3,2),(4,5),(1,1),(2,1)}
\end{bmatrix}
\]
\[
\begin{bmatrix}
\adjmat\mymattwo
\end{bmatrix}
\]
\end{document}
Here's an expl3
implementation:
\documentclass{article}
\usepackage{xparse,amsmath}
\ExplSyntaxOn
\NewDocumentCommand{\definegraph}{ o m }
{
\IfNoValueTF{#1}
{
\graphs_define:nn { default } { #2 }
}
{
\msg_term:n { I'm~(re)defining~graph~#1 }
\graphs_define:nn { #1 } { #2 }
}
}
\tl_new:N \l__graphs_temp_tl
\seq_new:N \l__graphs_temp_seq
\int_new:N \l__graphs_count_int
\prop_new:N \g_graphs_list_prop
\cs_new_protected:Npn \graphs_define:nn #1 #2
{
% remove spaces
\tl_set:Nn \l__graphs_temp_tl { #2 }
\tl_remove_all:Nn \l__graphs_temp_tl { ~ }
% store the list of edges
\prop_gput:NnV \g_graphs_list_prop { #1 edges } \l__graphs_temp_tl
% get the number of nodes
\tl_remove_all:Nn \l__graphs_temp_tl { ( }
\tl_remove_all:Nn \l__graphs_temp_tl { ) }
\tl_replace_all:Nnn \l__graphs_temp_tl { , } { ; }
\seq_set_split:NnV \l__graphs_temp_seq { ; } \l__graphs_temp_tl
\seq_remove_duplicates:N \l__graphs_temp_seq
% store the number of nodes
\prop_gput:Nnx \g_graphs_list_prop { #1 length } { \int_to_arabic:n { \seq_count:N \l__graphs_temp_seq } }
}
\NewDocumentCommand{\adjacencymatrix} { O{default} }
{
\graphs_build_adjmatr:n { #1 }
}
\cs_new:Npn \graphs_build_adjmatr:n #1
{
% retrieve the list of nodes
\prop_get:NnN \g_graphs_list_prop { #1 edges } \l__graphs_temp_tl
% split the list into a sequence
\seq_set_split:NnV \l__graphs_temp_seq { ; } \l__graphs_temp_tl
% retrieve the number of nodes
\int_set:Nn \l__graphs_count_int { \prop_get:Nn \g_graphs_list_prop { #1 length } }
% start building the matrix
\tl_clear:N \l__graphs_temp_tl
% the outer loop indexes the rows, the inner loop the columns
\int_step_inline:nnnn { 1 } { 1 } { \l__graphs_count_int }
{
\int_step_inline:nnnn { 1 } { 1 } { \l__graphs_count_int }
{ \__graphs_put_coeff:nn { ##1 } { ####1 } }
\tl_put_right:Nn \l__graphs_temp_tl { \\ }
}
\begin{bmatrix}\l__graphs_temp_tl\end{bmatrix}
}
% An auxiliary function for the lower level code:
% add 1 if the edge is listed, add 0 otherwise;
% then place the & if not in the last column.
\cs_new:Npn \__graphs_put_coeff:nn #1 #2
{
\seq_if_in:NnTF \l__graphs_temp_seq { (#1,#2) }
{ \tl_put_right:Nn \l__graphs_temp_tl { 1 } }
{ \tl_put_right:Nn \l__graphs_temp_tl { 0 } }
\int_compare:nT { #2 < \l__graphs_count_int }
{ \tl_put_right:Nn \l__graphs_temp_tl { & } }
}
\ExplSyntaxOff
\begin{document}
\definegraph{(1,2);(1,3);(2,3);(4,5)}
$\adjacencymatrix$
\definegraph{(1,2);( 1,3) ;(2 , 3); ( 4 , 5)} % spaces are insignificant
$\adjacencymatrix$
\definegraph[IK]{
(1,1);
(1,2);
(1,5);
(2,1);
(2,3);
(2,5);
(3,2);
(3,4);
(4,3);
(4,5);
(4,6);
(5,1);
(5,2);
(5,4);
(6,4)
}
$\adjacencymatrix[IK]$
\end{document}
You can define and store any number of graph specifications. It would be possible to use a comma also to separate edge specifications, but I believe it's better to keep a distinction (more structure = more information).