4

I'm in a computer science formal languages / computability / complexity course, and I have to type a lot of sequences... Sometimes I have to edit the terms, add terms, remove terms, etc., and doing it by hand seems messy.

Is it possible to generate a sequence of terms (not necessarily numbers) with subscripts automatically, given perhaps the term label and length of sequence for starters, and then possible additional options like: step, which terms to include, commas/spaces, etc.?

Basically, I want something like this:

enter image description here enter image description here

From perhaps something like this:

\seq{a}{1..2n}{1,3,2}
Skip(L)=\{~\seq{a}{1..2n-1}{2,2,1} ~|~ \seq{a}{1..2n}{1,3,2} \text{ is in } L~\}

Instead of having to write this:

a_1~a_2~a_3~\ldots~a_{2n-1}~a_{2n}
Skip(L)=\{~a_1~a_3~\ldots~a_{2n-1} ~|~ a_1~a_2~a_3~\ldots~a_{2n-1}~a_{2n} \text{ is in } L~\}

Maybe there is a discrete math or formal languages package specifically that can do this? I'm Googling, but haven't found what I'm looking for yet.

  • 1
    What does each argument do? I mean \seq{a}{1...2n} seems logical for me, what do the other arguments do? – Manuel Feb 1 at 23:32
  • @Manuel Those extra arguments might be for specifying number of specified starting terms and number of ending terms, e.g. {2,1} And the other argument was for a maybe a step, e.g. every term {1}, or every other term {2}, etc. Don't know if anything like that exists though... – delrocco Feb 1 at 23:41
  • @delrocco Can we assume you will always only input 1 item, three dots, and last item? Or you want more flexibility? – Manuel Feb 1 at 23:44
  • @Manuel The number of terms at start and end of sequence are not critical I'd say to most sequences, and a good start if you have a solution for that. I'm using my professor specific sequences here in his notes/homeworks. Also, I could see sequences when they would be critical. – delrocco Feb 1 at 23:44
5

Syntax: \seq[⟨steps before ellipsis⟩,⟨steps after ellipsis⟩]{⟨term label⟩}[⟨step⟩]{⟨first index⟩,...,⟨last index⟩} where every [..] is optional.

\documentclass{scrartcl}

\usepackage{mathtools,amssymb}
\DeclareMathOperator\Skip{Skip}

\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand \seq { o m o m }
 {
  \group_begin:
  \IfValueT {#1}
   {
    \int_set:Nn \l_delrocco_ini_int { \clist_item:nn {#1} {1} }
    \int_set:Nn \l_delrocco_fin_int { \clist_item:nn {#1} {2} }
   }
  \IfValueT {#3}
   {
    \int_set:Nn \l_delrocco_step_int { #3 }
   }
  \delrocco_seq:nn { #2 } { #4 }
  \group_end:
 }

\int_new:N  \l_delrocco_ini_int
\int_set:Nn \l_delrocco_ini_int  { 3 }
\int_new:N  \l_delrocco_fin_int
\int_set:Nn \l_delrocco_fin_int  { 2 }
\int_new:N  \l_delrocco_step_int
\int_set:Nn \l_delrocco_step_int { 1 }


\cs_set_eq:NN \math_sb:n \sb

\cs_new_protected:Npn \delrocco_seq:nn #1 #2
 {
  \int_step_inline:nnnn
   { \clist_item:nn {#2} {1} }
   { \l_delrocco_step_int }
   { \clist_item:nn {#2} {1} + (\l_delrocco_ini_int - 1) * \l_delrocco_step_int }
   { #1 \math_sb:n { ##1 } \, }
  \!\cdots  
  \int_step_inline:nnnn
   { (\l_delrocco_fin_int - 1) * \l_delrocco_step_int }
   { -\l_delrocco_step_int }
   { \l_delrocco_step_int }
   { #1 \math_sb:n { \clist_item:nn {#2} {3} - ##1 } \, }
  #1 \math_sb:n { \clist_item:nn {#2} {3} }
 }
\ExplSyntaxOff

\begin{document}
$\seq[4,4]{a}[2]{5,...,2n}$
\[
  \Skip(L) = \{ \seq[2,1]{a}{1,...,2n-1} \mid \seq{a}{1,...,2n} \in L \}
\]
\end{document}

If you don't want the spaces remove every instance of \, and \!.

  • This is nice! I'm customizing it a bit. I take it there is no standard package for doing formal language stuff like this? – delrocco Feb 2 at 0:37
  • I modified it so all the optionals are in one array, and the default start and end number of terms is 1. So you use it like \seq[3,3,2]{a}{1,...,2n} or \seq{a}{3,...,2n-3}. Thank you very much for your response! – delrocco Feb 2 at 1:05
  • The thing with my solution was that you could change separately the step or the other without needing to input everything. But ok! – Manuel Feb 2 at 8:28
  • Yea I noticed that. Your solution is more general. I figured most of the time I would be supplying the start and end terms only if modifying the step, so I just threw it all into one optional argument - but that may turn out to be incorrect lol We'll see ~ – delrocco Feb 3 at 4:45
2

With some pain in programming it, the following macros seem to do what you like with a not very complicated syntax.

\seq{<variable>}{<start>..<end>}[<initial>,<final>,<step>]

where <final> and <step> can be omitted and are both set to 1 in this case. If the optional argument is missing, [2,1,1] is implied.

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\seq}
 {
  m                               % base letter
  >{\SplitArgument{1}{..}}m       % <start>..<stop>
  >{\SplitArgument{2}{,}}O{2,1,1} % <initial>,<final>,<step>
 }
 {
  \delrocco_seq_print:nnnnnn { #1 } #2 #3
 }

\cs_new_protected:Nn \delrocco_seq_print:nnnnnn
 {
  \tl_if_novalue:nTF { #5 }
   {
    \__delrocco_seq_print:nnnnnn { #1 } { #2 } { #3 } { #4 } { 1 } { 1 }
   }
   {
    \tl_if_novalue:nTF { #6 }
     {
      \__delrocco_seq_print:nnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { 1 }
     }
     {
      \__delrocco_seq_print:nnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { #6 }
     }
   }
 }

\cs_new_protected:Nn \__delrocco_seq_print:nnnnnn
 {
  \mathopen{}
  \int_step_inline:nnnn { #2 } { #6 } { #2+(#4-1)*#6 }
   { \mathbin{}\nobreak #1\sb{##1} }
  \mathbin{}\nobreak\dots
  \__delrocco_seq_break:n { #3 }
  \int_step_inline:nnnn { 0-(#5-1)*#6 } { #6 } { 0 }
   {
    \mathbin{}\nobreak
    #1\sb
     {
      \l__delrocco_seq_base_tl
      \int_compare:nTF { \l__delrocco_seq_index_int + (##1) < 0 }
       {
        \int_to_arabic:n { \l__delrocco_seq_index_int + (##1) }
       }
       {
        \int_compare:nF { \l__delrocco_seq_index_int + (##1) = 0 }
         {
          \tl_if_empty:NF \l__delrocco_seq_base_tl { + }
          \int_to_arabic:n { \l__delrocco_seq_index_int + (##1) }
         }
       }
     }
   }
   \mathclose{}
 }

\seq_new:N \l__delrocco_seq_temp_seq
\tl_new:N \l__delrocco_seq_temp_tl
\tl_new:N \l__delrocco_seq_base_tl
\int_new:N \l__delrocco_seq_index_int

\cs_new_protected:Nn \__delrocco_seq_break:n
 {
  \regex_split:nnN { ([\+\-]?[0-9]+\Z) } { #1 } \l__delrocco_seq_temp_seq
  % the last item is empty if there is a base and an index
  \seq_pop_right:NN \l__delrocco_seq_temp_seq \l__delrocco_seq_temp_tl
  \seq_if_empty:NTF \l__delrocco_seq_temp_seq
   {
    \tl_set:Nn \l__delrocco_seq_base_tl {#1}
    \int_set:Nn \l__delrocco_seq_index_int { 0 }
   }
   {
    % the last but one item is the number
    \seq_pop_right:NN \l__delrocco_seq_temp_seq \l__delrocco_seq_temp_tl
    % the base
    \tl_set:Nx \l__delrocco_seq_base_tl { \seq_use:Nn \l__delrocco_seq_temp_seq {} }
    % the index
    \int_set:Nn \l__delrocco_seq_index_int { \l__delrocco_seq_temp_tl }
   }
 }


\ExplSyntaxOff

\begin{document}

$|\seq{a}{1..20}|$

$|\seq{a}{1..2n}[2,2,1]|$

$|\seq{a}{1..2n-1}[3,2,2]|$

$|\seq{a}{1..2n+1}[3,2,2]|$

$|\seq{a}{1..13}[3,2,2]|$

$\operatorname{Skip}(L)=
 \{ \seq{a}{1..2n-1}[2,1,2] \mid \seq{a}{1..2n}[3,2]\text{ is in } L \}
$

$\operatorname{Skip}(L)=
 \{ \seq{a}{1..2n-1}[2,2,2] \mid \seq{a}{1..2n}[3,3]\text{ is in } L \}
$

\end{document}

I didn't allow symbolic calculations for the starting point, but it could be added. No consistency check is done, as it would require quite a lot of algebra.

The space between items is twice \medmuskip, because an empty binary operation is set between any two items. Thisenter image description here can be customized.

  • Thank you! I modified @Manuel version so that it is used very similar to this. But this solution is technically 3 characters shorter to use, and some optional, optional arguments, which is cool. I wish I was as good as you guys as meta-programming :) – delrocco Feb 3 at 4:37

This site is temporarily in read only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .