Matrix from graph description

Are there any LaTeX package that draws/plots/generates a matrix from a "graph" description (node relations). Any type of description/language could be useful. The trick is to generate automaticly a matrix from a description of "relations".

For example, from the following "mathematical" relation:

(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)


which represents the next graph:

to get the following matrix representation of this relation:

Are there packages available for LaTeX to accomplish this type of "translation"? (from the mathematical relation to the matrix representation of its corresponding graph).

-
Could you be a little more specific as to what description language is? – Scott H. Nov 9 '12 at 3:37
I'have edited the ask. Perhaps now I explain it better. – Peregring-lk Nov 9 '12 at 10:35

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]{%
\IfIsInNodeRelations{\arabic{ColCount}}{\arabic{RowCount}}{1}{0}%
}
\newcommand*{\FirstColumn}[1]{%
\setcounter{ColCount}{0}%
\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}

-
Wow! Thank you so much. You, and in general users in this forum, impress me. – Peregring-lk Nov 9 '12 at 16:03

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*}
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*}

\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 } }
}

{
}
{
% 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:
% 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).

-
Note that as of September 2014, \prop_get:Nn has been renamed to \prop_item:Nn – egreg Sep 17 '14 at 17:58