Does a single \path for drawing a series of geometrical objects make the compilation more efficent?

The TikZ syntax is so liberal (as mentioned in the documentation) that makes me a bit confused with which I have to adopt. Best practice is really my main consideration in coding anything.

I have no knowledge of the internal details how TikZ parses the input source code during the compilation. Please consider the following 2 cases.

1. With a single \path command for a series of geometrical objects.

\path
(0,0) circle (1) [draw]
-- (1,1) node[above] {x}
+(1,-1) rectangle ++(2,2)[draw];

2. With a single \path command for each object.

\draw (0,0) circle (1);
\draw (0,0) -- (1,1) node[above] {x};
\draw (1,1) +(1,-1) rectangle ++(2,2);


Does a single \path in the first case make the compilation more efficent (compared to the second case)?

How about the produced PDF, is there any difference in file size?

Of course I agree with the following quote.

Writing what is clearer to the reader of the code is a best practice.

But, let's throw it away temporarily as the readability issue is more subjective than performance impact.

-
The second version produces a larger pdf file on my system. – Andrew Swann Mar 10 '13 at 12:33
I get 8.81kB for each picture with only standalone class and tikz package loaded. – percusse Mar 10 '13 at 12:41
@percusse A minimal file produced 8955 bytes for the first case, the second gave 8964 bytes. However, repeating each of the given code examples within in one tikzpicture environment only increased the difference by 1 extra byte total. – Andrew Swann Mar 10 '13 at 12:41
I think it's more important to consider the semantic meaning of the code than the apparently very small file size differences. You should only put the circle, line and rectangle into a single path command if they're very closely related. You can't have different colours within a single path command, for example (unless you use edge commands). I think that the verbose syntax of TikZ is actually one of it's strong points: It's very easy to read and understand. Trying to shorten the code at the cost of readability seems like you're optimising for the wrong objective. – Jake Mar 10 '13 at 12:45
@percusse The numbers are clouded by the pdf compression, setting \pdfcompressionlevel=0 produces notable differences. – Andrew Swann Mar 10 '13 at 13:19

Of course, as @Jake mention, the readability of the code is the most important thing. So this should always be enforced!

However, the question is quite an interesting one. I might have an analysis answer. I use the pdflatex compiler, version: 3.1415926-2.4-1.40.13

First we have to determine which minimal example to look into.

\documentclass{article}
\usepackage{tikz}
\pdfcompresslevel=0 % allows direct comparison
\begin{document}
\thispagestyle{empty} % this is crucial to obtain the smallest file

\end{document}


Furthermore, there are two codes being compared, we will compare the object streams created in the PDF by our pdflatex executable (i.e. TikZ shipout). I only show what is important for the drawing, object stream operations above and below the region of interest are the same.

1. Code

\begin{tikzpicture}
\draw (0,0) --(1,0) (2,0) -- (3,0);
\end{tikzpicture}


Produces the following page object:

0.0 0.0 m       % start point of new drawing (m for move)
28.3468 0.0 l   % line ending (l) for line
56.69362 0.0 m  % new move
85.04042 0.0 l  % draw line
S               % stop

2. Code

\begin{tikzpicture}
\draw (0,0) --(1,0);
\draw (2,0) -- (3,0);
\end{tikzpicture}


Produces the following page object:

0.0 0.0 m       % start point of new drawing (m for move)
28.3468 0.0 l   % line ending (l) for line
S               % stop
56.69362 0.0 m  % new move
85.04042 0.0 l  % draw line
S               % stop


So as seen above the two-segmented code actually does produce extra work for the PDF viewer.

Lets consider a slightly more interesting example:

1. Code

\begin{tikzpicture}
\draw[red] (0,0) --(1,0) (2,0) -- (3,0);
\end{tikzpicture}


Produces the following object:

1 0 0 rg 1 0 0 RG  % choose color in RGB
0.0 0.0 m          % move
28.3468 0.0 l      % draw
56.69362 0.0 m     % move
85.04042 0.0 l     % draw
S                  % stop
0 g 0 G            % apply color

2. Code

\begin{tikzpicture}
\draw[red] (0,0) --(1,0);
\draw[red] (2,0) -- (3,0);
\end{tikzpicture}


Produces the following object:

1 0 0 rg 1 0 0 RG  % choose color
0.0 0.0 m          % move
28.3468 0.0 l      % draw
S                  % stop
0 g 0 G            % apply color
Q                  % restore the previous saved graphics state
q                  % save the current graphics state (i.e. Q q is a no-op)
1 0 0 rg 1 0 0 RG  % choose color
56.69362 0.0 m     % move
85.04042 0.0 l     % draw
S                  % stop
0 g 0 G            % apply color


However, as you notice, the compression of the PDF will reduce this to roughly the same layout as it is easy. :)

Lets, suffice to say that whatever you do, the optimization routine in the final product is endlessly more important than these simplistic examples.

Conclusion

The object stream must be created in some way, before being optimized, so this would mean that less bytes to pass to the optimizer should (in theory) mean a faster compilation (provided the optimizer is linearly dependent on the number of bytes received!).

But it is easy to consider very complex drawings with a lot of no-op operations in the non-compressed file. And also, the easier the object stream is to interpret by the optimizer, the more optimized it will be, producing smaller files.
Dare I say: it could be argued that one should do everything on one path.

EDIT

I wanted to clarify whether there actually was a speed penalty associated with using several path-segments. So here is what I did.

1. The above examples with the red color have been used for testing.
2. In my test.tex document I create them 10.000 times
3. I time this over an average of 100 runs

And here is what I get:

-----One draw Two draws
Mean 20.3028  26.6568
Std.  1.2976   2.5581

So clearly, it does have an effect on the execution time, but here we have used 10.000 and 20.000 draw commands. respectively. So the document has to be on the order of this for it to be noticeable. The difference in std. makes me wonder whether this is clear comparison. However, I will probably not do the test again. :)

-
Very excellent analysis! – kiss my armpit Mar 10 '13 at 14:09
@GarbageCollector suffice to say that your example is a lot more challenging to analyse, however, the number of lines deviation is only ~6-10 lines out of 32 of object streams, (after having rearranged and stuff) – zeroth Mar 10 '13 at 14:24
That's probably because the nodes are inline and other mechanisms are interfering. Inline nodes are collected and placed differently than the \pgfnode mechanism. – percusse Mar 10 '13 at 15:00

I have removed the extra [draw] in the first case. Here are the logs on my Aspire 4752ZG, with Intel Core 8960 Processor (2.2GHz, 2MB L3 cache), 4 GB DDR3 memory with Ubuntu 12.10 installed. I don't know if the long logs are useful.

Xelatex

First Case

Fille size: 1,679 bytes

Time log

Second Case

File size: 1,688 bytes

PDFLaTeX

First Case

Output written on prob44d.pdf (1 page, 8656 bytes).
PDF statistics:
15 PDF objects out of 1000 (max. 8388607)
10 compressed objects within 1 object stream
0 named destinations out of 1000 (max. 500000)
13 words of extra memory for PDF output out of 10000 (max. 10000000)


Second Case

Output written on prob44c.pdf (1 page, 8664 bytes).
PDF statistics:
15 PDF objects out of 1000 (max. 8388607)
10 compressed objects within 1 object stream
0 named destinations out of 1000 (max. 500000)
13 words of extra memory for PDF output out of 10000 (max. 10000000)


LuaLaTeX

First Case

Output written on prob44e.pdf (1 page, 8674 bytes).
PDF statistics: 15 PDF objects out of 1000 (max. 8388607)
10 compressed objects within 1 object stream
0 named destinations out of 1000 (max. 131072)
16 words of extra memory for PDF output out of 10000 (max. 10000000)


Second Case

Output written on prob44f.pdf (1 page, 8674 bytes).
PDF statistics: 15 PDF objects out of 1000 (max. 8388607)
10 compressed objects within 1 object stream
0 named destinations out of 1000 (max. 131072)
16 words of extra memory for PDF output out of 10000 (max. 10000000)


I only timed the xelatex compilations since it was only with it and pdflatex that I saw a noticeable difference in file size (however negligible). I did 15 trials each and ran Welch t test in R on the outcomes. (I got lazy when I had to do the pdflatex part. Well, you can try it out.)

Here is the analysis.

The variance of the first setup is 0.005339 while that of the second is 2.47 e -05.

T Test

Welch Two Sample t - test
data : setupa and setupb
t = 0.5147 , df = 14.13 , p - value = 0.6147
alternative hypothesis : true difference in means is not equal to 0
95 percent confidence interval :
-0.03079 0.05026
sample estimates :
mean of x mean of y
0.6073
0.5975


Here you will see that the difference is not significant. And with the continuously increasing computer power, it is barely noticeable. (Unless of course you run time in the terminal.) I have to agree with Jake that the second set up is preferred when applying colors and stuff.

-
I am not sure the difference will be insignificant for other projects (as opposed to my trivial examples). – kiss my armpit Mar 10 '13 at 13:51
@GarbageCollector Perhaps. But it is hard to say without an actual use case code and without running several trials on it for statistical analysis. :) – hpesoj626 Mar 10 '13 at 14:01