2

I've try to modify the animate of Sieve of Eratosthenes from the code (author: Peter Grill): http://www.texample.net/tikz/examples/eratosthenes-sieve/

All I've done is I removed the title and the texts in the right sides.

But there are some problems here:

  • The first frame can work properly, the scope of the picture is exactly what I want first
    • But from the second frame on, the scope of the picture is smaller, you can see a big vertical space between the title and the picture enter image description here

HOW to maintain the same scope of the picture with the frist frame?

Here is my code:

    \documentclass[t]{beamer}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usetheme{default}

\usepackage{geometry}

\usepackage{microtype}%       Allow comma into margin in list of primes
\usepackage{xstring}%         String comparison
\usepackage{tikz}%            Drawing
\usetikzlibrary{calc}%        Coordinate calculations
\usetikzlibrary{backgrounds}% Apply shading on background layer
\usepackage{animate}


\begin{document}



\def\NumOfColumns{10}% See note above if product of  
\def\NumOfRows{10}%    NumOfColumns and NumOfRows > 100.

%% \FramesToHoldAtEnd should be larger than the number of primes
%% so that they can get highlighted at the end of the process
\def\FrameRate{1}%
\def\FramesToHoldAtStart{1}%
\def\FramesToHoldAtEnd{25}% 25 is enough for 10x10


\def\Scale{0.6}% May need tweaking..


\def\PrimeColor{green!80!red}%  Shade for primes found previously
\def\NewPrimeColor{green!80!red}% Shade for prime just found
\def\NewPrimeText{red}%  Color for primes in list
\def\NonPrimeColor{yellow!80!red}%  Shade for non-primes


%% List of Primes is typeset into a \node of this width.
\def\TextWidth{2.0cm}%


% Simplifies code below if we just redefine these two from the
% animate package so that they do don't much.
%\renewenvironment{animateinline}[1]{\begingroup}{\endgroup}% 
%\renewcommand{\newframe}[1][]{\newpage}%




%%% ---------------------------------------------------------------
%%% Should not need to adjust anything below this line
%%%
\pgfmathtruncatemacro{\MaxNumber}{\NumOfRows*\NumOfColumns}%
\pgfmathtruncatemacro{\MaxValue}{sqrt(\MaxNumber)}%

% Choose opacity so that we can have the max number of shades
%\pgfmathsetmacro{\Opacity}{1.0/min(5,\MaxValue-1)}%
\pgfmathsetmacro{\Opacity}{0.4}%

%% The Sieve algorithm requires that once a number is marked
%% as non-prime (i.e., was a multiple of some other number)
%% we don't need to check multiples of that number as they
%% have already been marked as non-prime.
%%
%% Usually one would use an array and set a flag.  But since
%% variables with numbers are difficult with TeX, we can
%% define a node named with the number that is non-prime.
%% Then just check that the node exists to see if it was 
%% marked as non-prime.

\makeatletter
% Mark number as either "Prime" or "NonPrime".
\newcommand*{\MarkNumber}[2][NonPrime]{\node (#1#2) {}}% #1=prefix, #2=num

% https://tex.stackexchange.com/questions/37709/how-can-i-know-if-a-node-is-already-defined
\newcommand{\IfNumberAlreadyMarked}[4][NonPrime]{% #1=prefix, #2=num
\pgfutil@ifundefined{pgf@sh@ns@#1#2}{#4}{#3}%
}

% https://tex.stackexchange.com/questions/20655/how-to-undo-a-def-i-e-need-a-undef-capability
\newcommand*\@nameundef[1]{%
\global\expandafter\let\csname #1\endcsname\@undefined%
}

%% Since we repeat the process from the beginning for the animated
%% version, use this to clear the nodes so that the numbers are
%% not marked as multiples of a number from the previous run.
\newcommand{\ClearAllNumberedNodeNames}{%
\foreach \i in {1,...,\MaxValue}{%
    \@nameundef{pgf@sh@ns@NonPrime\i}%
    \@nameundef{pgf@sh@ns@Prime\i}%
}%
}
\makeatother

%% The Sieve algorithm skips multiples of numbers already marked as
%% non-prime.  So, to number the individual steps, need to use
%% a counter.
%% i.e., Step 4 is processing multiples of 5 (since we skip 4).
\newcounter{StepNumber}%


%%% ---------------------------------------------------------------
%%%
%%%  Titles and Labels
%%%

\newcommand\ListOfPrimes{}
\newcommand\AddToListOfPrimes[2][fill=\PrimeColor]{%
\IfStrEq{\ListOfPrimes}{}{%
    \def\Separator{}%   First member of list of primes
}{%
    \def\Separator{, }% Subsequent member of list of primes
}%
%
\FillCellForGivenNumber[#1]{#2};%
\global\edef\ListOfPrimes{\ListOfPrimes\Separator#2}%
\MarkNumber[Prime]{#2};%
}

\newcommand*{\ClearListOfPrimes}{%
\ClearAllNumberedNodeNames;%
\renewcommand{\ListOfPrimes}{}%
}

%%% ---------------------------------------------------------------

%%%
%%% Step 1: Create a list of integers 2...n
%%%
\newcommand*{\DrawGridWithNumbers}{%
\begin{scope}% Add numbers to each node
    \draw  (0,-1) -- ($(0,-\NumOfRows-1)$);
    \foreach \col in {1,...,\NumOfColumns} {%
        \draw  (\col,-1) -- ($(\col,-\NumOfRows-1)$);

        \draw  (0,-1) -- (\NumOfColumns,-1);
        \foreach \row in {1,...,\NumOfRows}{%
            \pgfmathtruncatemacro{\value}{\col+\NumOfColumns*(\row-1)}
            \IfEq{\value}{1}{
                %% Suppress number 1 from being printed since first  
                %% step of Sieve of Eratosthenes algorithm is to 
                %% create a list of integers 2...n
            }{
                \node at ($(\col,-\row)-(0.5,0.5)$) {\value};
            }
            \draw (0,-\row-1) -- (\NumOfColumns,-\row-1);
        }
    }
\end{scope}

%% Since we just drew the grid we should ensure that none
%% of the numbered nodes exist (i.e., that no numbers
%% are marked as non-prime.  And reset list of primes.

\ClearListOfPrimes;
\ClearAllNumberedNodeNames;

%\ShowListOfPrimesNode;
}

\newcommand*{\FillCellForGivenNumber}[2][]{%
%% #1 = fill options
%% #2 = number
%%
\pgfmathtruncatemacro{\Column}{mod(#2,\NumOfColumns)}%
\IfEq{\Column}{0}{\pgfmathtruncatemacro{\Column}{\NumOfColumns}}{}%
\pgfmathtruncatemacro{\Row}{(#2-1)/\NumOfColumns+1}%

\begin{scope}[on background layer]
    \fill [#1]
        (\Column-1,-\Row) --
        ($(\Column-1,-\Row)+(1,0)$) --
        ($(\Column-1,-\Row)+(1,-1)$) -- 
        (\Column-1,-\Row-1) --
        cycle;
\end{scope}
}



\newcommand*{\ColorMultiplesOf}[2][0]{%
%% If only 1 arg is given (i.e., #1=0), then 
%%     #2 = the multiple for which the coloring is applied
%%
%% If two args are given (i.e., #1 != 0) then
%%     #1 = Value of \MaxMultiple (used for animated version)
%%          In the two arg case we run the entire sequence 
%%          from the beginning up until the multiple #1*#2 
%%          is reached.

\IfEq{#1}{0}{% Run the entire sequence
    \pgfmathtruncatemacro{\MaxMultiple}{\MaxNumber/#2}
}{%            Run sequence up until number given for animating
    \def\MaxMultiple{#1}
}

\foreach \i in {2,...,\MaxMultiple} {
    \pgfmathtruncatemacro{\NonPrimeNumber}{\i*#2}
    \FillCellForGivenNumber[
            fill=\NonPrimeColor, 
            fill opacity=\Opacity
        ]
        {\NonPrimeNumber};
    \MarkNumber[NonPrime]{\NonPrimeNumber};
}
}


\newcommand*{\BuildFrameInternals}[2][0]{%
%% #1 = current multiple to which to build the pattern up to
%%      if #1=0 and #2=\MaxValue, then we are in an end hold frame
%% #2 = number of whose multiples we are eliminating in this step
%%      if #2=1, then only draw grid (provides hold frame at start)

%%\AddTitleNode;% Print Main title if \AnimateSieve is defined

\DrawGridWithNumbers;
\IfEq{#2}{1}{%
    %% This is a hold frame at start so only show grid of numbers
    %%\AddInitialSubTitleNode{#2};
}{%
    \IfEq{#2}{2}{%
        %% No pre-processing steps to be done in this case
    }{%
        %% Since we are eliminating multiples of a number  
        %% other than 2, we need to get the table up to  
        %% the state where all the multiples of 2...(#2-1) 
        %% are eliminated.

        \pgfmathsetmacro{\PreviousMultiple}{#2 - 1}%
        \foreach \n in {2,...,\PreviousMultiple} {%
            \IfNumberAlreadyMarked[NonPrime]{\n}{%
                %% Skip. Multiples are already marked as non-prime
                %% since this number is a multiple of a smaller
                %% prime.
            }{%
                %% This is a prime. Mark it as prime, and mark 
                %% its multiples as non-prime.
                \AddToListOfPrimes[fill=\PrimeColor]{\n};
                \ColorMultiplesOf{\n};
            }
        }
    }

    \IfNumberAlreadyMarked[NonPrime]{#2}{%
        %% Already taken care of in a previous run.  This test
        %% is needed to cover the case where the value of the
        %% sqrt{NumberOfColumns x NumberOfRows) is not prime.
        %% For example: 10x10.
    }{%
        %% Now eliminate the numbers up to the current state
        \AddToListOfPrimes[fill=\NewPrimeColor]{#2};
        \ColorMultiplesOf[#1]{#2};
    }

    %% If we are holding the very final result don't print title.
    %% This is the case when #2=\MaxValue and #1=0.
    %%
    %% Need to do this at the end so that we can access
    %% which numbers have been marked as non-prime.

    \IfEq{#2}{\MaxValue}{%
        %\IfEq{#1}{0}{%
            %% This is the final hold frame
            %%\SubTitleFinal;

            \IfNumberAlreadyMarked[NonPrime]{#2}{%
            }{%
                \IfNumberAlreadyMarked[Prime]{#2}{%
                    %% In this case, #2 is not a new prime so 
                    %% correct its color. So, don't add it to the
                    %% list of primes, but correct ensure its
                    %% color corresponds to an old prime
                    \FillCellForGivenNumber[fill=\PrimeColor]{#2};
                }{%
                    %% In this case, #2 is a new prime so 
                    %% add it to the list of primes,                
                    \AddToListOfPrimes[fill=\NewPrimeColor]{#2};
                }%
            }%

            %% But since this is the final hold frame, we need
            %% to mark all the numbers not already marked as 
            %% non-prime as prime. Do one at at time, so that
            %% this can be seen in the animation.

            \pgfmathtruncatemacro{\StartValue}{\MaxValue+1}%
            \foreach \p in {\StartValue,...,\MaxNumber}{%
                \IfNumberAlreadyMarked[NonPrime]{\p}{%
                    %% This number has been marked as non-prime
                }{%
                    %% This is a prime
                    \IfNumberAlreadyMarked[Prime]{\p}{%
                        %% Already found this prime earlier.
                        %% So ensure it has appropriate fill.
                        \AddToListOfPrimes[fill=\PrimeColor]{\p};%
                    }{%
                        %% New prime: Mark it as such, and 
                        %% break out to complete this frame.
                        \AddToListOfPrimes[fill=\NewPrimeColor]{\p};%
                        \MarkNumber[Prime]{\p};%
                        %%\AddSubTitleNode{};%
                        \breakforeach;%
                    }%
                }%
            }%
        %}{%
            %% Not final hold frame, so normal title
            %%\AddSubTitleNode{#2};%
        %}%
    }{%
        %%\AddSubTitleNode{#2};%
    }%
}%
%%\ShowListOfPrimesNode%
}%



\newcommand*{\BuildFrame}[2][0]{%
%% #1 = current multiple to which to build the pattern up to
%% #2 = number of whose multiples we are eliminating in this step
%%      if #2=1, then only draw grid (provides hold frame at start)
\noindent%
\centering%
\begin{tikzpicture}[yscale=\Scale]%
    \BuildFrameInternals[#1]{#2};
\end{tikzpicture}%
%
}%

\newcommand*{\BuildFinalFrame}{%
\noindent%
\centering%
\begin{tikzpicture}[yscale=\Scale]%
    %%\AddTitleNode;% Print Main title if \AnimateSieve is defined
    %%\AddSubTitleNode{};
    \DrawGridWithNumbers;
    \foreach \p in {2,...,\MaxValue}{%
        \IfNumberAlreadyMarked[NonPrime]{\p}{%
        }{%
            \AddToListOfPrimes[fill=\PrimeColor]{\p};
            \ColorMultiplesOf{\p};
        }%
    }%
    \pgfmathtruncatemacro{\StartValue}{\MaxValue+1}%
    \foreach \p in {\StartValue,...,\MaxNumber}{%
        \IfNumberAlreadyMarked[NonPrime]{\p}{%
            %% This number has already been marked as non-prime
        }{%
            %% This is a prime. Since we are just printing out
            %% the final results we don't distinguish between a
            %% newly found prime and a prime found previously.
            \AddToListOfPrimes[fill=\PrimeColor]{\p};
        }%
    }%

    %\ShowListOfPrimesNode;
\end{tikzpicture}%
%
}

\newcounter{CountK}
\newcounter{CountP}
\newcounter{CurrentMaxMultiplePlusOne}
%



\begin{frame}{Sieve of Eratosthenes}
\begin{animateinline}[autopause,controls, buttonsize=1.2em, buttonbg=1:0.78:0,buttonfg=0.2:0.2:0.2]{\FrameRate}%
    \stepcounter{StepNumber}%
    \setcounter{CountK}{0}%
    \whiledo{\arabic{CountK} < \FramesToHoldAtStart}{%
        \BuildFrame[0]{1}% initial hold frame
        \newframe[\FrameRate]%
        \stepcounter{CountK}%
    }%
    %
    \setcounter{CountK}{2}%
    \whiledo{\numexpr\arabic{CountK}-1 < \MaxValue}{%
        \IfNumberAlreadyMarked[NonPrime]{\arabic{CountK}}{%
            %% \value{CountK} has already been marked as non-prime.
            %% Hence, so so are its multiples, and we can skip it.
        }{%
%% Question 1: Should be able to replace three lines following with
%%             this. But then animation seems to skip the loop below
% \pgfmathsetcounter{CurrentMaxMultiplePlusOne}{1+(\MaxNumber/\arabic{CountK})}%
            \pgfmathtruncatemacro{\MaxMultiple}{\MaxNumber/\arabic{CountK}}%
            \setcounter{CurrentMaxMultiplePlusOne}{\MaxMultiple}%
            \stepcounter{CurrentMaxMultiplePlusOne}%
            %
            \setcounter{CountP}{2}% 
            \stepcounter{StepNumber}%
%% Question 2: Ideally would prefer to use the following syntax
%%             but this does not even compile!!!   But, an indentical
%%             syntax works in the above `\whiledo`, where the value of
%%             \MaxValue was also defined by \pgfmathtruncatemacro
%               \whiledo{\numexpr\arabic{CountP}-1 < \MaxMultiple}{%
            \whiledo{\arabic{CountP} < \arabic{CurrentMaxMultiplePlusOne}}{%            
                \BuildFrame[\theCountP]{\theCountK}%
                \newframe[\FrameRate]%
                \stepcounter{CountP}%
            }%
        }%
        \stepcounter{CountK}%
    }%
    % At end, add hold frames in case we are looping
    %
    % There needs to be enough of these so that each of the
    % primes (those not colored in) get highlighted at each frame.
    %
    \setcounter{CountK}{2}%
    \whiledo{\numexpr\arabic{CountK}-1 < \FramesToHoldAtEnd}{%
        \BuildFrame{\MaxValue}%
        \newframe[\FrameRate]%
        \stepcounter{CountK}%
    }
\end{animateinline}%
\end{frame}
\end{document}

To compile the code may require more memory, I just edit the file texmf.cnf under C:\texlive\2018\texmf.cnf, and add the following code at the end of the file:

main_memory=12435455
extra_mem_top=60000000​
extra_mem_bot=5000000
font_mem_size=5000000
pool_size=5000000
buf_size=5000000

and then compile with XeLaTex

xaero
  • 459
  • Could you please consider removing all nonstandard characters from your code? Having them in prevents people from just copying and running your code. –  Sep 16 '18 at 14:26
  • Hm, looks like accumulated spurious space. Perhaps by uncommented line ends repeated in some loop. – AlexG Sep 16 '18 at 17:17
  • OK, I'v removed all nonstandard characters – xaero Sep 17 '18 at 00:44
  • @xaero, your code still doesn't compile. If you have made so many modifications to your settings (latex or editor) that you can run it, please use a online service like "sharelatex" or "overleaf" to make sure it compiles for us too. – koleygr Sep 17 '18 at 01:06
  • @koleygr, I compile withe xelatex, I'v modified some code , but I did't modify any compiler or editor...May be you can compile the code second or third times may works – xaero Sep 17 '18 at 01:17
  • 1
    @koleygr, Sorry, I'v edited the texmf.cnf file under C:\texlive\2018\texmf.cnf and added following code:main_memory=12435455 extra_mem_top=60000000​ extra_mem_bot=5000000 font_mem_size=5000000 pool_size=5000000 buf_size=5000000...Could you please compile the code second or third times may works. – xaero Sep 17 '18 at 01:28
  • Sorry, I can't do such changes in my PC... I already use overleaf to compile codes from here and your code doesn't compile there... May be someone else will try to do it by making the changes you mentioned on his/her PC. So, your last comment is useful until someone will try this. – koleygr Sep 17 '18 at 01:49
  • It might be easier to debug if you modified the code to produce just the first two frames that where the problem shows up. – Peter Grill Sep 19 '18 at 17:36
  • How to produce just only the first two frames?@PeterGrill – xaero Sep 23 '18 at 10:46

0 Answers0