8

Let's suppose that I have a very complicated function that depends on i and j. So I define a new command, say

\newcommand{\foo}[2]{X_{i+j+1}}. % This might be an complicated expression, but I want to keep it simple

Using this definition, I can invoke this command like \foo{\alpha}{\beta} or \foo{2}{3}. Now, what I want to get is if both of arguments are numerical values, I want to force them to evalue this expression, i.e., \foo{2}{3} should generate X_{6} instead of X_{2+3+1}. It is sometimes annoying that I should manually simplify it even though I know the full expression.

I actually feel this seems almost impossible but I anyway would like to ask in case there exists some workarounds.

  • 1
    There are packages (tikz for one) which perform calculations. But it you want to do it yourself, you can use counters amd lengths (or counts and dims for plain TeX), but you will be limited to addition and multiplication. – John Kormylo Sep 4 '14 at 23:57
  • 3
    The sagetex package gives you access to a computer algebra system and the Python language. You insert calculations with \sage{} similar to the \foo{} macro you mention. You'll need to install Sage on your computer or use Sagemath Cloud (free). – DJP Sep 5 '14 at 0:00
10

This seems to be a job for l3regex:

\documentclass{article}
\usepackage{xparse,l3regex}

\ExplSyntaxOn
\NewDocumentCommand{\evaluateorprint}{m}
 {
  \regex_match:nnTF { [^0-9+\-] } { #1 }
   { #1 }                 % symbolic expression
   { \int_eval:n { #1 } } % only numbers, + or -
 }
\ExplSyntaxOff

\newcommand\foo[2]{%
  X_{\evaluateorprint{#1+#2+1}}%
}

\begin{document}
\[
\foo{2}{3}+\foo{\alpha}{\beta}
\]
\end{document}

enter image description here

A version without l3regex that might be more likely accepted by publishers relying on older TeX distributions (courtesy of Bruno Le Floch):

\ExplSyntaxOn
\NewDocumentCommand{\evaluateorprint}{m}
 {
  \group_begin:
  \cs_set_eq:NN \__sungmin_eval:n \int_eval:n
  \tl_map_inline:nn { #1 }
   {
    \tl_if_in:nnF { 0123456789+-*() } { ##1 }
     {
      \cs_set_eq:NN \__sungmin_eval:n \use:n
     }
   }
  \__sungmin_eval:n { #1 }
  \group_end:
 }
\ExplSyntaxOff

The function \__sungmin_eval:n is tentatively set equal to \int_eval:n; then the argument is scanned token by token; if something not legal in a numeric expression is found, \__sungmin_eval:n is changed into \use:n that simply outputs the argument without any processing.

  • It is a brilliant idea to use regex in this context. I have two more questions regarding the status of those packages(Please forgive me if i the questions sound too ignorant.) As far as I understood, xparse and l3regex were made to become major building blocks of the future latex3. Is it still safe and stable to use it under latex2e environment? At some point, my work will be submitted to a scientific(physics) journal. Do ypu consider the usage of these packages are generally accepted? – Sungmin Sep 5 '14 at 8:22
  • @Sungmin It might be rejected: several publishers rely on older TeX distributions, unfortunately. You should contact the publisher to know. – egreg Sep 5 '14 at 8:31
  • 2
    @egreg: In this simple case it is not too hard to provide a solution which avoids l3regex and just uses expl3, which should work in journals (at least arXiv appears to have TeXLive 2011). Basically loop trough the input with \cs_set_eq:NN\my_eval:n\int_eval:n\tl_map_inline:nn{#1}{\tl_if_in:nnF{0123456789+-*()}{##1}{\cs_set_eq:NN\my_eval:n\use:n}}\my_eval:n{#1}. Do you want to add that to your answer, or should I provide a separate one? – Bruno Le Floch Sep 5 '14 at 8:42
  • 2
    @BrunoLeFloch Thanks. It's a pain having to be compatible with such older distributions. How many packages have appeared since TeX Live 2011 has been frozen? – egreg Sep 5 '14 at 8:52
  • I don't know how computationally expensive l3regex is, but as a rule I tend to avoid regular expressions unless they are absolutely necessary. And as @BrunoLeFloch says, it is not that hard to avoid them in this particular case. – You Sep 5 '14 at 9:08
9

I know that my solution don't look such elegant (as egregs) from first point of view, but it uses only TeX primitives so it is working for all. And it uses only 27 lines of code (on the other hand the \usepackage{xparse,l3regex} loads many tens of thousands lines of code).

% \replacestring + \addto from OPmac:
\newcount\tmpnum
\bgroup \catcode`!=3 \catcode`?=3
\gdef\replacestrings#1#2{% 
   \long\def\tmp##1#1##2!{\ifx!##2!\addto\tmpb{##1}\else\addto\tmpb{##1#2}\tmp##2!\fi}%
   \expandafter\def\expandafter\tmpb\expandafter{\expandafter}\expandafter\tmp\tmpb?#1!%
   \def\tmp##1?{\def\tmpb{##1}}\expandafter\tmp\tmpb
}
\egroup
\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}

% \evalindex{text} evaluates text if it is sum of numbers; else the text is printed
\def\evalindex#1{\def\tmpa{#1}\evalindexA#1\evalindexB.\evalindexB\evalindexA}
\def\evalindexA#1#2\evalindexA{%
   \ifx-#1\def\tmpb{#1#2}\else\def\tmpb{+#1#2}\fi
   \replacestrings+{\evalindexB+}\replacestrings-{\evalindexB-}%
   \tmpnum=0 \tmpb
}
\def\evalindexB#1#2\evalindexB{\ifx#1.\the\tmpnum
   \else \setbox0=\hbox{$\tmpnum=0#2$}%
         \ifdim\wd0=0pt \advance\tmpnum by#1#2 \else \evalindexC \fi
   \expandafter\evalindexB \fi
}
\def\evalindexC#1.\evalindexB{\fi\fi \tmpa}

\def\foo#1#2{X_{\evalindex{#1+#2+1}}}

% tests:
$\evalindex{i+j+1} \quad \evalindex{1+2\alpha+3}\quad \evalindex{-1+20-3}$
%           i+j+1                   1+2\alpha+3                  16

$\foo ij \quad \foo\alpha\beta \quad \foo 23$
% X_{i+j+1}     X_{\alpha+\beta+1}    X_6        

\end

This gives the same results as egregs solution. But I know, you will not vote this up. It is only my hobby to play with my toys -- primitive features.

  • 1
    Why not vote up? We certainly do ;-) +1. – user11232 Sep 5 '14 at 9:37
  • +1, of course. The problem is not loading thousands of lines of code (TeX now does it in much less time it needed for shipping out a page twenty years ago); besides one can always prepare a format with that code preloaded. The problem is ensuring the code is usable in older TeX distributions, for the reasons I explained in my answer and comments thereto. I firmly believe that a well-structured approach providing predefined functions for common tasks is preferable. – egreg Sep 5 '14 at 9:47
5

Such commands can be done easily with the calculator package, although a counter approach is also possible, as long only integer indices are used.

In this case, the two arguments of \foo should be added and increased by 1, this is possible by using

\ADD{#1}{#2}{\resulta}%
\ADD{\resultb}{1}{\resultb}%

By using counters, there are for example two possibilities -- applying \setcounter and \addtocounter or \numexpr approach. \Foo and \FooAgain demonstrate this.


\documentclass{scrbook}

\usepackage{calculator}
\usepackage{forloop}

\newcounter{acounter}
\newcounter{bcounter}

\newcommand{\foo}[2]{%
\begingroup
     \def\resultA{}%
     \def\resultB{}%
     \ADD{#1}{#2}{\resultA}%
     \ADD{\resultA}{1}{\resultB}%
        X_{\resultB}
\endgroup%
}%

\newcounter{mydummycounter}
\newcommand{\Foo}[2]{%
  \setcounter{mydummycounter}{#1}%
  \addtocounter{mydummycounter}{#2}%
  \addtocounter{mydummycounter}{1}%
  Y_{\arabic{mydummycounter}}%
}%

\newcommand{\FooAgain}[2]{%
  \setcounter{mydummycounter}{\numexpr #1 + #2 +1}%
  Z_{\arabic{mydummycounter}}%
}%

\begin{document}
Testing:
\[ \foo{2}{3}  \] 

Some playing around: 
\LARGE \bfseries
\forloop{acounter}{1}{\value{acounter} < 11}{%
        \forloop{bcounter}{1}{\value{bcounter} < \value{acounter}}{%
        \( \foo{\number\value{acounter}}{\number\value{bcounter}} \)
        }

}
\end{document}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.