michal-h21 / rdfref

Cross-referencing system for LaTeX, inspired with RDF
16 stars 3 forks source link

Dependency graph of equations? #9

Open ouboub opened 3 weeks ago

ouboub commented 3 weeks ago

Hi

would it be possible to support equations in the dependency graph. Here are two images, both generated, manually, with quiver

equation12

michal-h21 commented 3 weeks ago

This could be a start:

\documentclass{article}
\usepackage{amsmath}
\numberwithin{equation}{section}
\usepackage{rdfref}
\begin{document}

% we need to declare some properties for the eq: prefix 
\AddRdfType{eq}{
  \AddPropertyEx{rdf:type}{eq:equation}
  \AddPropertyEx{doc:pageNo}{\thepage}
  % this will be used in the graph label, change to your liking
  \AddPropertyEx{rdfs:label}{Equation \theequation}
}

\section{first section}
\rdflabel{sec:first}
\begin{equation}
  a = b + c
  % each label for equation must use the eq: prefix
  \rdflabel{eq:hello}
\end{equation}

This equation links to equation~\rdfref{eq:second}, as well as to equation~\rdfref{eq:third}.

\section{another}
\rdflabel{sec:another}

\begin{equation}
  a = d + c 
  \rdflabel{eq:second}
\end{equation}

Link to another equation~\rdfref{eq:third}

\begin{equation}
  d = x + y
  \rdflabel{eq:third}
\end{equation}

\newwrite\graphwrite
\immediate\openout\graphwrite=\jobname.dot

\makeatletter
\newcommand\graphout[1]{\protected@write\graphwrite{}{#1}}

\graphout{digraph hello\@charlb} % save graph header

% loop over all equation object
\Bind{?curreq}{rdf:type}{eq:equation}{%
  % find all \rdfref objects that points to the equation
  \Bind{?curreq}{doc:referedBy}{?blank}{%
    % now we need to find the parent object of \rdfref
    \Bind{?blank}{doc:hasParent}{?parent}{
      % this will filter only equations
      \Bind{?parent}{rdf:type}{eq:equation}{%
        \noindent Equation \GetValProperty{?curreq}{rdfs:label} is referenced by \GetValProperty{?parent}{rdfs:label}\par%
        \graphout{"\GetValProperty{?parent}{rdfs:label}" -> "\GetValProperty{?curreq}{rdfs:label}"}

      }
    }
  }%
}

\graphout{\@charrb} % save footer
\closeout\graphwrite
\makeatother

\end{document}

You need to update rdfref, because I made a change that save the current object outside environments.

This is the result:

image

It saves the DOT file to \jobname.dot:

digraph hello{
"Equation 1.1" -> "Equation 2.1"
"Equation 1.1" -> "Equation 2.2"
"Equation 2.1" -> "Equation 2.2"
}

image

ouboub commented 3 weeks ago

"MH" == Michal Hoftich @.***> writes:

This could be a start:

\documentclass{article}
\usepackage{amsmath}
\numberwithin{equation}{section}
\usepackage{rdfref}
\begin{document}

% we need to declare some properties for the eq: prefix 
\AddRdfType{eq}{
  \AddPropertyEx{rdf:type}{eq:equation}
  \AddPropertyEx{doc:pageNo}{\thepage}
  % this will be used in the graph label, change to your liking
  \AddPropertyEx{rdfs:label}{Equation \theequation}
}

\section{first section}
\rdflabel{sec:first}
\begin{equation}
  a = b + c
  % each label for equation must use the eq: prefix
  \rdflabel{eq:hello}
\end{equation}

This equation links to equation~\rdfref{eq:second}, as well as to equation~\rdfref{eq:third}.

\section{another}
\rdflabel{sec:another}

\begin{equation}
  a = d + c 
  \rdflabel{eq:second}
\end{equation}

Link to another equation~\rdfref{eq:third}

\begin{equation}
  d = x + y
  \rdflabel{eq:third}
\end{equation}

\newwrite\graphwrite
\immediate\openout\graphwrite=\jobname.dot

\makeatletter
***@***.***\graphwrite{}{#1}}

\graphout{digraph ***@***.***} % save graph header

% loop over all equation object
\Bind{?curreq}{rdf:type}{eq:equation}{%
  % find all \rdfref objects that points to the equation
  \Bind{?curreq}{doc:referedBy}{?blank}{%
    % now we need to find the parent object of \rdfref
    \Bind{?blank}{doc:hasParent}{?parent}{
      % this will filter only equations
      \Bind{?parent}{rdf:type}{eq:equation}{%
        \noindent Equation \GetValProperty{?curreq}{rdfs:label} is referenced by \GetValProperty{?parent}{rdfs:label}\par%
        \graphout{"\GetValProperty{?parent}{rdfs:label}" -> "\GetValProperty{?curreq}{rdfs:label}"}

      }
    }
  }%
}

***@***.***} % save footer
\closeout\graphwrite
\makeatother

\end{document}

You need to update rdfref, because I made a change that save the current object outside environments.

This is the result:

Thanks very much

It saves the DOT file to \jobname.dot:

digraph hello{
"Equation 1.1" -> "Equation 2.1"
"Equation 1.1" -> "Equation 2.2"
"Equation 2.1" -> "Equation 2.2"
}

But if I insert math in that dot file manually like digraph hello{ "$\int f dx$" -> "Equation 2.1" "Equation 1.1" -> "Equation 2.2" "Equation 2.1" -> "Equation 2.2" }

It will be displayed literally, but that I presume is a limitation of the dot format, right?

Thanks

michal-h21 commented 3 weeks ago

You can convert dot to LaTeX using dot2tex, this variant should keep LaTeX math:

 $ dot2tex --figonly sample.dot  -t raw filename.tex > graph.tex

The problem is how to save contents of equations. This version defines new environment rdfequation, which can do that. The label is passed as an optional argument:

\documentclass{article}
\usepackage{amsmath}
\numberwithin{equation}{section}
\usepackage{tikz}
% \usepgflibrary{path}
% \usepgflibrary{graphdrawing}
\usepackage{rdfref}
\NewDocumentEnvironment{rdfequation}{o +b}{
  \begin{equation}
    #2 
    \IfBlankF{#1}{
      \rdflabel{#1}
      \AssignProperty{#1}{eq:value}{$$#2$$}
    }
  \end{equation}
}{}
\begin{document}

% we need to declare some properties for the eq: prefix 
\AddRdfType{eq}{
  \AddPropertyEx{rdf:type}{eq:equation}
  \AddPropertyEx{doc:pageNo}{\thepage}
  % this will be used in the graph label, change to your liking
  \AddPropertyEx{rdfs:label}{Equation \theequation}
}

\section{first section}
\rdflabel{sec:first}
\begin{rdfequation}[eq:hello]
  a = b + c
  % each label for equation must use the eq: prefix
  % \rdflabel{eq:hello}
\end{rdfequation}

This equation links to equation~\rdfref{eq:second}, as well as to equation~\rdfref{eq:third}.

\section{another}
\rdflabel{sec:another}

\begin{rdfequation}[eq:second]
  a = d + c 
  % \rdflabel{eq:second}
\end{rdfequation}

Link to another equation~\rdfref{eq:third}

\begin{rdfequation}[eq:third]
  d = x + y
  % \rdflabel{eq:third}
\end{rdfequation}

\newwrite\graphwrite
\immediate\openout\graphwrite=\jobname.dot

\makeatletter
\newcommand\graphout[1]{\protected@write\graphwrite{}{#1}}

% \AssignProperty{eq:third}{rdfs:label}{\detokenized{$a=b^2$}}

\graphout{digraph hello\@charlb} % save graph header

% loop over all equation object
\Bind{?curreq}{rdf:type}{eq:equation}{%
  % find all \rdfref objects that points to the equation
  \Bind{?curreq}{doc:referedBy}{?blank}{%
    % now we need to find the parent object of \rdfref
    \Bind{?blank}{doc:hasParent}{?parent}{
      % this will filter only equations
      \Bind{?parent}{rdf:type}{eq:equation}{%
        \noindent Equation \GetValProperty{?curreq}{rdfs:label} is referenced by \GetValProperty{?parent}{rdfs:label}\par%
        \graphout{"\GetValProperty{?parent}{eq:value}" -> "\GetValProperty{?curreq}{eq:value}"}
      }
    }
  }%
}

\graphout{\@charrb} % save footer
\closeout\graphwrite

\makeatother

\InputIfFileExists{graph.tex}{}

\end{document}

image

ouboub commented 2 weeks ago

Hi

thanks so much sorry for delay (I cought Covid a couple of days ago)

  1. I saved your file as sample.tex
  2. I run pdflatex twice on that file
  3. then I run dot2tex --figonly sample.dot -t raw filename.tex > graph.tex
  4. but I obtained an error (which does not surprise that much because filename.tex does not exist, but I don't know dot2tex so much the error is
    sage: dot2tex [-h] [-f v] [-t {math,verbatim,raw}] [-d] [-s]
               [--template FILE] [-o FILE] [--force] [-e {utf8,latin1}] [-V]
               [-w] [-p] [--margin MARGIN] [--docpreamble TEXCODE]
               [--figpreamble TEXCODE] [--figpostamble TEXCODE]
               [--graphstyle STYLE] [--gvcols] [--figonly] [--codeonly]
               [--styleonly] [--debug] [--preproc] [--alignstr ALIGNSTR]
               [--valignmode {center,dot}] [--nominsize] [--usepdflatex]
               [--tikzedgelabels] [--nodeoptions OPTIONS]
               [--edgeoptions OPTIONS] [--runtests] [--prog v]
               [--progoptions OPTIONS] [--autosize] [--cache] [--pgf118]
               [--pgf210]
               [inputfile]
    dot2tex: error: unrecognized arguments: filename.tex

    sorry for this elementary question, but what do I miss?

ouboub commented 2 weeks ago

ok I just checked on my Ubuntu 24.04 sudo apt-get dot2tex gives me strange errors of the sort

Setting up dot2tex (2.11.3-4) ...
/usr/lib/python3/dist-packages/dot2tex/dot2tex.py:900: SyntaxWarning: invalid escape sequence '\i'
  variables['<<gvcols>>'] = "\input{gvcols.tex}"
/usr/lib/python3/dist-packages/dot2tex/dot2tex.py:1236: SyntaxWarning: invalid escape sequence '\p'

I try to use pip or sort this out on Ubuntu 24.04

ouboub commented 2 weeks ago

Ok I installed dot2tex with pip, without any error but your syntax still does not work

michal-h21 commented 2 weeks ago

My command was wrong, it should look like this:

$  dot2tex --figonly  -t raw sample.dot > graph.tex

I don't understand why I added filename.tex in my previous message.

michal-h21 commented 2 weeks ago

The .dot filename should have the same basename as your TeX file, which is sample.tex for me. So you may need to use a different name if your TeX file has a different name.

ouboub commented 2 weeks ago

`

My command was wrong, it should look like this:

$  dot2tex --figonly  -t raw sample.dot > graph.tex

I don't understand why I added filename.tex in my previous message.

Thanks very much, just one comment, when I then again compile sample.tex via pdflatex

I receive

Package rdfref error: unknown type of reference sec:another :sec:
(./graph.tex
Missing character: There is no ; in font nullfont!
Missing character: There is no ; in font nullfont!
Missing character: There is no ; in font nullfont!

but the pdf looks ok, xelatex gives a similar error, so does lualatex in any case, the pdf looks ok in all three cases. I will play with this a bit more and report back. The only pity which might hampering a bit its widespread use, is that it is a bit awkward to use, but I am definitely very grateful! Because it saves me the time to rely on quiver

michal-h21 commented 2 weeks ago

Ah, I see the error now. It is in fact just a warning. It can be suppressed by definition of the sec type:

\makeatletter
\AddRdfType{sec}{
  \AddPropertyEx{rdf:type}{sec:sectioning}
  \AddPropertyEx{doc:pageNo}{\thepage}
  % this will be used in the graph label, change to your liking
  \AddPropertyEx{rdfs:label}{Section \@currentlabel}
}
\makeatother

You can put this code after \AddRdfType{eq}{...}

I really need to provide a good tutorial and documentation for the package, but I am really bad at documentation :( After that, I can put it on CTAN. If you have some ideas how things could be done easier, I can try to change that :)

ouboub commented 2 weeks ago

Thank that worked and supresses the error, what's about the error (pdflatex)

Missing character: There is no ; in font nullfont!

xelatex

lualatex

Missing character: There is no ; (U+003B) in font nullfont!

I presume they are harmless.

I really need to provide a good tutorial and documentation for the package, but I am really bad at documentation :( After that, I can put it on CTAN. If you have some ideas how things could be done easier, I can try to change that :)

I also think some more macros wouldn't be bad. It is such wonderful package, but I doubt a lot of users want in their manuscript, structure like

\graphout{digraph hello\@charlb} % save graph header

% loop over all equation object
\Bind{?curreq}{rdf:type}{eq:equation}{%
  % find all \rdfref objects that points to the equation
  \Bind{?curreq}{doc:referedBy}{?blank}{%
    % now we need to find the parent object of \rdfref
    \Bind{?blank}{doc:hasParent}{?parent}{
      % this will filter only equations
      \Bind{?parent}{rdf:type}{eq:equation}{%
        \noindent Equation \GetValProperty{?curreq}{rdfs:label} is referenced by \GetValProperty{?parent}{rdfs:label}\par%
        \graphout{"\GetValProperty{?parent}{eq:value}" -> "\GetValProperty{?curreq}{eq:value}"}
      }
    }
  }%
}

\graphout{\@charrb} % save footer
\closeout\graphwrite

\makeatother

that of course could be solved via \input{auxfile.tex} but a more elegant solution would be \generategraphofequations or something like this. As for the manual. I don't mind contributing. As a reader/user I prefer a manual with a lot of examples, but not too much theoretical explanation.

michal-h21 commented 1 week ago

I presume they are harmless.

I think so. I also don't know where they come from, only semicolons that I can found in the current directory are in the TikZ picture for graph.

Anyway, I've added a new command to rdfref-user.sty, \RdfLoopReferences. It can be used like this:

\RdfLoopReferences{}{eq:equation,sec:sectioning}{%
  \GetProperty{\currentobject}{rdfs:label} -> \GetProperty{\currentsubject}{rdfs:label}, %
}

The first and second arguments should contain lists of rdf:type of objects and subjects that should be used. If they are empty, it will output every object. Third argument contains code to be executed. \currentobject and \currentsubject are identifiers that can be used with \GetProperty.

Thanks to this command, I could create a simplified code for the Graphviz output:

\newwrite\graphwrite

\makeatletter
\newcommand\graphout[1]{\protected@write\graphwrite{\let\owrite\write\def\write{\immediate\owrite}}{#1}}

% #1 name of the graph (default \jobname-graph) -- it needs to be different than name of any existing file!
% #2 RDF property to be printed
% #3 list of allowed rdf:type for objects
% #4 list of allowed rdf:type for subjects
% don't forget to call latex with --shell-escape 
\NewDocumentCommand\RdfDrawGraph{O{\jobname-graph} O{rdfs:label} m m}{%
  \immediate\openout\graphwrite=#1.dot\relax%
  \graphout{digraph hello\@charlb} % save graph header
  \RdfLoopReferences{#3}{#4}{%
    \graphout{"\GetProperty{\currentobject}{#2}"-> "\GetProperty{\currentsubject}{#2}"} %
  }
  \graphout{\@charrb}% save footer
  \immediate\closeout\graphwrite%
  \ShellEscape{dot2tex --figonly  -t raw -o #1.tmp #1.dot }%
  \InputIfFileExists{#1.tmp}{}%
}
\makeatother

You can filter rdf:types in the same way as with \RdfLoopReferences. Optional arguments contain name of the graph and property to be used. It can be used like this:

\RdfDrawGraph[\jobname-graph][eq:value]{}{eq:equation}

Here is a full document:

\documentclass{article}
\usepackage{amsmath}
\numberwithin{equation}{section}
\usepackage{tikz}
\usepackage{shellesc}
\usepackage{rdfref}
\NewDocumentEnvironment{rdfequation}{o +b}{
  \begin{equation}
    #2 
    \IfBlankF{#1}{
      \rdflabel{#1}
      \AssignProperty{#1}{eq:value}{$$#2$$}
    }
  \end{equation}
}{}

\newwrite\graphwrite

\makeatletter
\newcommand\graphout[1]{\protected@write\graphwrite{\let\owrite\write\def\write{\immediate\owrite}}{#1}}

% #1 name of the graph (default \jobname-graph) -- it needs to be different than name of any existing file!
% #2 RDF property to be printed
% #3 list of allowed rdf:type for objects
% #4 list of allowed rdf:type for subjects
% don't forget to call latex with --shell-escape 
\NewDocumentCommand\RdfDrawGraph{O{\jobname-graph} O{rdfs:label} m m}{%
  \immediate\openout\graphwrite=#1.dot\relax%
  \graphout{digraph hello\@charlb} % save graph header
  \RdfLoopReferences{#3}{#4}{%
    \graphout{"\GetProperty{\currentobject}{#2}"-> "\GetProperty{\currentsubject}{#2}"} %
  }
  \graphout{\@charrb}% save footer
  \immediate\closeout\graphwrite%
  \ShellEscape{dot2tex --figonly  -t raw -o #1.tmp #1.dot }%
  \InputIfFileExists{#1.tmp}{}%
}
\makeatother

\begin{document}

% we need to declare some properties for the eq: prefix 
\AddRdfType{eq}{
  \AddPropertyEx{rdf:type}{eq:equation}
  \AddPropertyEx{doc:pageNo}{\thepage}
  % this will be used in the graph label, change to your liking
  \AddPropertyEx{rdfs:label}{Equation \theequation}
}

\makeatletter
\AddRdfType{sec}{
  \AddPropertyEx{rdf:type}{sec:sectioning}
  \AddPropertyEx{doc:pageNo}{\thepage}
  % this will be used in the graph label, change to your liking
  \AddPropertyEx{rdfs:label}{Section \@currentlabel}
}
\makeatother

\section{first section}
\rdflabel{sec:first}
\begin{rdfequation}[eq:hello]
  a = b + c
\end{rdfequation}

This equation links to equation~\rdfref{eq:second}, as well as to equation~\rdfref{eq:third}.

\section{another}
\rdflabel{sec:another}

\begin{rdfequation}[eq:second]
  a = d + c 
\end{rdfequation}

Link to another equation~\rdfref{eq:third}, in section~\rdfpageref{sec:first}.

\begin{rdfequation}[eq:third]
  d = x + y
\end{rdfequation}

\RdfLoopReferences{}{eq:equation,sec:sectioning}{%
  \GetProperty{\currentobject}{rdfs:label} -> \GetProperty{\currentsubject}{rdfs:label}, %
}

\RdfDrawGraph[\jobname-graph][eq:value]{}{eq:equation}

\end{document}

You need to run LaTeX with the --shell-escape option. It will run dot2tex automatically, so the graph is always updated with current values.