Comparing changes
Open a pull request
This is sufficiently widely-used that we can't hope to keep it 'team only', and don't want loads of copies of the primitive.
This is a tidy up of the 'already done' work. Where we can avoid the primitive entirely, we do. Otherwise we keep it for all uses in a module.
As \int_value:w is now public, and there is a performance gain, this makes sense here.
We could use one per module, but that is a bit of a waste.
This *might* show up an issue as a couple of other people use the break functions. As they we internal, there's a limited amount we can do ...
... so they acutally work.
I've renamed the 'one' functions as 'add': hope this makes sense. Could perhaps be 'store'?
This requires a new public function, and is slightly slower.
The only places that really require the same functionality are the FPU and bigint comparison. Both of these can use private copies which are slightly more efficient. One might consider making the FPU version wrap-up the "= 0" part other than for the bigint stuff.
This requires loading l3intarray later. Since I am somewhat likely to implement an l3fparray it makes sense to load l3intarray and then l3fparray just after l3fp.
…d, tn
The idea is that one can refer to a foreign internal by \cs{__foreign_...}
but not document it using \begin{function}{\__foreign_...} or similar, nor
use it in code wrapped by macrocode.
We have enough 'open ended' int expression usage that we do need \int_eval:w I think. That allows us to reduce the number of \@@_int_eval:w cases to those which are *really* needed (FPU).
This one really is 'just for us'.
.. should have been @@ from the start!
There were a couple of tricky cases here, at least in part due to the lack of a set of interfaces for \kern.
Cuts down a few warnings.
That's slightly tricky because l3regex relied on the group that old tl_build functions created.
Also actually test an error message
Makes finding 'real' uses of __ a bit easier.
Really goes with the \prg_map_.... changes.
Either a kernel-level message or 'do not do this'.
Change subsections to sections
And to allow \dim_to_decimal_in_sp:n to be used in l3fp, make it faster.
Raising a flag takes a time proportional to its height, while this function takes a constant time. When the actual height is not useful it's much faster to only raise the flag once.
This is all about stuff only in l3prop.
We are moving to having everything either public-and-documented or purely in the code section. These functions are not used outside of their 'home' module so do not need wider docs (or moving to \__kernel).
A couple have to be made __kernel (I think).
This shows up when you have everything together.
A better place than \__unicode
The code is simple enough and there isn't any reasonable interface
This allows us to move \int_rand:nn to l3fp if we want.
I put the end of this year because we deprecated them at the very end of last year.
This avoids one internal being 'out of order'.
A couple of cases outstanding in l3kernel
As these are 'legit' at this level.
This reverts commit d6fc40b.
This deals with an __ issue, and makes \int_rand:nn stable (seems reasonable).
This means we have only one set of data storage, avoiding __ issues.
This avoids some issues in test files. Also means that we are in a known state.
The new approach is more general. Not sure we should keep \seq_set_map:NNn but it has been in l3candidates for a while so it would have to be deprecated properly.
Some \tableofcontents were before even the title of the doc. I've left some others that were placed in reasonable places, but for most files we don't even have a toc.
This should never matter since expl3 is only ever loaded in vertical mode, but I do that for consistency with other lines in that file.
…ions This is somewhat experimental. It may make sense to provide a package that suppresses \traceon output likewise for all non-expandable commands: even for simple ones like \seq_put_left:Nn this reduces terminal output.
It is often simpler to use finer expansion control, specifically the surprisingly useful \exp_last_unbraced:NNNNo.
Rather than deal with issues on the naming, by using some x-type expansion at point-of-use we can drop the second argument here.
The name here may need adjustment: the "show" function is \tl_show_analysis:n. Presumably one of them is the wrong way around .... On the *returned* data, I've made the swap suggested by Bruno and have charcode/catcode as for \char_generate:nn.
At least for consistency.
This reverts commit 35bf15f.
First step in reducing use of :D functions more generally.
Same logic as for \etex_unexpanded:D - we need this a few times.
In particular, the string comparison auxiliary should use \lua_now_x:n etc.
Eventually we'll use this in the sys module, but at the moment it's too soon.
... as we only keep the engine name for the 'version' primitives.
As Chris argues, the namign should reflect the function, even if here we are resticted in engine coverage.
For \tl_trim_spaces_apply:nN
This adds a new "!" modifier to the syntax which applies to optional
arguments. At present, it only does anything if the optional argument is
also trailing: others are left alone. The logic of that is something
like
\DeclareDocumentCommand{\foo}{mom}{...}
\foo{bar} [baz] {bop}
has to find a second mandatory, and grabbing "[" here as #3 would be
pretty strange.
What happens with multiple trailing optionals is not entirely clear.
I've gone for "!" applying on a per-argument basis, but that is only one
way of setting it up.
I got this by looking at all "updated" dates for functions in l3kernel. This may miss syntax changes that only affected functions that were subsequently updated. The distinction between bug fixes and syntax changes is not always easy to make.
Putting a one-level redirect here makes using these with a known number of expansions tricky. Moreover, it doesn't actually help when we are not using LuaTeX: a test is still required 'up front'.
When adding items to a comma list, spaces were removed but not braces,
even for items that did not need them. Now the treatment is consistent
by having a common (internal) function to test whether an item should
be braced or not. For instance,
\clist_set:Nn \l_tmpa_clist { {a} }
\clist_if_in:NnTF \l_tmpa_clist { a } {true} {false}
gave false but now gives true.
Almost all uses of int_step loops had a step of 1; adding these variants was probably right.
These are the only two n-type synonyms of primitives, so the only two n-type arguments that must be braced (the n-type argument of \cs_new:Npn and similar functions must also be braced but only to end the p-type argument before it).
Still some discussion to be had here on the best approach.
There's no actual content in interface3.
For example for xmltex.
The trailing combining chars aren't set up for inputenc, which means with TL'18 LaTeX2e they are pointing to an error message. That causes havoc in the case changer: the older version has them just as chars. Almost certainly these codepoints can't be used in an 8-bit document as the fact they apply *after* the char is not supported by the engine. So rather than try to pick up the error, simply adjust the test to stick to legitimate input.
There is no need to use the primitive directly here as we can do the job using \char_generate:nn. We may want to think about a 'generic Unicode engine' switch, something like \sys_if_engine_unicode_p: or \sys_if_enigine_utex_p: (as we already use utex for some primitives).
Many of the functions already needed expr evaluation for underlying implmentation reasons. The hit is therefore mainly in color functions.
This cuts out a lot of overful lines. We might consider making this less repetitive ... but that might be more work than it's worth.
This deals with more-or-less all of the ones dues to overlong code lines. There are various places that perhaps might be handled by re-writing some docs. More tricky are the non-trivial number that come at the end-of-definition lines: they are outside of something that can be changed in the source. There are also a reasonable number that are (I think) in the syntax environments.
l3doc can't pick this up.
This allows proper linking of the versions without TF.
The RNG's low bits are not great, so use in priority its high bits.
Diffs due to: - LuaTeX logging changes - (u)pTeX boxing changes - l3build normalisation adjustments
In some experiments that's about a 20% speed-up because we avoid re-reading tokens that were expanded
These are the only two variable types with a "<var>_use:N" function that does not just apply \the or expand a macro once.
It seems reasonable to use \__int_eval:w in these l3int functions. They are the bottleneck in some upcoming \seq_shuffle:N code.
I am only committing this implementation for the record, and not updating test files, because I will commit a much faster implementation using \toks soon.
I couldn't find a good way to distinguish them so I took a bad way: systematically compare every register that comes into fp expressions with \infty and with \pi.
Some test file changes will likely be altered again: l3build approach needs adjustment here.
Showing you all comments on commits in this comparison.
This comment has been minimized.
This comment has been minimized.
|
@blefloch typo "explict" |
This comment has been minimized.
This comment has been minimized.
|
Fixed, thanks. |
This comment has been minimized.
This comment has been minimized.
|
@blefloch is using toks registers with odd indices non globally okay practice in expl3 ? |
This comment has been minimized.
This comment has been minimized.
|
@blefloch Have you considered this: |
This comment has been minimized.
This comment has been minimized.
|
I mean the point is that |
This comment has been minimized.
This comment has been minimized.
|
I have done the following experiment.
This gives I am not good at statistical analysis but perhaps someone can conclude things out of this. For example the "36" at row 4 and column 1 is small, it is at 3 standard deviation below "50", which has about ``0.135%` likelihood, which looks small even if we multiply by 24, but perhaps not so. Anyway, by simply making 2 such |
This comment has been minimized.
This comment has been minimized.
|
Thanks for doing that comparison. It might make sense to generalize it
to each individual bit (basically here you are testing bit 2^14 in the
underlying stream of 28 bit numbers), and decide which bits have
acceptably low correlations between seeds. Perhaps we should look more
carefully at the algorithm: for instance if seeds differ by a large
power of 2, are the low bits of the resulting random streams identical?
(I.e., a generalization of my observation about the lowest bit.)
Note however that the main reason we don't just use the primitive is
different. If one does \uniformdeviate 3 then the result is not quite
uniformly distributed: the underlying 28 bit integer is simply
multiplied by 3/2^{28} then rounded (then 3 is mapped to 0). Obviously,
2^{28} cannot split evenly into the outcomes 0, 1, and 2. Of course,
for such a small argument 3, the bias is tiny, but when the argument
starts being of the order of 2^{28}, some outputs become impossible.
For instance, \uniformdeviate 1073741824 gives only multiples of four.
|
This comment has been minimized.
This comment has been minimized.
|
Yes, the pdftex manual should be more precise about the limitations of the PRNG. Arguably for reasonable usage in LaTeX, 16384 item is already large, what do you think? then the non-uniformity is not so dramatic. Your question about statistics deserves attention indeed. I wanted earlier today to look at the sources but did not so far. All my information comes from the one added to expl3. Although this does (edit: not) answer your question about the low bits I am reporting here that I did some tests using ent software (available from MacPorts on the Mac). I generated bytes (8bits) seven by seven ( The serial correlation test comes however always (I mean, in the three cases I tested...) lower for the low bits and is the only indicator seeing low bits more random than high bits. Of course these things tell us nothing about the fact that using another seed might lead to a surprisingly correlated outcome, as your parity finding demonstrates. |
This comment has been minimized.
This comment has been minimized.
|
@blefloch already |
This comment has been minimized.
This comment has been minimized.
|
at the tex.sx question I added mention that with |
This comment has been minimized.
This comment has been minimized.
|
@blefloch Bad news indeed. I looked in pdftex.web the algorithm. It is purely linear modulo You observation on parity bits is completely general. |
This comment has been minimized.
This comment has been minimized.
|
Here is a quote from Knuth TACP, vol II, chap. on random numbers, summary vii): (he seems to comment a Thus of course he is well aware of low bits badness (i haven't check the exercise). I have not checked pdftex, but I expect it to follow the advice so to do edit the metapost code does the rescaling with rounding remapping upper limit of range to zero. |
This comment has been minimized.
This comment has been minimized.
|
(not to spam but just to say that having a more limited number of possible sequences of say 4 low bits doesn't mean that the actual sequences do not behave randomly; imagine a RNG which has no seed. It can still be excellently random ) |
This comment has been minimized.
This comment has been minimized.
|
Thanks a lot for the detailed work! We should probably forgo completely
the use of low-order bits. My current plan is (1) for ranges ≤ 2^14
just use the primitive and document the non-uniformity; (2) for larger
ranges produce a random float between 0 and 1 and multiply it by the
size of the range before truncating; (3) to produce a random float
produce digits either several at a time by \uniformdeviate 1048576 and
discarding results ≥ 1000000, or by calling \uniformdeviate 10 for each
digit. I'm happy to change some parts of that plan.
On a related note, we could change the definition of
\sys_gset_rand_seed:n to be something like
\cs_new_protected:Npn \sys_gset_rand_seed:n #1
{
\pdftex_setrandomseed:D \int_eval:n {#1} \exp_stop_f:
\prg_replicate:nn { \pdftex_uniformdeviate:D 65536 }
{ \exp_after:wN \use_none:n \pdftex_uniformdeviate:D \c_zero }
}
and perhaps provide something like
\cs_new_eq:NN \pdftex_elapsedtime:D \pdfelapsedtime
\cs_new_protected:Npn \sys_get_entropy:
{
\exp_args:Nf \__sys_get_entropy:n
{ \int_eval:n { 1 + \tex_the:D \pdftex_elapsedtime:D } }
}
\cs_new_protected:Npn \__sys_get_entropy:n #1
{
\if_int_compare:w
\pdftex_uniformdeviate:D \c_zero #1
< \pdftex_elapsedtime:D
\use_i:nnn
\fi:
\__sys_get_entropy:n #1
}
because typically one step in the loop will take much less than 2^{-16}
seconds. Both of these mitigation techniques are far from perfect since
they just shift the random sequences somewhat.
|
This comment has been minimized.
This comment has been minimized.
|
I would recommend being terse in the documentation! I don't know what is the current state of research regarding "lagged Fibonacci sequences" as used in the MetaPost RNG. I opened for the first time yesterday volume II of Knuth TAOCP which contains information about it, and all of it may be dated nowadays. Discussion starts at 3.2.2-(7) page 27. See also exercise 3.2.2.-30 which seems to indicate in our case the period of each sequence (whatever the seed) is On mention of some issues of these "lagged Fibonacci" in TAOCP, see among others
In particular exercise 3.3.2-31 comments on parity bits for what I think is about the same recurrence as in pdftex.web (modulo the "backwards run through the array" I mentioned earlier which confuses me) seems to say that when we start at a random point in the sequence (your Nevertheless the parity bits are not that bad, they guided the construction to generate sequences with guaranteed very big periods ( About documenting non-uniformity, perhaps something like "The underlying pseudo random number generator works with 28bits integers ; even if it achieved perfect uniform distribution, the rescaling (done by the engine) to produce an integer in a range with N values by necessity introduces non-uniformity, of relative order of magnitude about I find your plans about going via floats quite reasonable. I briefly examined an alternative but it looks more costly: the problem with the rescaling from fraction |
This comment has been minimized.
This comment has been minimized.
|
ah ok I think I got a not too bad way for handling
Let's evaluate non uniformity of an integer when the returned value is The non-uniformity of an integer obtained via the The whole thing should be tightened up but maybe a viable way. |
This comment has been minimized.
This comment has been minimized.
|
in implementation of course we first decide whether it will return Thus the doc could say: "for N less than in all of the above I restricted myself mentally to |
This comment has been minimized.
This comment has been minimized.
|
@blefloch Here is another idea, but it recycles the same trick that we need to approximate closely a frequency. I think you mentioned something about log(N) somewhere so perhaps you have already considered this, apologies if this is repetition. Goal: draw a uniform integer Initialize:
In about log_2(N) steps the algorithm concludes (if Sorry last paragraph was non-sense. The point of the manoeuver is that we do |
This comment has been minimized.
This comment has been minimized.
|
I corrected last paragraph of previous comment. Possibly |
This comment has been minimized.
This comment has been minimized.
|
A variant, possibly faster: still the naive idea that to get a random integer in a range of size N which is split into one part of size K and one of size L we need good approximations of K/N (or L/N), which means we must somehow use not too small values of either K or L. Because we will do e.g. So the variant here is N = K + L, K a power of two, and L not too small in proportion to N. If we take |
This comment has been minimized.
This comment has been minimized.
|
@blefloch Hi again. Sorry for my never-ending comments, but I have given some extra thought on the "non-uniformity". Imagine we use For So I have started running some global statistics with the help of a Python snippet doing the same as pdftex.web code (see links below). And for example I get this: where I do a χ2 test of 300,000,000 draws of If we use Fwiw, I Pythonified pdftex.web code here (see also this tex file, which uses The general conclusion is that for |
This comment has been minimized.
This comment has been minimized.
|
(can't stop) Still focusing on |
This comment has been minimized.
This comment has been minimized.
|
Stream of consciousness (heavily edited of course). I'm still thinking
about this, sorry for my silence. My main worry is that trying to
improve randomness is known to often backfire. Many conflicting
requirements. The algorithm should be:
- Simple. The behaviour must be documentable precisely (as we see now
it is useful to know exactly what the code does).
- Predictable. The number of calls to \uniformdeviate should be the
same for any \int_rand:nn, because then the algorithm can be modified
later without changing the result of other uses of \uniformdeviate.
- Quick. The algorithm should be fast in TeX, so no "bit twiddling",
but "digit twiddling" is ok.
- Robust. It should work even for \int_rand:nn { - \c_max_int } {
\c_max_int } where the range is not representable as an integer.
- Uniform. The result should be exactly uniform assuming that
\uniformdeviate is.
- Uncorrelated. The result should not have detectable ("low-bit")
correlations between different seeds.
Ignoring "Quick." completely the optimal algorithm with m calls (2 is
enough) to \uniformdeviate is as follows. Call \uniformdeviate 2^28
repeatedly and write each result as a binary floating point
0.x_1x_2...x_{28} between 0 and 1-2^-28. Interleave the bits as
0.x_1y_1z_1x_2...z_{28} (where I've assumed for definiteness that I had
m=3 binary floats x, y, z). Multiply that 28*m bit float by
(max-min+1), truncate to an integer, and add min.
A more realistic version (speed-wise) may be to work with digits: call
\uniformdeviate 10^8 twice, interleave digits to get a decimal floating
point between 0 and 1-10^-16, multiply by (max-min+1), truncate, add
min. Hardcoding the multiplication with the interleaving-digits step
should make it tolerably fast.
The digits probably don't need to be interleaved one by one; perhaps
this rehabilitates the idea of using binary: call \uniformdeviate 2^28
twice to get x and y, then interleave as 0.x_Ay_Ay_Bx_B where x_A etc
are 14-bits each. Note that I put y_B before x_B (I don't think it
affects randomness). In fact, remove x_B because its effect is of order
(2^-10) since the range is at most 2^32-1 and x_Ay_Ay_B has 42 bits.
Let R be max-min+1. (I'll ignore huge ranges where R≥2^31 as using a
slow algorithm is ok in such cases.) If I'm not mistaken we can do
(with eTeX rounding)
S = \uniformdeviate R
X = \uniformdeviate 16384
R1 = (R-8192)/16384
R2 = R-16384*R1
result = min + R1*X+(R2*X+S)/16384
if result > max: result = min
As in the WEB code I'm replace truncation by rounded division and
mapping the top and bottom values to the same. For ranges ≤2^17-1 we
don't need to separate R1 from R2, just put R2=R.
|
This comment has been minimized.
This comment has been minimized.
|
I agree with 99% but look at
If I understand correctly you are laying out mentally 16384 copies of range R. One such interval is picked at random (this step is uniform) and in the interval one uses range R (non-uniform). Then one divides by 16384 with rounding. The relative probabilities before division by 16384 obey the sequence The value 1 will be obtained from 8192 to 8192+16383. As 8192 is 2 modulo 3 the pattern is |
This comment has been minimized.
This comment has been minimized.
|
A. the requirement about fixed number of calls to \uniformdeviate appears very strong constraint, this means if you manage to make in 4 calls, you can not improve in future if it requires 5 calls. B. I would drop the requirement for exact uniformity, because it is already an article of faith it is achieved modulo 2**28, or at least we don't know to what extend it is achieved. Placing myself in this perspective!
For me the more serious problem is the one with \uniformdeviate N when N is not a power of 2 but is divided by some large power of 2. The procedure as above using P is designed to get rid of it, but it costs a Underlying all of this is that I am happy with the non-uniformity inherent in the "re-scaling" method to go from P to N as I am with the one from 2**28 to N. Then you also want random floats but that's another matter. Going via uniform float to get uniform integer is like replacing 2 by 10 and will still have the problems with numbers such as 3*10**b, b>0. |
This comment has been minimized.
This comment has been minimized.
|
(I realized that if someone is allowed to know a bit more than 55
consecutive values of \uniformdeviate 2^28 then they know all future and
past results and can get back to the seed. So perhaps we are spending
too much effort in hiding these kinds of issues.)
Thanks for the example! Your statements are correct. Note that there
is no way to achieve uniformity using a fixed number of \uniformdeviate
calls: basically we approximate 1/N by fractions whose denominator is a
power of 2. In my approach that denominator is 2^42 because I only use
half of the bits of X (and \uniformdeviate R uses 28 bits under the hood).
In your example you could have picked 3*2^30 (the case of a "huge"
range) to get a 16 times worse non-uniformity of 2^12/3 ≃ 1/1365. This
suggests that for big ranges we should work a bit harder and keep the 14
other bits of X.
Here is a revised plan, written in python (but only doing operations
easily done with eTeX), where "random" means \uniformdeviate and "div"
means eTeX's rounded division. The idea for R>2**17 is to compute
R2R1R0 × 0.X1Y1Y0X0, where by juxtaposing variables I mean building a
number in base 2**14.
if R <= 2**17:
return min + ((R*random(2**14)+random(R)) // 2**14)
X = random(2**28)
Y = random(2**28)
R2 = R // 2**28
R1 = (R % 2**28) // 2**14
R0 = R % 2**14
R2R1 = R2*2**14 + R1
R1R0 = R1*2**14 + R0
X1 = X // 2**14
Y1 = Y // 2**14
Y0 = Y % 2**14
X0 = X % 2**14
X1Y1 = X1*2**14 + Y1
result = (min + R2*X1Y1 + R1*X1 +
div(R2*Y0 + R0*X1 +
div(R2R1*X0,2**28) + div(R1R0*Y,2**28), 2**14))
return min if result > max else result
As it is, this has two overflow problems when R≥2^31 (namely R2≥8). The
first one is that R2*X1Y1 can overflow. To avoid, just write (min +
8*X1Y1 + (R2-8)*X1Y1 + ...). The second one is that if max=2^31-1 then
the result may reach 2^31. To avoid, we could use truncated division
but this would prevent us from using eTeX fused multiply-divide, so we
would have to spell out many more terms. Alternatively, add compute
separately (min + R2*X1Y1 + R1*X1) and the rest and check at the end
that their sum does not overflow; if it does return min.
This gives a relative non-uniformity of order R/2^42≤2^-25 when R≤2^17
and I don't know at all how to estimate it for R>2^17. Ideas welcome.
|
This comment has been minimized.
This comment has been minimized.
|
so fat I had carefully neglected the "big" ones... wait, if R2 is at most 7 if R2 is from 8 to 15, S2 = R2 - 8 but final result can probably overflow ("over-big" ranges were not my perspective, so my brain is not ready) even if combined with expl3 should do only randrange(a,b) which does not admit upper limit b ! |
This comment has been minimized.
This comment has been minimized.
|
Sorry, I saw your post after posting mine (and then this draft stayed a
while in my computer).
A. Having a fixed number of \uniformdeviate is mostly "nice to have",
not a requirement. In principle it's pretty restrictive, but my last
suggestion seems to be ok with doing only two \uniformdeviate. I am not
going to keep track of (perhaps by now no longer active) literature on
this type of RNG so it's not so likely that we will change the
algorithm. If the worst came to be we could always provide a
compatibility mode.
B. I'm ok with dropping exact uniformity, but I'd prefer to bound it
around 2^-24 or so. Maybe I'm being too greedy: there is actually no
good reason to prefer such a bound to a weaker bound (I didn't quite
follow your arguments about chi^2 yet but it seems plausible that it's
very hard to detect even 2^-10 non-uniformity).
Your approach with a prime is nice but does not reduce the amount of
non-uniformity, still of order N/P. It's just slightly harder to
detect. Concretely, take P=268435399 and N=88783 and produce random
numbers between 0 and N-1 using your technique. Focusing on results
between 1 and 14796, odd numbers appear 3024 times and even results 3023
times. Odd and even are switched for the next interval from 14797 to
44k or so, then switched again etc. This switching of odd and even
depending on the interval is why we don't see an overall imbalance
between these two parities, but restricted to each interval the
imbalance is as bad as if we were using random(2^28) instead of
restricting it to [0,P-1].
believed the higher non-uniformity for higher N's was not a real
problem because doing even 0.01 (2**56)/N draws is a lot!
I haven't yet followed how you derived (2**56)/N (or a small multiple
thereof), but note that \uniformdeviate 2^30 for instance very clearly
produces only multiples of 4, and I don't need to go anywhere near
2^56/2^30 calls to see the bias. I think you were calculating the
likelihood of getting a particular number a particular number of times,
rather than looking more globally at all numbers obtained.
Then you also want random floats but that's another matter. Going via
uniform float to get uniform integer is like replacing 2 by 10 and will
still have the problems with numbers such as 3*10**b, b>0.
Yes, random floats are not helpful for uniformity. Let's postpone for a
bit the question of how to get good random floats.
|
This comment has been minimized.
This comment has been minimized.
|
As I now need to think before and not while posting I will ponder later your P=268435399 and N=88783. Just for the record, I wish to summarize to myself here that the bigger constraint is to get a scheme which is efficient in e-TeX. As your proposal with R0R1R2 etc... already shows, we could in principle simply do this: if we trust that the PDFTeX RNG for 28bits integers is uniform enough and uncorrelated enough for successive trials, then we just do round(N times 0.XY) where X, Y are base-
First item can be addressed with some waste by only using item 2 has the issue that if our recipe does not give in all cases the exact theoretical result then the non-uniformity analysis is more complicated. Thus we need to achieve exactly (I thinks this is all paraphrasing things tacit in your R0R1R2 etc ... just to convince myself the issue is one of TeXing so it gives me an excuse to wait for you to solve it |
This comment has been minimized.
This comment has been minimized.
by reducing to smaller range I mean any scheme going from N1 to N2 where N2 divides N1 and which would theoretically map uniform distribution at level N1 to uniform distribution at level N2. |
This comment has been minimized.
This comment has been minimized.
|
sorry in previous post my restriction on N2 divides N1 is not needed. I consider any scheme of the following type: I have a set with N1 elements, I partition it into N2 sub-parts of same cardinality Q and a remainder. Then I produce a random in range N2 from one in range N1 by repeating trials until I fall into one of the indexed sub-part and return the index. Then the relative non-uniformity for the range N2 variable is at worst the one prevailing at range N1. We don't even need Q to be the Euclidean quotient of N1 by N2. For example we can take Q = 1, meaning we have chosen some N2 outcomes among N1 and just wait until we hit one of them. however, if we know authorize ourselves to produce N2 from some such recipe involving a pair of 2 randoms in range N1, we worsen the non-uniformity by a factor 2. (i.e. we consider here N2 subsets of range(N1) x range(N1) of equal cardinality). regarding your observations about P and N, I guess it tells us a concrete scheme to go from N1 = N to N2 = 2 and it makes it explicit how to effectively transfer non-uniformity at level N1 to non-uniformity at level 2. If with K outcomes we have relative non-uniformity e, we expect about The P-scheme does not change the fact that somewhere we have (by square root of that factor) |
This comment has been minimized.
This comment has been minimized.
|
I agree with your analysis about what non-uniformity is or is not
detectable. A quick test along the lines of \benchmark:n { \int_value:w
\prg_replicate:nn { 100000 } { \tex_uniformdeviate:D \c_zero } }
indicates that \tex_uniformdeviate:D takes a bit more than 2^{-23}
seconds (in a tight loop) on my computer. Code that does anything at
all with the random numbers will be much slower of course. Even
compiling for a day with the express purpose of testing the RNG will run
the RNG less than 2^17 / 2^{-23} = 2^40 times, so e = 2^{-20} is
completely undetectable.
One parameter that I have been ignoring somewhat is that \uniformdeviate
itself is certainly not exactly uniform. Do you know how non-uniform it
is? You seemed to be saying that the last bit is much more non-uniform
than that, for instance, with detectably more 1 than 0.
|
This comment has been minimized.
This comment has been minimized.
|
@blefloch about
As I don't know I will give instead some background information as memo that I got from looking in volume 2 of Knuth TAOCP: The underlying recurrence is
then there is more then But this does not apply directly to our true sequence y(n) which is related to x(n) by this formula: Here At the level of the we can express all in terms of past Python: If I am correct the above recurrences are obeyed exactly by successive returned values of The switch from the x's to the y's seems to perturb the 79 observation. I have not reproduced it in my brief testing (and I forgot to test the x's so far). At the level of the x's, as far as I understand the (x(n), x(n+1), ..., x(n+54)) mod 2 are never all zeros and all Here is quote (page 570): (i change notations to mine above)
(sometimes I find Knuth wording a bit hard to understand; when he says random walks of length 101, he seems to say get a run of 101 starting at x(n) , count 1s and 0s and if more 1s move to right else move to the left, then go to x(n+1) and repeat. At least that's my understanding.) |
This comment has been minimized.
This comment has been minimized.
|
@blefloch Ok, I found a bias in the parity bits. I initially was thinking of using batches of 55*79 runs, but it turns out that it is flagrant with batches of 165 random integers. Procedure: do The Python code is here. It does work exactly the same with the real thing in TeX! ADDITIONS More experiment on parity bits with arbitrary initial shift of 1 to 55 calls to For batches of 55 at a time, no abnormality is observed. a big preponderance of odd integers in 30000 successive batches of 55 randints, for the initial shift 23. Also the high bitI tried seeds 0, 1, 8035872, 10427991, 149847074 and 256844633 and batches of 165 |
This comment has been minimized.
This comment has been minimized.
|
It looks hard (I am probably lazy) to bound with complete certainty non-uniformity of R2R1R0x0,X1Y1Y0X0 if the implementation does not obtain the mathematically exact rounding. No problem with base Con: no way to do this in fixed number of |
This comment has been minimized.
This comment has been minimized.
|
Quick question: are you ok if I acknowledge you in l3fp-random.dtx by
including the following sentence early in the code documentation? « See
[url] for a very useful study by J...-F....... B..... of many aspects of
the engine's RNG, which clarified what constraints we are operating
under. » (You seem to be known to GitHub with a full first name but a
single-letter surname; I would use your full name if that's ok.)
Regarding runs of 55 or 165 numbers, it is still unclear to me whether
that affects uniformity or only correlations between neighboring random
numbers. For instance I find no surplus of odd numbers in 10^8 random
numbers (test done a couple times). That sounds a bit like
gerrymandering
|
This comment has been minimized.
This comment has been minimized.
|
This comment has been minimized.
This comment has been minimized.
|
See https://en.m.wikipedia.org/wiki/Mersenne_Twister, but it is well out of the class of PRNGs that Bruno wishes to use. It is lauded thus: It was the first PRNG to provide fast generation of high-quality pseudorandom integers; and The Mersenne Twister is the default PRNG in [very many] software systems, see article for the list. |
This comment has been minimized.
This comment has been minimized.
|
I agree with Chris that we won't implement the Mersenne Twister,
although if someone implements it in Lua we could make customizable the
random number generator used.
It's not surprising that the Mersenne Twister is slower than a trivial
recurrence relation; on the other hand it has very significantly better
properties.
Thanks Jean-François for pointing out a major bug (my code could produce
random numbers beyond the range that the user asked for) and a small doc
improvement.
|
This comment has been minimized.
This comment has been minimized.
|
Bruno's major bugs are my everyday tiny oversights Thanks Chris for link to wiki-page. Interestingly when testing my batches for predominance of 1s for randrange(2), short batches say with 11 items gave a bit strange result with the Mersenne twister they looked less random than they should have been, but, my experiments are limited to a few tries... and I am no statistician. |
This comment has been minimized.
This comment has been minimized.
|
The documentation does say that it needs careful, complex seeding or a long run in period to get uniform. |
There are no files selected for viewing