Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like to typeset the top part of Pascal's triangle. To get the triangle with the names of the binomial coefficients, i.e., {n \choose k}, I used the following code

\begin{tikzpicture}
\foreach \n in {0,...,4} {
  \foreach \k in {0,...,\n} {
    \node at (\k-\n/2,-\n) {${\n \choose \k}$};
  }
}
\end{tikzpicture}

The result is this enter image description here

Now I want to be equally lazy and do something like this for the values of the binomial coefficients, i.e., replace {\n \choose \k} in the node label with \CalculateBinomialCoefficient{\n}{\k} where \CalculateBinomialCoefficient is a hypothetical macro that calculates the binomial coefficient. Has anyone done something like that?

The result should look like this: enter image description here

share|improve this question
    
The code in Triangle de Pascal could give you some ideas; note the use of the \FPpascal macro implemented in fp-pas.sty (part of the fp package). –  Gonzalo Medina May 6 '11 at 0:49
2  
For a better result I suggest to use the command \binom{a}{b} from the amsmath package instead of {a \choose b} for binomial coefficients –  Spike May 6 '11 at 8:44

4 Answers 4

Second answer

The earlier answer used a macro computing individual binomial coefficients.

I now address the matter building row by row of the Pascal Triangle, as in the other answers.

For this as an exercise of translation I have taken an exact copy of the metapost code of @fpast's answer, and translated it into TeX. Up the the 34th row we can use TeX arithmetic. For simplicity I used \numexpr. Starting with the 34th row (actually there only the middle three coefficients exceeds 2^31-1) I use big integer arithmetic.

To organize the loops I use \xintFor from package xinttools. This package also defines \odef which does a definition + expansion and \oodef which does a definition + double expansion. They are used in the code together with various mixes of \numexpr, \dimexpr, \@namedef, @nameuse etc... pure TeX/LaTeX joys with its subtleties at times about where spaces are allowed or not (most spaces do not matter much as we are in a TikZ picture).

The code for the first 80 lines compile not too slowly (about 9 seconds on my laptop).

I only display the largest numbers of the triangle.

Notice that we are close to the TeX limits for the maximal dimension as each number is separated horizontally by 6cm from its neighbour.

The original metapost code of fpast is shown alongside its translation into TeX.

edit the code tested the line number to use only \numexpr for the first 33 lines (as only integers <2^31 are then evaluated) but actually doing all the computations with xint and not checking for the line number to decide to use \numexpr or xint is faster! (about 2% faster when computing 80 lines of the triangle). I thus comment out the conditionals.

\documentclass[12pt, tikz, border=5mm]{standalone}
\usepackage{tikz}
\usepackage{xint}
\usepackage{xinttools}
\makeatletter
\newdimen\X
\newdimen\Y
\def\PascalTriangle #1#2#3{% #1=n (integer) #2=u (dimension) #3=v (dimension)
 %    save b, mid; numeric b[][], mid; clearxy;  
 %    b[0][0] = b[1][0] = b[1][1] = 1;
 %    label("1", origin); label("1", (-.5u, -v)); label("1", (.5u, -v));
    \edef\U {\the\numexpr\dimexpr #2\relax }% convert to sp units
    \edef\V {\the\numexpr\dimexpr #3\relax }%
    \@namedef{dali@0@0}{1}%
    \@namedef{dali@1@0}{1}%
    \@namedef{dali@0@1}{1}%
    \node at (0,0) {$1$};%
    \node at (-.5*#2,-#3) {$1$};
    \node at (.5*#2,-#3)  {$1$};
  % for i = 2 upto n:
    \xintFor ##1 in {\xintegers[2+1]}\do {%
    \ifnum #1<##1\expandafter\xintBreakFor\fi
  %        mid := i div 2;
          \odef\Mid  {\the\numexpr (##1+1)/2 -1\relax }%
  %       x := -u*i/2;
          \X = \dimexpr\the\numexpr (-##1*\U)/2\relax sp
  %       y := -i*v ;
          \Y = \dimexpr\the\numexpr -##1*\V\relax sp
  %       b[i][0] = 1; label("1", z); label("1", (-x, y));
          \@namedef{dali@\the##1@0}{1}%
          \node at (\X,\Y)  {$1$};
          \node at (-\X,\Y) {$1$};
  %       for k = 1 upto mid:
          \xintFor ##2 in {\xintegers[1+1]}\do {%
          \ifnum\Mid<##2\expandafter\xintBreakFor\fi
  %           x := x + u;
              \advance\X by #2\relax
              \let\next\@secondoftwo
  %           if (k < mid) or (odd i):
              \ifnum \Mid>##2\let\next\@firstoftwo\fi
              \ifodd      ##1\let\next\@firstoftwo\fi
              \next
            {%
  %               b[i][k] = b[i-1][k-1] + b[i-1][k]; 
  %          \ifnum ##1<34 % binomial coefficients are < 2^31
  %          % EDIT DROPS THIS CONDITIONAL
  %             \expandafter\odef\csname dali@\the##1@\the##2\endcsname
  %             {\the\numexpr\@nameuse{dali@\the\numexpr##1-1@\the\numexpr##2-1}
  %                         +\@nameuse{dali@\the\numexpr##1-1@\the##2}\relax }%
  %          \else % 34 choose 17 is 2333606220 > 2^31-1 = 2147483647
               \expandafter\oodef\csname dali@\the##1@\the##2\endcsname
               {\xintiiAdd{\@nameuse{dali@\the\numexpr##1-1@\the\numexpr##2-1}}
                          {\@nameuse{dali@\the\numexpr##1-1@\the##2}}}%
  %          \fi 
  %               label(decimal b[i][k], z); label(decimal b[i][k], (-x, y));
            \node at (\X,\Y)  {$\@nameuse{dali@\the##1@\the##2}$};
            \node at (-\X,\Y) {$\@nameuse{dali@\the##1@\the##2}$};
            }%
  %           else:
            {%
  %               b[i][k] = 2b[i-1][k-1];
  %          \ifnum ##1<34   % EDIT DROPS THIS CONDITIONAL
  %             \expandafter\odef\csname dali@\the##1@\the##2\endcsname
  %             {\the\numexpr2*\@nameuse{dali@\the\numexpr##1-1@\the\numexpr##2-1}\relax}%
  %          \else
               \expandafter\oodef\csname dali@\the##1@\the##2\endcsname
               {\xintDouble{\@nameuse{dali@\the\numexpr##1-1@\the\numexpr##2-1}}}%
  %          \fi 
  %               label(decimal b[i][k], z);
            \node at (\X,\Y) {$\@nameuse{dali@\the##1@\the##2}$};
            }%
  %           fi
  %       endfor
          }%
    % endfor
    }%
}
\makeatother

\begin{document}
\begin{tikzpicture}
   \PascalTriangle{80}{6cm}{1cm}
\end{tikzpicture}
\end{document}

binomial coefficients around binomial(80,40)


Earlier answer

(computes individual binomial coefficients)

You can do this

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tikz}


% \binomialb macro from http://tex.stackexchange.com/a/161863/4686
% expandably computes binomial coefficients with \numexpr

% START OF CODE
\catcode`_ 11

\def\binomialb #1#2{\romannumeral0\expandafter
    \binomialb_a\the\numexpr #1\expandafter.\the\numexpr #2.}

\def\binomialb_a #1.#2.{\expandafter\binomialb_b\the\numexpr #1-#2.#2.}

\def\binomialb_b #1.#2.{\ifnum #1<#2 \expandafter\binomialb_ca
                            \else   \expandafter\binomialb_cb
                            \fi {#1}{#2}}

\def\binomialb_ca #1{\ifnum#1=0 \expandafter \binomialb_one\else 
                    \expandafter \binomialb_d\fi {#1}}

\def\binomialb_cb #1#2{\ifnum #2=0 \expandafter\binomialb_one\else
                      \expandafter\binomialb_d\fi {#2}{#1}}

\def\binomialb_one #1#2{ 1}

\def\binomialb_d #1#2{\expandafter\binomialb_e \the\numexpr #2+1.#1!}

% n-k+1.k! -> u=n-k+2.v=2.w=n-k+1.k!
\def\binomialb_e #1.{\expandafter\binomialb_f \the\numexpr #1+1.2.#1.}

% u.v.w.k!
\def\binomialb_f #1.#2.#3.#4!%
{\ifnum #2>#4 \binomialb_end\fi
 \expandafter\binomialb_f
 \the\numexpr #1+1\expandafter.%
 \the\numexpr #2+1\expandafter.%
 \the\numexpr #1*#3/#2.#4!}

\def\binomialb_end #1*#2/#3!{\fi\space #2}
\catcode`_ 8
% END OR \binomialb code

\begin{document}\thispagestyle{empty}


\begin{tikzpicture}
\foreach \n in {0,...,4} {
  \foreach \k in {0,...,\n} {
    \node at (2*\k-\n,-\n) {${\n \choose \k} = \binomialb\n\k$};
  }
}
\end{tikzpicture}

\bigskip\bigskip

\begin{tikzpicture}
\foreach \n in {21,...,24} {
  \foreach \k in {10,...,\the\numexpr\n-11\relax} {
    \node at (3*\k-1.5*\n,-\n) {${\n \choose \k} = \binomialb\n\k$};
  }
}
\end{tikzpicture}


%\bigskip\bigskip

% arithmetic overflow, use xint and \binomialB !
% \begin{tikzpicture}
% \foreach \n in {30,...,34} {
%   \foreach \k in {15,...,\the\numexpr\n-15\relax} {
%     \node at (4*\k-2*\n,-\n) {${\n \choose \k} = \binomialb\n\k$};
%   }
% }
% \end{tikzpicture}

\end{document}

enter image description here

share|improve this answer
    
Wow! I am dazzled by your skills in TeX programming. All this seems most complicated to me, even more so knowing that it is translated from my own MetaPost program. And I never imagined that TeX could handle such big numbers. –  Franck Pastor Mar 16 at 12:16
    
Package xint does expandable arithmetic with "arbitrarily big" integers. An earlier package was bigintcalc. Expandability allows among other things intuitive "composition of macros" rather than the style of \pgfmathparse or \FPadd to cite other mathematical engines. Expandability is implemented in the strongest sense by xint. Starting with numbers having hundreds of digits this makes the macro slower. If one were to drop expandability, it would be possible to implement much faster routines. –  jfbu Mar 16 at 16:10
    
@fpast Package xintfrac extends xint to handle exactly fractions A/B or decimal numbers. Packages with non expandable arbitrary precision fixed point arithmetic exist, but this does not mean that they are faster than the expandable xintfrac for numbers with less than one hundred digits. To the contrary in the case of xintfrac \xintXTrunc which admittedly is completely expandable, but not in the strongest sense as for the other xint macros. –  jfbu Mar 16 at 16:13

Done with MetaPost, several years too late.

The Pascal_triangle macro defined below takes three arguments, the number of rows n (starting from 0), the horizontal space between consecutive coefficients in the same row and the vertical space between two consecutive rows. It uses the well-known recursive relation between binomial coefficients, in an iterative way and a straightforward manner (it doesn't take any symmetry into account), yet it is more efficient than I expected: it works up to the first 56 rows.

\documentclass[12pt, border=5mm]{standalone}
\usepackage{luamplib}
    \mplibnumbersystem{double}
    \mplibtextextlabel{enable}
\begin{document}
\begin{mplibcode}
vardef Pascal_triangle(expr n, u, v) =
    save b; numeric b[][]; clearxy;
    b[0][0] = 1; b[0][1] = 0; label("1", origin);
    for i = 1 upto n:
        x := -u*i/2; y := -i*v;
        b[i][0] = 1; label("1", z);
        for k = 1 upto i:
            x := x + u;
            b[i][k] = b[i-1][k-1] + b[i-1][k]; label(decimal(b[i][k]), z);
        endfor b[i][i+1]=0;
    endfor
enddef;

beginfig(1);
    Pascal_triangle(19, 1.4cm, 1cm);
endfig;
\end{mplibcode}
\end{document}

To be executed with LuaLaTeX. This example shows the first 20 rows of the triangle (n=19):

enter image description here

Edit Here is a version which makes use of the symmetry of Pascal's triangle, with the same output as before, of course. It was quite a bit more difficult for me to sort that one out (probably because I have not found the most clever way of doing it ;-)), and I have not noticed any difference in speed nor in efficiency with the previous version.

\documentclass[12pt, border=5mm]{standalone}
\usepackage{luamplib}
    \mplibnumbersystem{double}
    \mplibtextextlabel{enable}
\begin{document}
\begin{mplibcode}
vardef Pascal_triangle(expr n, u, v) =
    save b, mid; numeric b[][], mid; clearxy;  
    b[0][0] = b[1][0] = b[1][1] = 1;
    label("1", origin); label("1", (-.5u, -v)); label("1", (.5u, -v)); 
    for i = 2 upto n:
        mid := i div 2; 
        x := -u*i/2; y := -i*v; 
        b[i][0] = 1; label("1", z); label("1", (-x, y));
        for k = 1 upto mid:
            x := x + u;
            if (k < mid) or (odd i):
                b[i][k] = b[i-1][k-1] + b[i-1][k]; 
                label(decimal b[i][k], z); label(decimal b[i][k], (-x, y));
            else:
                b[i][k] = 2b[i-1][k-1];
                label(decimal b[i][k], z);
            fi
        endfor
  endfor
enddef;

beginfig(1);
    Pascal_triangle(19, 1.4cm, 1cm);
endfig;
\end{mplibcode}
\end{document}
share|improve this answer

Here is a solution using TeX integer arithmetic. I am reusing counters defined by PGF in order to avoid having to declare new ones.

\documentclass{article}
\usepackage{tikz}

\makeatletter
\newcommand\binomialCoefficient[2]{%
    % Store values 
    \c@pgf@counta=#1% n
    \c@pgf@countb=#2% k
    %
    % Take advantage of symmetry if k > n - k
    \c@pgf@countc=\c@pgf@counta%
    \advance\c@pgf@countc by-\c@pgf@countb%
    \ifnum\c@pgf@countb>\c@pgf@countc%
        \c@pgf@countb=\c@pgf@countc%
    \fi%
    %
    % Recursively compute the coefficients
    \c@pgf@countc=1% will hold the result
    \c@pgf@countd=0% counter
    \pgfmathloop% c -> c*(n-i)/(i+1) for i=0,...,k-1
        \ifnum\c@pgf@countd<\c@pgf@countb%
        \multiply\c@pgf@countc by\c@pgf@counta%
        \advance\c@pgf@counta by-1%
        \advance\c@pgf@countd by1%
        \divide\c@pgf@countc by\c@pgf@countd%
    \repeatpgfmathloop%
    \the\c@pgf@countc%
}
\makeatother

\begin{document} 
\begin{tikzpicture}
\foreach \n in {0,...,15} {
  \foreach \k in {0,...,\n} {
    \node at (\k-\n/2,-\n) {$\binomialCoefficient{\n}{\k}$};
  }
}
\end{tikzpicture}

\end{document}

enter image description here

If you want, you can wrap \pgfmathdeclarefunction around that to have the function available in pgfmath (see Section 65 “Customizing the Mathematical Engine” in the manual (v2.10)).

share|improve this answer
    
Nice solution! It works up to the first 30 rows! –  Gonzalo Medina May 6 '11 at 2:42
    
Is it easy to change this triangle to this one here with a slight change to the addiction $N=2R+L$? –  hhh Feb 5 at 2:45

From texample.net. The author is Paul Gaborit.

Triangle de Pascal

enter image description here

share|improve this answer
    
Such a pity this can't do more than the 16 rows shown here. Someone needs to write an arbitrary integer type for TikZ ;) –  Christian Sep 22 '13 at 14:00
    
Is it easy to change this triangle to this one here with a slight change to the addiction $N=2R+L$? –  hhh Feb 5 at 2:49

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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