Joe Riel

9660 Reputation

23 Badges

20 years, 9 days

MaplePrimes Activity


These are replies submitted by Joe Riel

Assuming there aren't issues with the random number generator, a simple way to reduce the rejected values is to start with random values in the range 0..m-1, discard those with cand <= iquo(m,i)*i and then compute row := irem(cand,i) + 1.  Less can be rejected if the same technique is used but the range of random integers is increased. 

I distracted myself by attempting, unsuccessfully, to symbolically compute the expected number of random values needed per shuffle, assuming the random values are in the tighter range, 0..m-1.  The expected value is

  E = add((m/k)/trunc(m/k), k=1..m)

That led to the constant

   lim(E/m, m=infinity) ~ 1.25774...

Any one know a closed form for this?

Assuming there aren't issues with the random number generator, a simple way to reduce the rejected values is to start with random values in the range 0..m-1, discard those with cand <= iquo(m,i)*i and then compute row := irem(cand,i) + 1.  Less can be rejected if the same technique is used but the range of random integers is increased. 

I distracted myself by attempting, unsuccessfully, to symbolically compute the expected number of random values needed per shuffle, assuming the random values are in the tighter range, 0..m-1.  The expected value is

  E = add((m/k)/trunc(m/k), k=1..m)

That led to the constant

   lim(E/m, m=infinity) ~ 1.25774...

Any one know a closed form for this?

I'll think about this tomorrow---a vacation day.

It would be nice if one could pass an rtable to combinat:-randperm so that it wouldn't generate any collectible garbage.

I'll think about this tomorrow---a vacation day.

It would be nice if one could pass an rtable to combinat:-randperm so that it wouldn't generate any collectible garbage.

That depends, of course, on how one measures efficiency. If the user's time is involved, its hard to beat my suggestion.  A complete implementation of a random inplace shuffle is not easy to do more efficiently, however measured, than what I proposed (above), which is not inplace but avoids details. Using the compiler will help with the speed, but restricts the type of the Matrix elements, will probably be slower and requires generating random numbers in the compiled routine.  The following compilable routine just permutes the rows in-place (using a provided temporary array). That permits using the fast output of combinat:-randperm to avoid the mess of dealing with randomization.

PermuteMatrixRows := proc(M :: Array(datatype=float[8])
                          , T :: Array(datatype=float[8])
                          , P :: Vector(datatype=integer[4])
                          , m :: nonnegint
                          , n :: nonnegint
                         )
option compile;
local i,j;
    for i to m do
        for j to n do
            T[i,j] := M[P[i],j];
        end do;
    end do;
    for i to m do
        for j to n do
            M[i,j] := T[i,j];
        end do;
    end do;
    return NULL;
end proc:

That could be used with

ShuffleMatrix3 := proc(M :: Matrix, T :: matrix)
local m,n,P;
    (m,n) := op(1,M);
    P := Vector(combinat:-randperm(m), 'datatype'=integer[4]):
    PermuteMatrixRows(M, T, P, m, n);
end proc:

For example,

M := rtable(1..m,1..n,frandom(0..1),'datatype'=float[8]):
T := rtable(1..m,1..n,'datatype'=float[8]):

ShuffleMatrix3(M, T);

The memory saving is proportional to the number of columns in M.

 It would be helpful if there were a simple random number generator, say that returned uniform floats in range [0..1), available from compiled routines. It isn't hard to create this, but that shouldn't be necessary. Then one could do the entire shuffle in the routine.

In thinking about the type restriction, it would be useful if there were a way for the Compiler to handle datatype=anything.  I assume that such rtables use pointers to the actual content. Because we are neither inspecting nor changing the data but merely moving it, this should be doable, at least theoretically.  That is, if an rtable with datatype=anything were treated as datatype=integer[kernelotsopts(wordsize)/8] by the compiler then we'd be set.  Of course that wouldn't be generally useful, but would here.  Maybe there is a clever way to do this.

That depends, of course, on how one measures efficiency. If the user's time is involved, its hard to beat my suggestion.  A complete implementation of a random inplace shuffle is not easy to do more efficiently, however measured, than what I proposed (above), which is not inplace but avoids details. Using the compiler will help with the speed, but restricts the type of the Matrix elements, will probably be slower and requires generating random numbers in the compiled routine.  The following compilable routine just permutes the rows in-place (using a provided temporary array). That permits using the fast output of combinat:-randperm to avoid the mess of dealing with randomization.

PermuteMatrixRows := proc(M :: Array(datatype=float[8])
                          , T :: Array(datatype=float[8])
                          , P :: Vector(datatype=integer[4])
                          , m :: nonnegint
                          , n :: nonnegint
                         )
option compile;
local i,j;
    for i to m do
        for j to n do
            T[i,j] := M[P[i],j];
        end do;
    end do;
    for i to m do
        for j to n do
            M[i,j] := T[i,j];
        end do;
    end do;
    return NULL;
end proc:

That could be used with

ShuffleMatrix3 := proc(M :: Matrix, T :: matrix)
local m,n,P;
    (m,n) := op(1,M);
    P := Vector(combinat:-randperm(m), 'datatype'=integer[4]):
    PermuteMatrixRows(M, T, P, m, n);
end proc:

For example,

M := rtable(1..m,1..n,frandom(0..1),'datatype'=float[8]):
T := rtable(1..m,1..n,'datatype'=float[8]):

ShuffleMatrix3(M, T);

The memory saving is proportional to the number of columns in M.

 It would be helpful if there were a simple random number generator, say that returned uniform floats in range [0..1), available from compiled routines. It isn't hard to create this, but that shouldn't be necessary. Then one could do the entire shuffle in the routine.

In thinking about the type restriction, it would be useful if there were a way for the Compiler to handle datatype=anything.  I assume that such rtables use pointers to the actual content. Because we are neither inspecting nor changing the data but merely moving it, this should be doable, at least theoretically.  That is, if an rtable with datatype=anything were treated as datatype=integer[kernelotsopts(wordsize)/8] by the compiler then we'd be set.  Of course that wouldn't be generally useful, but would here.  Maybe there is a clever way to do this.

A syntactically neater way is

A[combinat:-randperm(3)];

A syntactically neater way is

A[combinat:-randperm(3)];

As pagan suggests, using mint is a reasonable way to avoid that error.  A stop-gap to avoid the mistake is to reassign the parameters to local variables and then use only them in the procedure:

f := proc( x? )
local x;
    x := x?;
    x := 23;
end proc:

f(a); a;
                                      23

                                       a

However, that doesn't save the unwary programmer

f := proc( x? )
local x;
    x := x?;
    assign(x,23);
    x;
end proc:

f(a); a;
                                       a

                                      23
                                       
f(a);
Error, (in assign) invalid arguments

I think you are better off learning to deal with the language as is.

It's not clear to me what you want.  For example, given

y1 := A1*sin(omega1*t + theta1);
y2 := A2*sin(omega2*t + theta2);

do you want to find all values of t such that y1 = y2?   Note that generally there is no nice solution.  For example, if omega1/omega2 is irrational, then the intersections are not periodic. 

While that works here, it is poor technique; identify is expensive and may not return a result.  Much simpler is to provide a predicate to the sort routine that is used to compare values:

 sort(t, (x,y)->evalf(x-y)<0);
                                                1/2
                        [-1, 0, 1/2, 1, 3/2, 2 2   , 3]

If speed is an issue, then consider using the technique described here.

While that works here, it is poor technique; identify is expensive and may not return a result.  Much simpler is to provide a predicate to the sort routine that is used to compare values:

 sort(t, (x,y)->evalf(x-y)<0);
                                                1/2
                        [-1, 0, 1/2, 1, 3/2, 2 2   , 3]

If speed is an issue, then consider using the technique described here.

There are a few ways to inject shell variables at various points in a here document sent to Maple. The simplest is to just embed a variable reference in the code, say

maple -q -s <<EOF
   print("%s\n", $VAR);
   done
EOF

A problem with that approach is that it can be difficult to enter normal Maple input, say a back-quoted name (`mypkg/myfunc`) because the backquotes are interpreted by the shell.   To prevent interpretation, add a backslash to the EOF:

maple -q -s <<\EOF
   print("%s\n", $VAR);
   done
EOF

That, of course, prevents the $VAR from expanding.  One way around that is to pass $VAR as a Maple preprocessor directive:

maple -q -s -D VAR="$VAR" <<\EOF
   print("%s\n", VAR);
   done
EOF

Another possibility is to use the -c option to assign the variable:

maple -q -s -c "VAR:=$VAR" <<\EOF
   print("%s\n", VAR);
   done
EOF

 

Here's a similar, but slightly different technique.  The script is contained in one file, which becomes an executable.  The script acts like a pipe reading from standard input and writing to standard output.  I used this to find the unterminated procedure calls (due to a crash) from a massive printlevel dump. My awk skills are rusty, so this was easier to throw together.

#!/bin/bash

# Removed paired lines from Maple output generated with printlevel.
# The paired lines should match, hence no output, however,
# when program crashes this will show the open calls.
#
# Usage:
# $ clean-printlevel log.dat
#
# Tip:
# To avoid generating a massive file, run through a fifo
#
# $ mkfifo fifo
# $ clean-printlevel fifo > log.dat &
#
# Now fire up Maple and dump output to fifo:
#
# $ maple
#
# (**) writeto("fifo"):
# (**) printlevel := 100:
# (**) run_procedure_that_crashes();
# (**) done  # not necessary with crash
#
# Now remove the fifo and inspect log.dat
#
# rm fifo
# $ cat log.dat

script="$0"
logfile="$1"

( echo | cat - $logfile <<EOF
proc()
local line, Stk, cnt, all, g1, g2;
    line := readline('terminal');
    cnt := 0;
    while line <> 0 and line <> "quit" do
        if StringTools:-RegMatch("^(({-->)|<--)", line, 'all, g1, g2') then
            if g2 <> 'g2' then
                # Push onto stack
                g2 := 'g2';
                cnt := cnt+1;
                Stk[cnt] := line;
            elif cnt > 0 then
                # Pop stack
                cnt := cnt-1;
            end if;
        end if;
        line := readline('terminal');
    end do;
    # Print stack contents to standard out
    for cnt to cnt do
        fprintf('terminal', "%s\n", Stk[cnt]);
    end do;
    return NULL;
end proc():
EOF
) | maple -q
exit 0
# ---------------- end of script -------------------

 

You should have mentioned what you wanted (or I failed to read it).

with(StringTools):
map2(Select,IsDigit,L);
                                                           ["345", "532", "6422"]

Alternatively,

map2(RegSubs, "[^0-9]+"="", L);
                                                           ["345", "532", "6422"]

 

and once more, with the ~ operator:

Select~(IsDigit,L);            
                                                           ["345", "532", "6422"]

First 89 90 91 92 93 94 95 Last Page 91 of 195