In a series of posts now imported to the Maplesoft blog (starting here), I have been talking about pseudo-random number sequences, but since part of what kicked off this series was a paper on true random number generation (with LASERS!) I thought I would share some routines I wrote that alllow you to use the two main true random number sources available on the web (neither using lasers, sadly).

The most popular true random number source on the web is random.org.  It uses atmospheric noise to generate its random sequences.  Specifically, it uses radio receivers, tuned between stations, in several different countries to pick up atmospheric noise, which is then used to generate the random bits.  To ensure quality of their numbers, they run, in real-time, many of the tests I have described in this series of posts.  It is a pretty fast service with a pretty good API, so it was easy to write the following interface to get random bits into Maple using the ?Sockets package.  The arguments to the procedure RandomDotOrg basically mirror that API and should be self explanatory.

RandomDotOrg := proc( rangemax::integer:=1000000000, 
                      rangemin::integer:=0, 
                      {number::posint:=1, base::posint:=10}, $) 
local sock, query, quota, output, line, tmp;

    try
        # Open socket 
        sock:=Sockets:-Open("random.org",80);

        # check quota
        query := "GET /quota/?format=plain \n\n";
        Sockets:-Write(sock, query);
        line := Sockets:-Read(sock);
        Sockets:-Close(sock);

        quota := parse(StringTools:-Chomp(line));
        if quota < 0 then
            error `out of random.org quota`;
        end if;

        sock:=Sockets:-Open("random.org",80);
        query := cat("GET /integers/?num=",number,"&min=",rangemin,"&max=",rangemax-1,"&col=1&base=",base,
                          "&format=plain&rnd=new \n\n"); Sockets:-Write(sock, query); tmp := Sockets:-Read(sock); if tmp[1..12] = "HTTP/1.1 400" then error `connection error: HTTP/1.1 400 Bad Request`; elif tmp[1..12] = "HTTP/1.1 403" then error `connection error: HTTP/1.1 403 Service Unavailable`; end if; line := "": while tmp <> false do line := cat(line,tmp); tmp := Sockets:-Read(sock, 100): end do; output := StringTools:-Split(StringTools:-Chomp(line)); output := map(parse, output); catch: error finally Sockets:-Close(sock); end try; return op(output); end proc:

Of course, to prevent overuse, they limit each IP address to 200,000 bits per day.  So, if you are doing a big Monte-Carlo simulation, you would probably be better off just using the service to generate a random seed and use a good PRNG for the rest of the sequence.

Here is a how you could use this procedure to efficiently generate a 10,000 bit random sequence

(**) L1 := map((op@Bits:-Split), [RandomDotOrg(2^25-1, number=417)], bits=24);

The other online service for true random numbers is HotBits from Fourmi Lab.  It uses the randomness of the radioactive decay of atoms of Cæsium-137 (here is a detailed description of how it is done). Its service is a lot slower that random.org, so it is best to use it generate small sequences or seeds.

The Hotbits API is a little more complicated, so I have to deploy ?XMLTools to parse the output I get from the ?Sockets package

HotBits := proc(bytes::posint:=8, {format::string:="decimal"}, $ )
local sock, query, line, tmp, xmldata, rinfo, breq, bret, reqquota, bytequota, rdata, output;

    if bytes >= 1000 then
        error "invalid input: maximum request size is 999 bytes";
    end if;

    try
        # Open socket 
        sock:=Sockets:-Open("www.fourmilab.ch",80);

        query := cat("GET /cgi-bin/Hotbits?nbytes=",bytes,"&fmt=xml \n\n");
        Sockets:-Write(sock, query);

        tmp := Sockets:-Read(sock,100);

        if tmp[1..12] = "HTTP/1.1 400" then
            error `connection error: HTTP/1.1 400 Bad Request`;
        elif tmp[1..12] = "HTTP/1.1 403" then
            error `connection error: HTTP/1.1 403 Service Unavailable`;
        end if;

        line := "":
        while tmp <> false do
            line := cat(line,tmp);
            tmp := Sockets:-Read(sock, 100):
        end do;

    catch:
        error
    finally
        Sockets:-Close(sock);
    end try;
    
    if line="" then
        error `did not receive any data from server`;
    end if;
    
    # line is XML
    xmldata := XMLTools:-ParseString(line);
    
    
    # check that bytes requested = bytes returned
    rinfo := XMLTools:-GetChildByName(xmldata, "request-information")[1];
    breq := parse(XMLTools:-TextText(XMLTools:-SelectContent(XMLTools:-IsText, 
                             XMLTools:-GetChildByName(rinfo, "bytes-requested")[1])[1])); bret := parse(XMLTools:-TextText(XMLTools:-SelectContent(XMLTools:-IsText,
                             XMLTools:-GetChildByName(rinfo, "bytes-returned")[1])[1])); if breq > bret then WARNING("Returning Fewer bytes than requested");
    end if; # process random bits rdata := XMLTools:-GetChildByName(xmldata, "random-data")[1]; rdata := XMLTools:-TextText(XMLTools:-SelectContent(XMLTools:-IsText, rdata)[1]); rdata := remove(type, StringTools:-Split(StringTools:-Trim(rdata)), ""); if format[1..3]="hex" then output := map(convert, rdata, 'name'); elif format[1..3]="bit" or format[1..3]="bin" then output := map(convert, rdata, 'decimal', 16); output := map(op@Bits:-Split, output, bits=8); elif format="raw" then output := rdata; else WARNING("invalid format specifier; valid formats are decimal, hex, binary, and raw"); output := map(convert, rdata, 'decimal', 16); end if; return output; end proc:

The arguments to HotBits are different, again, to mirror the API. Here is how you might generate a sequence of 10,000 bits by making two requests for 625 bytes worth of bits:

(**) L2 := [seq(op(HotBits(625, format="bits")), i=1..2)];

For your convience, here are the two procedures in a worksheet that uses each to generate images from random bit sequences: WebRandom.mw.

If you want to play with these generates together with some randomness tests, keep in mind that both services impose quotas and it is easy to run out.

Please Wait...