24

I have quite a lot of labels and references (around 250 labels, 600 references to those) in my document. As I need to re-arrange parts of the document, I'd like to know which labels are referenced from which parts (and, transitively, which are referenced by the referenced label etc.). In other words, I'd like to have a graphical representation of my document which only shows the names/numbers of the environments (proofs, lemmas, etc.) and the corresponding labels and references.

Example:

  • Lemma 2 -> Proof A, Proof B, Lemma 1
  • Proof B -> Proof C
  • Lemma 3 -> Lemma 2

How can I generate such a graph? I am only interested in the information conveyed by the graph, the graph itself will not be published and does not need to look nice.

13
+125

I took a look at my rdfref package, which wasn't easy, as I haven't written any documentation and there were also no comments in the source code. So I improved the situation, fixed some bugs, wrote some comments, but the documentation is still to be done.

rdfref is inspired with RDF, as name suggests. The idea is that every referencing command (\rdflabel, \rdfref, \rdfpageref) add some properties for a current subject in the form of

 subject attribute object

depending on the type of subject. The type of subject is based either on part of label before colon (so for \rdflabel{sec:hello} is the typesec`), or on containing environment:

\begin{lem}\rdflabel{thm:lem1}
\partOf{thm:thr1}
   A lemma. Reference to theorem\ref{thm:euclid}
\end{lem} 

In this case the subject type is lem. \partOf is custom command which states that this lemma is part of theorem thm:thr1.

Referencing commands defines another type of subject, so called blank node, so it is possible to search for such nodes and do some manipulation with them.

It is possible to specify added attributes for given subject type with \AddRdfType command:

\AddRdfType{lem}{%
\AddProperty{rdf:type}{thm:lemma}
\AddPropertyEx{doc:pageNo}{\thepage}
\AddPropertyEx{rdfs:label}{\@currentlabel\ \@currentlabelname}
}

Properties are added with \AddProperty and \AddPropertyEx commands. Some more properties are saved automatically by \rdflabel: doc:hasParent and doc:envir. All properties are saved in the aux file. If you search this file for thm:lem1 label, you will find this:

\LoadTriple {thm:lem1}{doc:hasParent}{sec:first}
\LoadTriple {thm:lem1}{doc:envir}{lem}
\LoadTriple {thm:lem1}{rdf:type}{thm:lemma}
\LoadTriple {thm:lem1}{doc:pageNo}{1}
\LoadTriple {thm:lem1}{rdfs:label}{1\ }
\LoadTriple {thm:lem1}{doc:partOf}{thm:thr1}

you can get value of any property with \GetPropery{subject}{property}, so \GetProperty{thm:lem1}{doc:pageNo} will print 1.

Important property is rdf:type, which all subjects should have assigned. The value of rdf:type should be subject of its own, with rdf:type set to rdfs:Class and some descriptive rdfs:label. It is also possible to define type hierarchy with rdfs:subClassOf. You need to set these properties inside \WithObject command, as these properties must be assigned only once. (\AddRdfType saves properties every time \rdflabel is called):

\WithObject{thm:lemma}{%
\AddProperty{rdfs:label}{Lemma}
\AddProperty{rdf:type}{rdfs:Class}
\AddProperty{rdfs:subClassOf}{thm:theorem}
}

thm:theorem class is defined as parent class in this example.

All these properties should be declared in so called ontology file, like this one theorems-ontology.tex for theorems:

\newcommand\partOf[1]{%
\AddPropertyEx{doc:partOf}{#1}
} 

\AddRdfType{Theorem}{%
\AddProperty{rdf:type}{thm:theorem}
\AddPropertyEx{doc:pageNo}{\thepage}
\AddProperty{rdfs:label}{\@currentlabel\ \@currentlabelname}
}
\AddRdfType{thr}{%
\AddProperty{rdf:type}{thm:theorem}
\AddPropertyEx{doc:pageNo}{\thepage}
\AddPropertyEx{rdfs:label}{\@currentlabel\ \@currentlabelname}
}
\AddRdfType{prop}{%
\AddProperty{rdf:type}{thm:proposition}
\AddPropertyEx{doc:pageNo}{\thepage}
\AddPropertyEx{rdfs:label}{\@currentlabel\ \@currentlabelname}
}

\AddRdfType{lem}{%
\AddProperty{rdf:type}{thm:lemma}
\AddPropertyEx{doc:pageNo}{\thepage}
\AddPropertyEx{rdfs:label}{\@currentlabel\ \@currentlabelname}
}


\AddRdfType{sec}{
\AddProperty{rdf:type}{sec:sectioning}
\AddPropertyEx{doc:pageNo}{\thepage}
\AddPropertyEx{rdfs:label}{\@currentlabel\ \@currentlabelname}
\AddPropertyEx{doc:label}{\@currentlabel}
}
\AddRdfType{equation}{%
\AddProperty{rdf:type}{eq:equation}
\AddPropertyEx{doc:pageNo}{\thepage}
\AddProperty{rdfs:label}{\@currentlabel\ \@currentlabelname}
}

%Add properties for classes
\WithObject{sec:sectioning}{%
\AddProperty{rdfs:label}{Sectioning}
\AddProperty{rdf:type}{rdfs:Class}
}
\WithObject{thm:theorem}{%
\AddProperty{rdfs:label}{Theorem}
\AddProperty{rdf:type}{rdfs:Class}
}
\WithObject{thm:proposition}{%
\AddProperty{rdfs:label}{Proposition}
\AddProperty{rdf:type}{rdfs:Class}
\AddProperty{rdfs:subClassOf}{thm:theorem}
}
\WithObject{thm:lemma}{%
\AddProperty{rdfs:label}{Lemma}
\AddProperty{rdf:type}{rdfs:Class}
\AddProperty{rdfs:subClassOf}{thm:theorem}
}

\WithObject{eq:equation}{%
\AddProperty{rdfs:label}{Equation}
\AddProperty{rdf:type}{rdfs:Class}
\AddProperty{rdfs:subClassOf}{thm:theorem}
}
\WithObject{rdfs:Class}{%
\AddProperty{rdfs:label}{Class}
}

now we can look at the document preamble:

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[]{tgschola}
\usepackage[T1]{fontenc}
\usepackage{hyperref}
\usepackage[]{rdfref-user,rdfref-query,lipsum,nameref,cleveref}
\usepackage{amsthm,thmtools,xstring}
\declaretheorem[name=Lemma,Refname={Lemma,Lemmas}]{lem}
\declaretheorem[name=Proposition,Refname={Proposition,Proposition}]{prop}
\declaretheorem[name=Theorem,Refname={Theorem,Theorems}]{thr}

thmtools package is used to define new theorem like environments lem, prop and thr. Now include the ontology and redefine \ref command to \rdfref, just to show that it works:

\begin{document}
\inputontology{theorem-ontology.tex}
\let\ref\rdfref

now some sample text with theorems (I am not a mathematician so it is pure nonsense, I just want to show some possibilities):

\section{Hello world}\rdflabel{sec:first}
\lipsum[1-2]
  \begin{lem}\rdflabel{thm:lem1}
    \partOf{thm:thr1}
    A lemma. Reference to theorem \ref{thm:euclid}
  \end{lem}

  \begin{prop}
    \rdflabel{thm:prop1}
    \partOf{thm:thr1}
    A proposition.
    %\renewcommand{\theenumi}{\thecor.\arabic{enumi}}
    \begin{enumerate}
      \item An item
      \item Another one
    \end{enumerate}
  \end{prop}

  \begin{thr}\rdflabel{thm:thr1}
    A theorem.
  \end{thr}

\begin{thr}[Euclid]
\rdflabel{thm:euclid}%
For every prime $p$, there is a prime $p’>p$.
In particular, the list of primes,
\begin{equation}\rdflabel{eq:1}
2,3,5,7,\dots
\end{equation}
is infinite.
\end{thr}

As it was said in theorem \ref{thm:euclid}, we see that 

In our ontology, we defined also sec type, so with \section{Hello world}\rdflabel{sec:first} subject of rdf:type sec:sectioning is added.

Now it is possible to make some fun with rdfref-query package. This package enables us to easily query our database. If we want to search for all theorem like subjects, we can use the fact that all of them have rdf:type property which is sub class of thm:theorem class. We can make simple command which looks for all subjects with rdfs:subClassOf= thm:theorem property and make list which can be used in the future:

\newcommand\buildtypelist[2]{%
\listadd#1{#2} % add searched
\Bind{?x}{rdfs:subClassOf}{#2}{%
% only direct children of #2 are taken into account
\listxadd#1{\GetVal{?x}}% must be global and expanded
}%
}

%
\buildtypelist\theoremlist{thm:theorem}

\Bind command is really useful. It takes four parameters, some of them may be unknown values (starting with ?) which are bind during search. First three parameters are subject, attribute and object, fourth is a function body which is executed for each found value.

So in this case, all subjects which have rdfs:subClassOf equal to thm:theorem are processed. etoolbox's command \listxadd is used to build a list. To get a value of bound variable, \GetVal command must be used.

With the list built, we can process all theorems with etoolbox's list looping commands:

\newcommand\MakeLabel[1]{%
\Bind{#1}{rdf:type}{?type}{% get type of parent
\textbf{\GetValProperty{?type}{rdfs:label}} % parent type label
}%
% now clickable reference to parent
\hyperref[\GetVal{#1}]{\GetValProperty{#1}{rdfs:label}}%
}
\renewcommand\do[1]{%
\Bind{?obj}{rdf:type}{#1}{%
% Prin basic info about the object
\par Object type:
\textbf{\GetValProperty{#1}{rdfs:label}}, % #1 is theorem type label
% now clickable reference to label of current object
value:\textbf{\hyperref[\GetVal{?obj}]{\GetValProperty{?obj}{rdfs:label}}},
% and just label
label: [\GetVal{?obj}].
% Print info about parent object:
\Bind{?obj}{doc:hasParent}{?par}{% parent label
\par \hspace{2em}Parent object:%
  \MakeLabel{?par}%
}%
\def\refinfo{\par\hspace{2em} Referenced by:\par\hspace{3em}}
\Bind{?ref}{doc:refersTo}{?obj}{%
 \refinfo\def\refinfo{\par\hspace{3em}}%
 \GetValProperty{?ref}{rdfs:label} in
 \Bind{?ref}{doc:hasParent}{?par}{%
\MakeLabel{?par}%
 }, p. \hyperpage{\GetValProperty{?ref}{doc:pageNo}};%
}%
}}
\dolistloop\theoremlist

This is complex example, which loops over all theorem types. \Bind{?obj}{rdf:type}{#1} will loop over all theorems of given type. New command is introduced \GetValProperty, which get property of bound variable. Helper macro \MakeLabel is used to print label for object. It is used for print info about parent subject (\Bind{?obj}{doc:hasParent}{?par}). References to given theorem are searched with \Bind{?ref}{doc:refersTo}{?obj}.

Full sample file can be found on rdfref page. Resulting information:

enter image description here

Now we can move to the graph: First define some auxilary macros:

% Now export a theorem graph

% Make expandable label
\newcommand\MakePlainLabel[1]{%
\GetProperty{\GetProperty{#1}{rdf:type}}{rdfs:label}
\GetProperty{#1}{rdfs:label}
}

we will use \MakePlainLabel to make labels for nodes

% Make list of used nodes, every node should be added only once
% #1 list csname #2 node prefix #3 subject
\newcommand\AddNode[3]{%
\ifcsdef{node@lbl@#2@#3}{}{%
\listxadd#1{#3}
\csgdef{node@lbl@#2@#3}{\MakePlainLabel{#3}}
}%
}

we need to add label only once, so we define a list and add each subject only once

% replace colons with underscores
\def\coltoun#1:#2;{#1_#2}% graphwiz doesn't support colon in names

\def\graphrelations{}

% connect nodes
% #1 source node #2 destination #3 graphviz style
\newcommand\AddRelation[3]{%
\edef\tempa{#1}%
\edef\tempb{#2}%
% add node label. we can call \AddNode for node multiple times,
% node is beeing added only once
\AddNode\mynodes{myn}{#1}%
\AddNode\mynodes{myn}{#2}%
% store relations in a macro
\xdef\graphrelations{%
\graphrelations \expandafter\coltoun\tempa; -> \expandafter\coltoun\tempb; [#3];^^J
}%
}

\AddRelation will add nodes labels, if the weren't used yet, and defines relation between the two.

Now we can make the actual graph. Idea is following: loop over all theorems and connect them with their parent objects. For theorems connected with \partOf command, use doc:partOf attribute, otherwise use doc:hasParent. Then loop over all references to given theorem, get parent objects and connect them to the theorem with dotted line.

\renewcommand\do[1]{%
\Bind{?obj}{rdf:type}{#1}{%
% select parent node. for lemmas etc, which use doc:partOf property,
% use that, otherwise use doc:has:parent
\IfProperty{\GetVal{?obj}}{doc:partOf}{%
\edef\parnode{\GetValProperty{?obj}{doc:partOf}}
}{
\edef\parnode{\GetValProperty{?obj}{doc:hasParent}}
}
\AddRelation{\GetVal{?obj}}{\parnode}{}
\Bind{?ref}{doc:refersTo}{?obj}{%
% select references to a theorem and print parent subject
\def\parnode{\GetValProperty{?ref}{doc:hasParent}}
\AddRelation{\parnode}{\GetVal{?obj}}{style=dotted}
}
}
}

% again loop over al theorems
\dolistloop\theoremlist

now we need some macros to store

graph in graphviz format to a file:

% now prepare output file for the graphviz output
\newwrite\graphwrite

% macros for opening and writing to the graph file
\newcommand\graphopen[1]{%
\immediate\openout\graphwrite=#1%
}

\newcommand\graphout[1]{\immediate\write\graphwrite{#1}}


\graphopen{\jobname.dot} % graphviz file name will be the same 
 % as input file name with .dot extension
\graphout{digraph hello\@charlb} % save graph header

% save labels
\renewcommand\do[1]{%
\graphout{\coltoun#1; [label="\MakePlainLabel{#1}"]}
}
\dolistloop\mynodes

% save graph relations
\graphout{\graphrelations}
\graphout{\@charrb} % save footer

after document processing with LaTeX, file filename.dot is saved:

digraph hello{
thm_thr1 [label="Theorem 1\  "]
sec_first [label="Sectioning 1\ Hello world "]
thm_euclid [label="Theorem 2\ Euclid "]
thm_lem1 [label="Lemma 1\  "]
thm_prop1 [label="Proposition 1\  "]
eq_1 [label="Equation 1\  "]
thm_thr1 -> sec_first [];
 thm_euclid -> sec_first [];
 thm_lem1 -> thm_euclid [style=dotted];
 sec_first -> thm_euclid [style=dotted];
 thm_prop1 -> thm_thr1 [];
 thm_lem1 -> thm_thr1 [];
 eq_1 -> thm_euclid [];

}

you can compile it with graphviz:

 dot -Tpng filename.dot -o filename.png

and the resulting graph:

enter image description here

4

pagereference package

There is the (undocumented and very old) pagereference package:

Pro­vides a mech­a­nism for record­ing the lo­ca­tion of la­bels placed in a doc­u­ment. The pack­age re­quires a two-pass pro­cess (it asks the user whether this is the “sec­ond pass”). The first pass es­tab­lishes where things are (writ­ing the val­ues of page la­bels to a .pgn file), the sec­ond pass fills in the ref­er­ences.

I didn't test it.

lablst-pkg package

There is also the (more recent) lablst-pkg package

A deriva­tive of the file lablst.tex (in the LaTeX dis­tri­bu­tion); em­beds it­self in \end{doc­u­ment} and prints, be­low the end of the doc­u­ment it­self, a list of la­bels used.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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