Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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:

An example graph

to get the following matrix representation of this relation:

Matrix representation

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

share|improve this question
1  
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

3 Answers 3

up vote 10 down vote accepted

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:

enter image description here

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}
share|improve this answer
    
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 :)

enter image description here

\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}
share|improve this answer

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

enter image description here

share|improve this answer
    
Note that as of September 2014, \prop_get:Nn has been renamed to \prop_item:Nn –  egreg yesterday

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.