Joe Riel

9660 Reputation

23 Badges

20 years, 10 days

MaplePrimes Activity


These are replies submitted by Joe Riel

Yes, they are quite handy, though in that example they don't measurably improve the efficiency. They can be used for Vectors and Matrices, but not general rtables, since those allow indices that do not start at one.
Thank you for elaborating. By "programmatic access" do you mean via, say, ArrayTools:-Alias? With the SampleRtable procedure one can do
X := RandomVariable(Normal(2,3)):
p := SampleRtable(X):
R := Matrix(3,4, 'datatype=float[8]', 'order=Fortran_order'):
AR := ArrayTools:-Alias(R,9,[3]):
p(AR);
R;
                       [0.    0.    0.    0.561974199090319981]
                       [                                      ]
                       [0.    0.    0.    4.35252109919989660 ]
                       [                                      ]
                       [0.    0.    0.    0.498540275504532948]
That won't, however, allow inserting random variables into a row of a Matrix in column-major order (Fortran_order). Permitting a stride would be useful there; however, I suspect that the utility might be insufficient to justify the additional complexity.
Congratulations to both winners. In addition to the material award, I see that Georgios is about to earn a new leaf. Kudos.
On the other hand, if you want the program to be correct, rather than merely proved correct, an imperative style is superior 8-). With apologies to Knuth. I prefer, or at least use, a mixture of the two. A disadvantage of the applicative style, at least in Maple, is that it is significantly harder to debug/trace.
FYI, Dr Lamport is a he, not a she.
I wondered the same thing, that is, whether Sample(X) should return a procedure that can operate on posints (to return a Vector), lists of ranges (to return a multidimensional rtable), or an an rtable directly. Another possibility is provide a keyword to Sample to tell it what type arguments a generated procedure should expect. I did some timing, testing the following two variations (of returned procedure):
 
# original
    proc(R) p(R, 'NULL', [ds], true) end proc;
# type check and branch
    proc(R :: Or(posint,list(range(integer)),rtable(datatype=float[8])))
        if R::rtable then
            p(R, 'NULL', [ds], true);
        else
            error "not implemented";
        end if;
    end proc
# just branch
    proc(R)
        if R::rtable then
            p(R, 'NULL', [ds], true);
        else
            error "not implemented";
        end if;
    end proc
The original and the 'just branch' versions are about the the same. Adding type checking ignificantly slows the operation (3x) and increases memory allocation (40x??) Actually, the real problem appears to be including the 'datatype=float[8]' option in the rtable type declaration. If that is changed to just rtable, then 'type check and branch' is essentially the same as 'just branch'. What do you expect the optional second argument to do? Specify subdimensions to be filled?
While it is true that Sample does not currently allow passing in an rtable, the external code that fills an existing rtable with samples exists. It shouldn't be too hard for Sample to be extended. Here is a proof of concept illustrating that this can be achieved (I have to use kernelopts(opaquemodules=false) to permit accessing some local procedures).
SampleRtable := proc(X)
local p,ds,opacity;
description "return a procedure that fills an rtable with samples of X";
    try
        opacity := kernelopts('opaquemodules' = false);
        p := Statistics:-ExternalSupport:-DefineExternal('MapleRandomSample');
        # this is a hack, it can be extended to support full options of Sample
        ds := ( Statistics
                :-Simulation
                :-DefaultGenerator
                :-GetParameters
              )(X , table([('range')       = 'deduce'
                           ,('tolerance')  = 1000
                           ,('updates')    = 100
                           ,('basepoints') = 'deduce'
                          ])
               );
    finally
        kernelopts('opaquemodules' = opacity);
    end try;
    proc(R) p(R, 'NULL', [ds], true) end proc;
end proc:

X := RandomVariable(Normal(2,3)):
p := SampleRtable(X):
R := rtable(1..3, datatype=float[8]):
p(R);
                     [0.561974199090320647, 4.35252109919989660, 0.498540275504532837]
Here is a test4 that uses SampleRtable
test4 := proc(N,n)
local R,X,p;
uses Statistics;
    X := RandomVariable(Normal(0,1)):
    R := Vector['row'](n, 'datatype=float[8]', 'order=Fortran_order');
    p := SampleRtable(X);
    to N do
        p(R);
    end do;
    NULL;
end proc:
This is just as fast as test3b, but with reduced memory usage, since R is reused.
While it doesn't improve the efficiency, and is undocumented, Statistics:-Sample permits a more general calling form than Sample(X, n); specifically, n can be a list of ranges, each specifying an rtable index. Thus test3b could be
test3c := proc(N,n)
local i,a,X,A;
uses Statistics;
    X := RandomVariable(Normal(0,1)):
    A := Sample(X,[1..N,1..n]);
    a := Vector[row](n,datatype=float,order=Fortran_order);
    for i from 1 to N do
        ArrayTools:-Copy(n,A,n*(i-1),1,a,0,1);
    end do;
end proc:
A has Fortran_order.
Imre Lakatos' "Proof and Reasoning" is an entertaining read. Leslie Lamport, the originator of LaTeX, has written a brief PDF, How to Write a Proof, describing his method for writing structured proofs.
Seems reasonable to me. You might make it more useful by showing the upper bound on the number of iterations. For n items, it should be O(lg(n)).
This returns a set (see my comments in another response below). Don't swap l and r in the anonymous procedure, it is significantly less efficient if you do so.
f6 := proc(L)
    foldl((l,r) -> map(x->map(`+`,r,x)[],l), {0}, L[]);
end proc:
This returns a set (see my comments in another response below). Don't swap l and r in the anonymous procedure, it is significantly less efficient if you do so.
f6 := proc(L)
    foldl((l,r) -> map(x->map(`+`,r,x)[],l), {0}, L[]);
end proc:
This example is fairly tricky. Note that f(1) is not evaluated until the very last step in `assuming` (the procedure that is called by using the infix assuming operator). If you had used f(x), then assuming would evaluate f(x) earlier, because x is the assumed variable, however, the result would be the same since the procedure ignores its argument and uses the global x. One might consider creating a version of assuming that evaluates its argument, for example,
`&assuming` := proc(ex) `assuming`([ex],[_rest]) end proc:
f := ()->ln(exp(x)):
f() assuming x::positive;
                            ln(exp(x))
f() &assuming (x::positive);
                              x
Note that the parenthese are required because the neutral operator (&assuming) has a higher binding strength than ::. Let's apply this to the previous example:
f := proc(x) sqrt(a^2)+x end proc:
f(1) &assuming (x::positive);
                                   (a^2)^(1/2) + 1
We get the same thing! The reason for that is subtle. With the variable a assumed positive, Maple simplifies sqrt(a^2) to a, however, it does not simplify (a^2)^(1/2), which is what sqrt evalutes to:
sqrt(a^2) + 3*(a^2)^(1/2) assuming a::positive;
                                a + 3*(a^2)^(1/2)
This example is fairly tricky. Note that f(1) is not evaluated until the very last step in `assuming` (the procedure that is called by using the infix assuming operator). If you had used f(x), then assuming would evaluate f(x) earlier, because x is the assumed variable, however, the result would be the same since the procedure ignores its argument and uses the global x. One might consider creating a version of assuming that evaluates its argument, for example,
`&assuming` := proc(ex) `assuming`([ex],[_rest]) end proc:
f := ()->ln(exp(x)):
f() assuming x::positive;
                            ln(exp(x))
f() &assuming (x::positive);
                              x
Note that the parenthese are required because the neutral operator (&assuming) has a higher binding strength than ::. Let's apply this to the previous example:
f := proc(x) sqrt(a^2)+x end proc:
f(1) &assuming (x::positive);
                                   (a^2)^(1/2) + 1
We get the same thing! The reason for that is subtle. With the variable a assumed positive, Maple simplifies sqrt(a^2) to a, however, it does not simplify (a^2)^(1/2), which is what sqrt evalutes to:
sqrt(a^2) + 3*(a^2)^(1/2) assuming a::positive;
                                a + 3*(a^2)^(1/2)
Sorry, I wasn't clear. My "improvements" didn't solve the set/list problem; they were mere variations demonstrating some minor Maple coding technique. To fix the set/list issue, you'll have to handle them explicity (as you do above), which reduces the simplicity and beauty of your original code. Note that backquotes around set and list serve no purpose. Using the `[]` and `{}` operators is nice technique.
First 156 157 158 159 160 161 162 Last Page 158 of 195