9
$\begingroup$

There're two ways to generate a random tree as 1 and 2 below. Both work fine here. So what's the reason to use vtx[] instead of vtx?

Source: How to generate a random tree?

1.

vtx[] := Table[i <-> RandomInteger[{0, i - 1}], {i, 1, 50}];
Graph@vtx[]

2.

vtx := Table[i <-> RandomInteger[{0, i - 1}], {i, 1, 50}];
Graph@vtx
$\endgroup$
  • $\begingroup$ The second way is 10 times faster. All rest looks similar. $\endgroup$ – Rom38 Oct 26 at 5:22
  • $\begingroup$ It is good to note that the method you linked does not sample trees uniformly. Some trees are generated with higher probability than others. To sample trees uniformly, you can use IGTreeGame[] from the IGraph/M package. $\endgroup$ – Szabolcs Oct 26 at 10:25
  • $\begingroup$ In 2 you could remove the delay from the assignment, since the LHS is not parameterised. $\endgroup$ – Shredderroy Oct 26 at 14:05
  • 1
    $\begingroup$ @Shredderroy := can be removed either in 1 or in 2 (but notice that the right-hand-side generates a random list, so := is important in this application) $\endgroup$ – Szabolcs Oct 26 at 17:43
12
$\begingroup$

The reason to use 1. is readability. There is no difference in function or performance.

Simply because of established convention, most people when they see f[vtx], they assume that vtx is "a variable", i.e. if it is evaluated twice, it will give the same result both times. vtx[] looks like "a function call", so people will expect that a second evaluation may give a different result (as it is the case here).

Technically speaking, Mathematica has neither functions nor variables (it is a term rewriting system), but it is still useful to think of code in these terms.

$\endgroup$
12
$\begingroup$

Besides the reasons mentioned by @Szabolcs, there's a second advantage of the first method: It is easier to control when evaluation happens.

  • With vtx := …, evaluation happens as soon as the symbol appears (as long as you're not using stuff with Hold attributes/Unevaluated)
  • With vtx[] := …, you can pass around vtx without having to worry about evaluation. Only when you add the square brackets is the code actually evaluated.

Example

To see why this can be useful, consider the following example: We want to create a function drawTrees that creates small plots of 5 randomly sample trees, where we can specify how to sample them.

With vtx[] := …, this would look like this:

drawTrees[gen_]:= Table[
  Graph[gen[], ImageSize->100],
  5
 ]

vtx[] := Table[i <-> RandomInteger[{0, i - 1}], {i, 1, 20}];
vtx2[] := Flatten@Table[{i <-> i - 1, i <-> f[i]}, {i, 20}];

drawTrees[vtx]

enter image description here

drawTrees[vtx2]

enter image description here

With vtx := …, we need to use a HoldFirst attribute:

drawTrees[gen_]:= Table[
  Graph[gen, ImageSize->100],
  5
 ]
Attributes[drawTrees] = {HoldFirst};

vtx := Table[i <-> RandomInteger[{0, i - 1}], {i, 1, 20}];
vtx2 := Flatten@Table[{i <-> i - 1, i <-> f[i]}, {i, 20}];

drawTrees[vtx]
(* same as above *)
drawTrees[vtx2]
(* same as above *)

Of course, the fix is simple in this case. But if you need to pass around the generator a lot and store it somewhere, it will become even more messy with the vtx := … approach.

$\endgroup$
  • $\begingroup$ I just wonder if you define vtx[] := … then why do you pass vtx not vtx[]? $\endgroup$ – anhnha Oct 26 at 12:35
  • $\begingroup$ You don't need to pass around vtx instead of vtx[] - the point is that you can. I have updated the answer with an example $\endgroup$ – Lukas Lang Oct 26 at 12:52
  • $\begingroup$ I see it now. Thanks for the updating. $\endgroup$ – anhnha Oct 26 at 13:18

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.