Ubuntu 中是否有一个软件可以分析 tex 项目中的交叉引用(定理、引理、方程等)?

Ubuntu 中是否有一个软件可以分析 tex 项目中的交叉引用(定理、引理、方程等)?

有一些软件可以分析代码(Java 或 C++)之间的交叉引用。多年前我曾经在 Windows 下使用过一个代码分析软件。但我记不起它的名字了。在 Linux 上,一个例子可能是 LXR Cross Referencer。

是否有类似的工具可以分析乳胶文件以找出定理、引理、命题和方程的交叉引用?

答案1

交叉引用LaTeX使用非常简单的模式 - 对于每个标签,它都会存储宏的值\@currentlabel和辅助文件中的页码。有一些包可以扩展此方案,例如titlerefzref,但它仍然只是标签和一些属性,然后可以通过某种形式的\ref命令访问它们。

在这种情况下,有用的是分布式文件框架因此可以构建对象及其属性和关系的复杂图形,例如

定理 Lorem 在第 4 页的 Ipsum 部分中定义,并且在第 5 页有定义 foo,在第 6 页有示例 boo,在第 3、7、89 页等中被引用......

在这个模型中,每个label(对象)可以有任意数量的属性,这些属性可以是值,也可以是其他对象,这给了我们对象、属性和主体的有向图。对象和属性的形式为prefix:name

现在有一些简单的rdf框架LaTeX

首先我们定义一些用于保存和加载属性的核心函数 rdfref-core.sty

\ProvidesPackage{rdfref-core}
\RequirePackage{etoolbox}
\def\Nil{}%
\def\First#1#2{#1}
\def\Second#1#2{#2}

\def\parsecolon#1:#2\relax{\ifx#2\Nil\Nil\else#1\fi}%
\newcommand\RdfPrefix[1]{%
\parsecolon#1:\Nil\relax%
}
\newcommand\AddTriple[3]{%
\edef\rdf@object{#3}
\immediate\write\@auxout{\noexpand\LoadTriple{#1}{#2}{\rdf@object}}
}

\newcommand\SetProperty[3]{%
\protected@csxdef{rdf@#1@#2}{#3}%
}

\newcommand\GetProperty[2]{%
\ifcsdef{rdf@#1@#2}{%
\csuse{rdf@#1@#2}%
}{%
\PropertyNotDef{#1}{#2}%
}%
}
\newcommand\PropertyNotDef[2]{%
???%
%\typeout{rdf warning: subject #1 has no property #2}%
}

\newcommand\SubjectListAdd[2]{%
\listcsgadd{sbjlst@#1}{#2}
}
\newcommand\MapSubjectList[2]{%
\def\do##1{#2}%
\dolistcsloop{sbjlst@#1}%
}

\newcommand\PropertyListAdd[3]{%
\listcsgadd{prprtlst@#2}{{#1}{#3}}
}
\newcommand\MapPropertyList[2]{%
\def\do##1{#2}%
\dolistcsloop{prprtlst@#1}%
}


\newcommand\LoadTriple[3]{%
\SetProperty{#1}{#2}{#3}
\SubjectListAdd{#1}{#2}
\PropertyListAdd{#1}{#2}{#3}
}

两个有用的函数是\MapPropertyList,它允许您循环遍历具有给定属性的所有对象和主题,并\MapSubjectList循环遍历给定主题的属性。

现在有一些辅助函数,以某种方式模拟乳胶交叉引用系统rdfref-user.sty

\ProvidesPackage{rdfref-user}
\RequirePackage{rdfref-core,nameref}
\newwrite\exportfile
\def\RootObject{_:doc}

\def\CurrentObject{\RootObject}

\newcommand\AddRdfType[2]{%
\def\do##1{\csgdef{rdf:type@##1}{\noexpand\unexpanded{#2}}}
%\csgdef{rdf:type@#1}{\unexpanded{#2}}
\docsvlist{#1}
}
\newcommand\AddProperty[2]{%
\AddTriple{\CurrentObject}{#1}{#2}
}


\newcommand\WithObject[2]{%
\begingroup%
\def\CurrentObject{#1}%
\def\run{#2}
\run%
\endgroup%
}



\newcommand\rdflabel[1]{%
\AddTriple{#1}{doc:hasParent}{\CurrentObject}%
\AddTriple{#1}{doc:envir}{\@currenvir}%
\def\CurrentObject{#1}%
\ifcsdef{rdf:type@\GuessRdfType{#1}}%
{\csuse{rdf:type@\GuessRdfType{#1}}}%
{\typeout{Package rdfref error: unknown type of reference #1 :\GuessRdfType{#1}:}}%
\label{#1}
}

\newcommand\GuessRdfType[1]{%
% We first try if current environment is defined as type, if not, then guess type from the parameter
\ifcsdef{rdf:type@\@currenvir}{\@currenvir}{%
\ifx\RdfPrefix{#1}\Nil\Nil\else%
\RdfPrefix{#1}%
\fi%
}%
}

\newcommand\inputontology[1]{%
\makeatletter
\input{#1}
\makeatother
}

命令\rdflabel构造LaTeX标签,因此您可以使用和等常规构造,\ref\pageref使用一些默认值创建对象,然后调用构造函数,该构造函数存储为给定类型的对象定义的属性。类型从对象的周围扣除environment,如果它没有设置类型,则从其前缀中扣除。

这些构造函数是在本体中定义的,本体是TeX带有宏定义的普通文件,但必须在之后加载\begin{document},因为它们需要写入aux文件。

theorem-ontology.tex

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


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

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


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

\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}
}
\WithObject{thm:lemma}{%
\AddProperty{rdfs:label}{Lemma}
\AddProperty{rdf:type}{rdfs:Class}
}

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

您可以看到我们为一些环境和前缀添加了构造函数。重要的属性是rdf:type,例如,如果您想循环遍历所有定理或方程式,可以使用它。还有属性doc:pageNordfs:label,它们或多或少是传统的LaTeX交叉引用属性。对于每个,rdf:object还有宏,它为这些类型\WithObject设置文本标签( )。rdfs:label

还有命令\partOf,它将当前对象声明为另一个对象的一部分。它可以用于示例或定义中,以声明它们是某个定理的一部分。我对数学定理一无所知,所以这真的只是一个简单的例子,没有什么用处。如果你知道一些有用的属性,它们可以轻松添加。

现在有一些示例文件:

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[]{tgschola}
\usepackage[T1]{fontenc}
%\catcode`\_=12
\usepackage[]{rdfref-user,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}

\begin{document}
\inputontology{theorem-ontology.tex}
\section{Hello world}\rdflabel{sec:first}
\lipsum[1-2]
  \begin{lem}\rdflabel{thm:lem1}
    \partOf{thm:thr1}
    A lemma.
  \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}

\end{document}

如果您想导出一些图表,请尝试这个宏(虽然不是很好,但它展示了一些如何使用属性图表的方法):

\newcommand\ExportGraphviz[2]{%
digraph G\{
\forcsvlist{\listadd\typelist}{#1}
%\forcsvlist{\listadd\propertylist}{#2}
\def\worker##1##2{%
%"\ObjectLabel" -> \GetProperty{\First##1}
\edef\ppp{\GetProperty{##1}{##2}}
\typeout{Worker: ##1: ##1 : \ppp}
\IfSubStr{\ppp}{???}{}{%
"\ObjectLabel" -> %
\IfSubStr{\ppp}{:}{"\GetProperty{\GetProperty{\ppp}{rdf:type}}{rdfs:label}: \GetProperty{\ppp}{rdfs:label}"}{"\ppp"} %
%\GetProperty{##1}{##2} 
 [label="##2"];\\%
}
}
\MapPropertyList{rdf:type}{%
\xifinlist{\Second##1}{\typelist}{%
\edef\ObjectLabel{\GetProperty{\Second##1}{rdfs:label}: \GetProperty{\First##1}{rdfs:label}}%
%\ObjectLabel \& \Second##1\\}
\bgroup%
%\MapObjectList{\First##1}{}
\forcsvlist{\worker{\First##1}}{#2}%
\egroup
}%
{}%
}
\}
}

由于一些奇怪的错误,我无法执行写入文件的版本,因此 graphviz 规范只是打印到文档中(我知道这真的很丑)。它可以按以下方式使用:

\ExportGraphviz{sec:sectioning,thm:theorem,eq:equation,thm:proposition,thm:proposition,thm:lemma}{doc:pageNo,doc:partOf,doc:hasParent}

第一个参数是rdf:type应导出的给定对象的列表,第二个参数是属性列表。出于某种原因,第一次运行时,当没有辅助文件时,会出现一些错误,但之后应该没问题

结果图:

在此处输入图片描述

此外,它还易于使用\MapPropertyList并将\MapSubjectList数据导出为某些rdf序列化格式,例如并将它们导入到一些专门的rdf数据库或可视化工具中,并用它们做许多有趣的事情。

相关内容