在我的设计理论课上,我试图构造幂等拉丁方和相互正交的拉丁方,如问题所述。我理解这个过程,可以很容易地为小订单做到这一点,但对于这个特定问题,我觉得编写一个程序来生成这些表格会快得多。我认为不需要任何设计理论知识,但我当然希望有人能帮助我编写代码来生成这些表格。
这个过程的工作原理如下。我得到了一个 21 阶的成对平衡设计,块大小为 5。例如,一个块是 {1,2,3,4,21}。然后我使用每个块创建 3 个 5 阶幂等拉丁方。在每个拉丁方中
x<y<z<u<v
因此对于我们的特定块 x=1,y=2,z=4,u=4,v=21。这是第一个幂等拉丁方的构造。(我相信如果我能编码它,我就可以修改其他 2 个)。外行和外列本质上在运算下创建了一个乘法表(想想群论中的凯莱表)。
\documentclass[12pt]{article}
\usepackage{fullpage}
\begin{document}
\begin{tabular}{c|ccccc}
\(\circ_1\)&\(x\)&\(y\)&\(z\)&\(u\)&\(v\)\\
\hline
\(x\)&\(x\)&\(u\)&\(y\)&\(v\)&\(z\)\\
\(y\)&\(u\)&\(y\)&\(v\)&\(z\)&\(x\)\\
\(z\)&\(y\)&\(v\)&\(z\)&\(x\)&\(u\)\\
\(u\)&\(v\)&\(z\)&\(x\)&\(u\)&\(y\)\\
\(v\)&\(z\)&\(x\)&\(u\)&\(y\)&\(v\)
\end{tabular}
\end{document}
然后,使用所有 21 个块的幂等拉丁方,我可以创建一个 21 阶拉丁方,其中 (i,j) 项可以通过在前一个拉丁方中定位乘积来找到。例如,在给定的构造中,y=2,z=3,yz=21,因此 (2,3) 项为 21。
环顾四周,我发现了这个话题在表内插入循环?其中提到“这是一个 LaTeX 解决方案,带有\forloop
来自 forloop 包。它使用命令构建一个表格数组\maketablerows{number_of_rows}{rowcontent}
,其中 rowcontent 被怀疑用于保存一行中单元格的值,无论是直接保存还是通过命令保存。”但是,我查看了手册,但我真的不知道如何让 {rowcontent} 生成我想要的内容。
我知道我可以用 C++ 编写一个程序来执行此操作并使其导出 tex 表(又名 21X21 拉丁方代码,天哪!),但我希望有人能帮助指导我如何在 latex 中执行此操作。我可以弄清楚编程逻辑,只是不知道要使用的语法。
TLDR:如何使用乳胶中的循环来使用指定的公式生成表格?
编辑:评论太长了。
我相信我已经找到了另外两个公式,其中一个确实是 2(2x+y) mod 5,但我发现的另一个是 2x-y mod 5。我试图将它们转换为像您对 3(x+y) 所做的那样的公式,这让我摆弄了您给出的公式 3*(#2+#3)-5*((3*(#2+#3)+3)/5 -1)+1。
如果我理解正确的话,
\expandafter\edef\csname Latin-\aBlock{#2+1}-\aBlock{#3+1}\endcsname {\aBlock{3*(#2+#3)-5*((3*(#2+#3)+3)/5 -1)+1}}% % 这是一个疯狂的公式,它只是对 3(a+b) 取模 5 % 但回想一下,a+1 和 b+1 是数组 \aBlock 的参数
意思是如果我在块 0,1,2,3,4 中取数字 3,4,那么数字 3*(3+4)-5((3*(3+4)+3)/5-1)+1=3 应该出现在 ((3+1,4+1))=(4,5) 条目中?我肯定误解了您将 1 添加到 #2 和 #3 的部分,因为我尝试添加 1 然后执行操作,同时将计算出的值放入 (#2+1,#3+1) 单元格中,但仍然没有得到表中的值。
答案1
目录
一般方法
从法诺平面获得 7×7 案例的概念证明
F4 上的射影平面有 16+4+1 = 21 个点和线。得益于显式枚举这里我可以应用前面描述的方法。我使用了 OP 的 5x5 拉丁方,它很简单
3(x+y) mod 5
。每对点都位于 21 条投影线中的一条唯一投影线上。每条投影线有 5 个点,因此我们可以在那里使用 5x5 拉丁方。使用相同的方法,我们构造了一个 21x21 拉丁方。因为枚举https://www.uwyo.edu/moorhouse/pub/planes/pg24.txt点的数量是从 0 到 20,我将其保留在最终结果中,因此行和列的索引是从 0 到 20,而不是 1 到 21,但这是可以更改的细节。
可以这样做:你有 21 个块 B,每个块的大小为 5x5。
对于每个这样的块 B,您使用\@namedef{Latin-i-j}{the value at row i and column j for the 5x5 Latin square with letters from B}
。您的小拉丁方是幂等的,因此在 i 处的对角线上,i 我们只需有 i。每个小拉丁方定义 20 个非对角线值。
因此,您需要对 21 个块 B 进行循环,为每个块定义 20+5 个宏(对角线的宏将由其他块再次定义,但没关系)。完成后,您的大拉丁方阵就准备好了,它包含 21 乘以 20 = 420 个非对角线元素加上 21 个对角线元素,总共 441 = 21x21 对。对角线是已知的,因为您的小拉丁方阵是幂等的。
然后,您可以使用如下结构来排版它:
\documentclass{article}
\usepackage{array}
\usepackage{xinttools}
% YOU NEED HERE TO DO A LOOP OVER THE BLOCKS TO DEFINE SUITABLY
% (POSSIBLY EVEN BY SOME \numexpr FORMULA) THE 21 x 21 MACROS
% \makeatletter
% % some loop here over the block to define for each suitable
% % \@namedef{Latin-i-j}
% \makeatother
\edef\TwentyOneNumbers{\xintSeq{1}{21}}
\begin{document}
\makeatletter
\begin{tabular}{*{22}{c|}}
% first row
\xintFor* #1 in \TwentyOneNumbers\do{}\\
\hline
\xintFor* #1 in \TwentyOneNumbers\do{% this will be row number #1
#1
\xintFor* #2 in \TwentyOneNumbers\do{% this indices the columns
&\@nameuse{Latin-#1-#2}}
\\\hline}
\end{tabular}
\makeatother
\end{document}
上面的 mwe 缺少所有需要的内容,\@namedef
因为您没有解释块是什么(您给出的 5x5 拉丁方乍一看只是 Z/5Z 中的加法,直到重命名索引)。所以目前我们只得到这个:
上面的表格溢出了右边距,但我没有修复页面布局(在 LaTeX 默认设置下,页面布局非常窄,最好使用包几何)。此外,列的宽度也不同,应该修复。最后,我从您的 5x5 示例中接管了第一行和第一列的包含,也许作为拉丁方,这些装饰应该被删除,以便真正拥有 21x21 而不是 22x22 的网格。
作为概念证明,这里是根据几何学构造一个 7x7 拉丁方法诺平面. 这些线给出了 7 个块,每个块包含 3 个元素。
对于 3x3 幂等拉丁方,我选择了模 3 加法(更准确地说-x-y mod 3
是为了得到幂等性)。该公式可以通过表达式来实现\numexpr
。这\numexpr
是默认的,因为我使用\xintAssignArray
了新工具,它定义了一个宏,其参数通过 自动求\numexpr
值。此参数从 1 开始(值 0 表示数组元素的数量,在本应用程序中为 3,因为块的大小为 3)。
每对不同的元素(从 1 到 7)都包含在一个唯一的块中。应用此方法,我们构造了一个 7 x 7 的拉丁方。
在一般描述中我提到过,\@namedef
但在这里我需要扩展论点,遗憾的是 LaTeX 在“编程”方面极其有限,所以我不得不为此研究更深层次的 TeX 原语。
在您的特定情况下,您似乎瞄准的是 3 个不同的 21x21 正方形,因此您需要通过再次循环块来调整或重复此处的过程。
\documentclass{article}
\usepackage{array}
\usepackage{xinttools}
% Take a pairwise design from Fano Plane
% I picked up the blocks at https://fr.wikipedia.org/wiki/Plan_de_Fano
% but I needed to shift by 1 the enumeration to manipulate 1, 2, ..., 7
% For each block, having 3 elements, I will construct an idempotent Latin
% square from addition modulo 3.
\xintFor #1 in {{1, 2, 4}, {2, 3, 5}, {3, 4, 6}, {4, 5, 7}, {5, 6, 1},
{6, 7, 2}, {7, 1, 3}}\do{%
\xintAssignArray\xintCSVtoList{#1}\to\aBlock
% arrays defined by \xintAssignArray are indexed starting at 1
\xintFor #2 in {0, 1, 2}\do{%
\xintFor #3 in {0, 1, 2}\do{%
% unfortunately LaTeX has very few programming tools,
% there is \@namedef but not even a \@nameedef
\expandafter\edef\csname Latin-\aBlock{#2+1}-\aBlock{#3+1}\endcsname
{\aBlock{2*(#2+#3)-3*((2*(#2+#3)+2)/3 -1)+1}}%
% this is crazy formula which simply does -(a+b) modulo 3
% which is same as 2(a+b) (we prefer non negative numbers with \numexpr)
% but a = i-1, b = j-1, and modulo is complicated with \numexpr
% (\numexpr is used by \aBlock to parse its argument)
% (this is property of "arrays" defined by \xintAssignArray)
}%
}%
}
% done, all our macros defined
\edef\SevenNumbers{\xintSeq{1}{7}}
\begin{document}
\makeatletter
\begin{tabular}{*{8}{c|}}
% first row
\xintFor* #1 in \SevenNumbers\do{}\\
\hline
\xintFor* #1 in \SevenNumbers\do{% this will be row number #1
#1
\xintFor* #2 in \SevenNumbers\do{% this indices the columns
&\@nameuse{Latin-#1-#2}}
\\\hline}
\end{tabular}
\makeatother
\end{document}
现在来看一下真正的情况,使用 21 平面。
\documentclass{article}
\usepackage{geometry}
\usepackage{array}
\usepackage{xinttools}
% The projective plane over the field of 4 elements has
% 16+4+1 = 21 points.
% It also has 21 lines. Each pair of distinct points
% is contained in a unique line.
% A projective line has 4+1 = 5 elements and we can
% construct an idempotent Latin square using the field
% with five elements and the rule 3(x+y) modulo 5
% as 6x is same as x modulo 5. This is indeed exactly the
% rule in the OP's example of Latin square.
% Thus we will get a 21x21 Latin square from that, simply
% by enumerating the 21 projective lines in the projective
% plane over F_4.
% We need a list of those lines, with the points of the plane
% are suitably enumerated. Thankfully, we found one at
% https://www.uwyo.edu/moorhouse/pub/planes/pg24.txt
% 0 1 2 3 4
% 0 5 6 7 8
% 0 9 14 15 16
% 0 10 12 17 19
% 0 11 13 18 20
% 1 5 9 10 11
% 1 6 14 17 18
% 1 8 13 16 19
% 1 7 12 15 20
% 2 5 14 19 20
% 4 5 13 15 17
% 3 5 12 16 18
% 2 6 9 12 13
% 2 7 11 16 17
% 2 8 10 15 18
% 3 6 11 15 19
% 4 6 10 16 20
% 4 7 9 18 19
% 3 8 9 17 20
% 4 8 11 12 14
% 3 7 10 13 14
% Our points are enumerated from 0 to 20.
% I manipulated it using search/replace in an Emacs buffer into
% nice format for input to \xintFor and \xintAssignArray
\xintFor #1 in {%
{0}{1}{2}{3}{4},
{0}{5}{6}{7}{8},
{0}{9}{14}{15}{16},
{0}{10}{12}{17}{19},
{0}{11}{13}{18}{20},
{1}{5}{9}{10}{11},
{1}{6}{14}{17}{18},
{1}{8}{13}{16}{19},
{1}{7}{12}{15}{20},
{2}{5}{14}{19}{20},
{4}{5}{13}{15}{17},
{3}{5}{12}{16}{18},
{2}{6}{9}{12}{13},
{2}{7}{11}{16}{17},
{2}{8}{10}{15}{18},
{3}{6}{11}{15}{19},
{4}{6}{10}{16}{20},
{4}{7}{9}{18}{19},
{3}{8}{9}{17}{20},
{4}{8}{11}{12}{14},
{3}{7}{10}{13}{14}}\do{%
\xintAssignArray#1\to\aBlock
% arrays defined by \xintAssignArray are indexed starting at 1
\xintFor #2 in {0, 1, 2, 3, 4}\do{%
\xintFor #3 in {0, 1, 2, 3, 4}\do{%
\expandafter\edef\csname Latin-\aBlock{#2+1}-\aBlock{#3+1}\endcsname
{\aBlock{3*(#2+#3)-5*((3*(#2+#3)+3)/5 -1)+1}}%
% this is crazy formula which simply does 3(a+b) modulo 5
% but recall it is a+1 and b+1 which serve as arguments to
% the array \aBlock
}%
}%
}
% done, all our macros defined
\edef\TwentyOneNumbersStartingAtZero{\xintSeq{0}{20}}
\begin{document}
\makeatletter
\begin{tabular}{*{22}{c|}}
% first row
\xintFor* #1 in \TwentyOneNumbersStartingAtZero\do{}\\
\hline
\xintFor* #1 in \TwentyOneNumbersStartingAtZero\do{% this will be row number #1
#1
\xintFor* #2 in \TwentyOneNumbersStartingAtZero\do{% this indices the columns
&\@nameuse{Latin-#1-#2}}
\\\hline}
\end{tabular}
\makeatother
\end{document}
答案2
对于您给出的示例,不需要\forloop
。相反,您只需使用一个简单的宏,例如:
\newcommand\LatinSquare[5]{
\[
\begin{array}{c|ccccc}
\circ_1\\
\hline
#1\\
#2\\
#3\\
#4\\
#5
\end{array}
\]
}
您可以使用
\LatinSquare{1}{2}{3}{4}{21}
正如预期,结果如下:
然而,我怀疑这并不是您真正想要的,因此也许您需要在问题中添加更多细节!
完整代码如下:
\documentclass[12pt]{article}
\usepackage{fullpage}
\newcommand\LatinSquare[5]{
\[
\begin{array}{c|ccccc}
\circ_1\\
\hline
#1\\
#2\\
#3\\
#4\\
#5
\end{array}
\]
}
\begin{document}
\LatinSquare{1}{2}{3}{4}{21}
\end{document}