用于自动化真值表的宏

用于自动化真值表的宏

我在写证明时使用了这个真值表。在此处输入图片描述
不幸的是,我犯了一个小错误;第一次,我放错了一个额外的ʹ符号,结果输出完全错误。我花了很长时间才明白为什么之后的一切似乎都不像我所知道的那样。

这让我很疑惑。是否有可能构建某种宏,使我能够根据给定的输入生成准确的真值表?换句话说:我希望它能像这样工作:

\truthtable{A, B, ( A \oplus B )', (A) \oplus (B')}

相比于必须手动绘制整个图形,可能会出错。您如何开始在 LaTeX 中编写这样的程序?

以下是上表的完整手动 MWE:


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass[border=10pt]{standalone}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%hdashline
\usepackage{array}
\usepackage{arydshln}
\setlength\dashlinedash{0.2pt}
\setlength\dashlinegap{1.5pt}
\setlength\arrayrulewidth{0.3pt}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
\begin{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%        
\begin{table}[htbp!]
\centering
\caption{}
\label{tab}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
\begin{tabular}{@{}cccc@{}}
\toprule%%–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
$A$ & $B$ & $(A \oplus B)'$ & $(A) \oplus (B')$ \\
\midrule%%–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
0 & 0 & 1 & 1 \\ \hdashline%%··········································
0 & 1 & 0 & 0 \\ \hdashline%%··········································
1 & 0 & 0 & 0 \\ \hdashline%%··········································
1 & 1 & 1 & 1 \\ \bottomrule%––––––––––––––––––––––––––––––––––––––––––
\end{tabular}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\end{table}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    

答案1

这是快速编写的。它不会操纵火星探测器,实际上它只是一行代码。如果您使代码可复制,我会在需要时添加所有表格选项。(事实上,我没有做任何努力使输出“漂亮”,也没有抑制空格或空行。)也可以使用循环来创建所有行。我在输出中添加了解释。

\documentclass{article}
\usepackage{pgf}
\newcounter{step}
\newcommand{\myrow}[2]{ #1 & #2 & 
 \pgfmathparse{not(int(mod(#1+#2,2)))}\pgfmathresult & 
 \pgfmathparse{int(mod(#1+not(#2),2))}\pgfmathresult\\
 }
\setcounter{step}{0}
\def\tabcontent{\stepcounter{step}\ifnum\value{step}<5
\pgfmathtruncatemacro{\myA}{(\value{step}-1)/2}%
\pgfmathtruncatemacro{\myB}{mod(\value{step}-1,2)}%
\edef\temp{\noexpand\myrow{\myA}{\myB}}\temp%
\tabcontent\fi}
\begin{document}
In the first example (Table~\ref{tab:First}), explicit macros
\verb|\myrow{A}{B}| are used for each row. The \verb|\myrow| macro takes two
arguments, which are $A$ and $B$ in your application. 

\begin{table}[!h]
\centering
\begin{tabular}{c@{}cccc@{}}
 ~$A$~ & ~$B$~ & $(A \oplus B)'$ & $(A) \oplus (B')$ \\
 \hline
 \myrow{0}{0}
 \myrow{0}{1}
 \myrow{1}{0}
 \myrow{1}{1}
\end{tabular} 
\caption{First example.}
\label{tab:First}
\end{table}

The important point is that the other entries of the remaining columns can be
computed with \texttt{pgf} via \verb|\pgfmathparse{not(int(mod(#1+#2,2)))}| and
\verb|\pgfmathparse{int(mod(#1+not(#2),2))}|, respectively. I strongly suspect
that other packages like \texttt{xint} allow you to do similar things. However,
I am most familiar with \texttt{pgf}.

In the second example (Table~\ref{tab:Second}), a loop produces the content
of the table. Since the \& character is notoriously nasty, this loop is realized
as a recursive macro. Alternatives to this recursion include the \verb|\gappto|
macro that comes with the \texttt{etoolbox} package.
\begin{table}[!h]
\centering
\begin{tabular}{c@{}cccc@{}}
 ~$A$~ & ~$B$~ & $(A \oplus B)'$ & $(A) \oplus (B')$ \\
 \hline
 \tabcontent
\end{tabular} 
\caption{Second example.}
\label{tab:Second}
\end{table}
\end{document}

在此处输入图片描述

答案2

答案并不简短,代码比我想象的要长。代码可能看起来有点麻烦,但我没有以任何方式对其进行优化。我只是想展示一种解决方案,其中解释输入并生成真值表,例如(A\oplus B)'A XOR B,结果被否定。代码不接受所有可能的输入。例如,只能有一个逻辑运算符:\land\lor\oplus。所以(A\land B) \land \neg (A\land B)不是有效输入。可以有多个运算符,如\neg'

应该可以扩展代码来克服这个限制。

\documentclass{scrartcl}

\usepackage{xparse}
\usepackage{array}
\usepackage{booktabs}

\ExplSyntaxOn

\tl_new:N \l__truthtable_op_tmp_tl
\tl_new:N \l__truthtable_logical_tmp_tl
\tl_new:N \l__truthtable_expression_tmp_tl
\seq_new:N \l__truthtable_logical_tmp_seq

\tl_new:N \l__truthtable_expression_left_tl
\tl_new:N \l__truthtable_expression_right_tl
\tl_new:N \l__truthtable_expression_out_tl

\seq_new:N \l__truthtable_op_seq

\seq_new:N \l__truthtable_vara_logical_seq
\seq_new:N \l__truthtable_varb_logical_seq
\seq_new:N \l__truthtable_op_logical_seq

\seq_new:N \l__truthtable_expression_seq
\seq_new:N \l__truthtable_expression_split_seq

\int_new:N \l__truthtable_expression_int
\int_new:N \g__truthtable_tmp_int

\bool_new:N \l__truthtable_vara_bool
\bool_new:N \l__truthtable_varb_bool
\bool_new:N \l__truthtable_result_bool

\NewDocumentCommand{\truthtable}{ m m m }
{
    \group_begin:
    \seq_set_from_clist:Nn \l__truthtable_expression_seq {#3}
    \int_set:Nn \l__truthtable_expression_int { \seq_count:N \l__truthtable_expression_seq }
    
    \seq_map_function:NN  \l__truthtable_expression_seq \truthtable_parse:n
    \truthtable_truthtable:NNnn \l__truthtable_expression_seq \l__truthtable_expression_int {#1} {#2}
    \group_end:
}

\cs_new_protected:Npn \truthtable_truthtable_begin:N #1
{
    \tabular{ *{ \int_eval:n { #1 + 2 } }{ >{$}c<{$} } }
    \toprule
}

\cs_new_protected:Npn \truthtable_truthtable_end:
{
    \\ \bottomrule
    \endtabular
}

\cs_new_protected:Npn \truthtable_truthtable:NNnn #1 #2 #3 #4
{
    \truthtable_truthtable_begin:N #2
    \truthtable_truthtable_header:NNnn #1 #2 {#3} {#4}
    \truthtable_truthtable_content:N   #2
    \truthtable_truthtable_end:
}

\cs_new_protected:Npn \truthtable_truthtable_header:NNnn #1 #2 #3 #4
{
    #3 & #4
    \int_compare:nNnF {#2} = { 0 }
    {  & \seq_use:Nn #1 { & }  }
    \\ \midrule
}

\cs_new_protected:Npn \truthtable_truthtable_content:N #1
{
    \int_gzero:N \g__truthtable_tmp_int
    \int_step_inline:nnn { 0 } { 1 }
    {
        \int_step_inline:nnn { 0 } { 1 }
        {
            ##1 & ####1
            
            \truthtable_evaluate:Nnn #1 {##1} {####1}
            
            \__truthtable_newline:N \g__truthtable_tmp_int
        }   
    }
}

\cs_new_protected:Npn \__truthtable_newline:N #1
{
    \int_gincr:N #1
    \int_compare:nNnF {#1} = { 4 }
    { \\ }
}

\cs_new_protected:Npn \truthtable_parse:n #1
{
    \tl_map_function:nN {#1} \__truthtable_get_operator:n
    
    \__truthtable_split_at_operator:n {#1}
    
    \truthtable_if_odd:VTF \l__truthtable_expression_left_tl
    {  \truthtable_odd:NN  \l__truthtable_expression_left_tl \l__truthtable_expression_right_tl  }
    {  \truthtable_even:NN \l__truthtable_expression_left_tl \l__truthtable_expression_right_tl  }
    
    
}

\cs_new_protected:Npn \__truthtable_get_operator:n #1
{
    \str_case:nnT {#1}
    {
        { \oplus } { \seq_put_right:Nn \l__truthtable_op_seq { xor } }
        { \lor   } { \seq_put_right:Nn \l__truthtable_op_seq { or  } }
        { \land  } { \seq_put_right:Nn \l__truthtable_op_seq { and } }
    }
    {  \tl_map_break:n { \tl_set:Nn \l__truthtable_op_tmp_tl {#1} }  }
}

\cs_new_protected:Npn \__truthtable_split_at_operator:n #1
{
    \exp_args:NNV
    \seq_set_split:Nnn \l__truthtable_expression_split_seq \l__truthtable_op_tmp_tl {#1}
    
    \tl_set:Nx \l__truthtable_expression_left_tl  { \seq_item:Nn \l__truthtable_expression_split_seq { 1 } }
    \tl_set:Nx \l__truthtable_expression_right_tl { \seq_item:Nn \l__truthtable_expression_split_seq { 2 } }
}

\cs_new_protected:Npn \truthtable_odd:NN #1 #2
{
    \tl_clear:N \l__truthtable_expression_out_tl
    \tl_reverse:N #2
    \truthtable_odd_aux:NNn #1 \l__truthtable_expression_tmp_tl { ( }
    \truthtable_odd_aux:NNn #2 \l__truthtable_expression_tmp_tl { ) }
    \tl_reverse:N #2
    
    \truthtable_get_logicals:NN \l__truthtable_expression_out_tl \l__truthtable_op_logical_seq
    \truthtable_get_logicals:NN #1 \l__truthtable_vara_logical_seq
    \truthtable_get_logicals:NN #2 \l__truthtable_varb_logical_seq
}

\cs_new_protected:Npn \truthtable_odd_aux:NNn #1 #2 #3
{
    \tl_set_eq:NN #2 #1
    
    \tl_map_inline:Nn #1
    {
        \str_if_eq:nnTF {##1} {#3}
        {
            \tl_set:Nx #2 { \tl_tail:N #2 }
            \tl_map_break:
        }
        {
            \tl_put_right:Nx \l__truthtable_expression_out_tl { \tl_head:N #2 }
            \tl_set:Nx #2 { \tl_tail:N #2 }
        }
    }
    \tl_set_eq:NN #1 #2
}

\cs_new_protected:Npn \truthtable_even:NN #1 #2
{
    \truthtable_get_logicals:NN #1 \l__truthtable_vara_logical_seq
    \truthtable_get_logicals:NN #2 \l__truthtable_varb_logical_seq
    \seq_put_right:Nn \l__truthtable_op_logical_seq { }
}

\cs_new_protected:Npn \truthtable_get_logicals:NN #1 #2
{
    \tl_clear:N \l__truthtable_logical_tmp_tl
    \tl_map_inline:Nn #1
    {
        \str_case:nn {##1}
        {
            { '    } { \truthtable_add_to_tl:Nnn \l__truthtable_logical_tmp_tl { not } { , } }
            { \neg } { \truthtable_add_to_tl:Nnn \l__truthtable_logical_tmp_tl { not } { , } }
        }
    }
    \seq_put_right:NV #2 \l__truthtable_logical_tmp_tl
}

\cs_new_protected:Npn \truthtable_add_to_tl:Nnn #1 #2 #3
{
    \tl_if_empty:NTF #1
    {  \tl_set:Nn       #1 {  #2}  }
    {  \tl_put_right:Nn #1 {#3#2}  }
}

\cs_new_protected:Npn \truthtable_evaluate:Nnn #1 #2 #3
{
    \int_step_inline:nnn { 1 } {#1}
    {
        &
        \truthtable_set_bool:Nn \l__truthtable_vara_bool {#2}
        \truthtable_set_bool:Nn \l__truthtable_varb_bool {#3}
        \truthtable_eval_logical:NNn \l__truthtable_vara_logical_seq \l__truthtable_vara_bool {##1}
        \truthtable_eval_logical:NNn \l__truthtable_varb_logical_seq \l__truthtable_varb_bool {##1}
        
        \truthtable_eval_operator:NNn \l__truthtable_vara_bool \l__truthtable_varb_bool {##1}
        \truthtable_print_result:NNn \l__truthtable_op_logical_seq \l__truthtable_result_bool {##1}
    }
}

\cs_new_protected:Npn \truthtable_eval_operator:NNn #1 #2 #3
{
    \str_case_e:nn { \seq_item:Nn \l__truthtable_op_seq {#3} }
    {
        { xor } { \truthtable_xor:NN #1 #2 }
        { or  } { \truthtable_or:NN  #1 #2 }
        { and } { \truthtable_and:NN #1 #2 }
    }
}

\cs_new_protected:Npn \truthtable_eval_logical:NNn #1 #2 #3
{
    \exp_args:NNx
    \seq_set_from_clist:Nn \l__truthtable_logical_tmp_seq { \seq_item:Nn #1 {#3} }
    
    \seq_map_inline:Nn \l__truthtable_logical_tmp_seq
    {
        \str_case:nn {##1}
        {
            { not } { \truthtable_not:N #2 }
        }
    }
}

\cs_new_protected:Npn \truthtable_print_result:NNn #1 #2 #3
{
    \truthtable_eval_logical:NNn #1 #2 {#3}
    
    \bool_if:NTF #2
    { 1 }
    { 0 }
}

\cs_new_protected:Npn \truthtable_set_bool:Nn #1 #2
{
    \int_case:nn {#2}
    {
        { 0 } { \bool_gset_false:N #1 }
        { 1 } { \bool_gset_true:N  #1 }
    }
}

\cs_new_protected:Npn \truthtable_xor:NN #1 #2
{
    \bool_xor:nnTF {#1} {#2}
    { \bool_set_true:N  \l__truthtable_result_bool }
    { \bool_set_false:N \l__truthtable_result_bool }
}

\cs_new_protected:Npn \truthtable_not:N #1
{
    \bool_set_inverse:N #1
}

\cs_new_protected:Npn \truthtable_or:NN #1 #2
{
    \bool_lazy_or:nnTF {#1} {#2}
    { \bool_set_true:N  \l__truthtable_result_bool }
    { \bool_set_false:N \l__truthtable_result_bool }
}

\cs_new_protected:Npn \truthtable_and:NN #1 #2
{
    \bool_lazy_and:nnTF {#1} {#2}
    { \bool_set_true:N  \l__truthtable_result_bool }
    { \bool_set_false:N \l__truthtable_result_bool }
}

\prg_new_conditional:Npnn \truthtable_if_odd:n #1 { T, F, TF }
{
    \regex_count:nnN { \( } {#1} \l_tmpa_int
    \regex_count:nnN { \) } {#1} \l_tmpb_int
    
    \int_if_odd:nTF { \l_tmpa_int + \l_tmpb_int }
    {  \prg_return_true:   }
    {  \prg_return_false:  }
}
\prg_generate_conditional_variant:Nnn \truthtable_if_odd:n { V } { TF }

\ExplSyntaxOff

\begin{document}
    \truthtable{A}{B}
    {
        (A\oplus B)',
        (A)\oplus(B'),
        A\oplus B,
        A\oplus B',
        \neg((A)\oplus (B)'),
        A\lor B,
        A\lor B',
        A\land B
    }
\end{document}

给予

在此处输入图片描述

相关内容