Joe Riel

9660 Reputation

23 Badges

20 years, 3 days

MaplePrimes Activity


These are answers submitted by Joe Riel

You are comparing solutions to different problems.  Note that the original post had a typo (read down a few replies to see the correction).  His original description had the exponent as 3/2.  It should have been 2/3.  My original response (with the A and B) was for the 3/2 exponent.  My later response was for the 2/3 exponent.

You don't need to put it in that form.  Just do

numer(x+y/z);
                        x*z + y

Well, you could always cheat and use identify:

len := VectorCalculus:-ArcLength(<x,(x/2)^(2/3)>, x=0..2):
identify(evalf[50](len));                                 
                                                    1/2
                                               20 10
                                               -------- - 2/27
                                                  27

This works,

len := VectorCalculus:-ArcLength(<x,(x/2)^(2/3)>, x=0..2,inert):
IntegrationTools:-Change(len, y=x^(2/3)):
value(%);
                                                    1/2
                                               20 10
                                               -------- - 2/27
                                                  27

#1:  v is assigned, sequentially, each element off L.  v[2] is the second element of v.  For example,

L := [[a,f1],[b,f2],[c,f3]]: # (normally fk are numerical values, here I made them symbolic for demonstration.
tot := add(v[2], v in L);
                                 tot := f1 + f2 + f3

So, what it does is sum the frequencies in the list and assign the total to tot.  I'm not sure what you are implying with  your comment about just counting the total elements in the list.  The Shannon-Fano algorithm does not use  (half) the number of elements but rather (half) the sum of the frequencies as the criteria.

#2: Here I use k as an index. The reason for doing this rather than

for v in L while cumul < tot/2 do
    cumul := cumul + v[2];
end do

is that the purpose of this loop is to determine the index, k, so that the sum of the frequencies in elements 1 to k is approximately half the total.  Another way to do this, possibly clearer, is to use a separate counter rather than the loop counter:

split := 0:
cumul := 0:
for v in L while cumul < tot/2 do
    split := split+1;
    cumul := cumul + v[2];
end do;

A difference with that approach is that when the loop ends, split is one less than the k was in my original code. So you would have to adjust the ranges accordingly.

Note that in both implementations (my original and this trivial modification) the split is such that the sum of the frequencies of the elements in the first list is less than half the total.

If you want to see the code in action, call

debug(ShannonFano);
before making the call to ShannonFano.

Use the solve procedure.  Combine the two equations into a set, and pass them to solve.  For this problem, in which the coefficients are numerical, you can use fsolve, which is generally faster (not an issue here).  Note that in Maple multiplication is expressed with *.  For example:

eqs := {3*x + 4*y = 1,  y = 3}:
solve(eqs, {x,y});
fsolve(eqs, {x,y});

Something like this is closer to what you had in mind, I think.  I may have gotten the details of the implemenation wrong, but this should give you the idea.  Note that I return a nested list that encodes the tree structure.  Also note that I changed your compare to >, which requires less looping.

compare := proc(a::list,b::list)
    evalb(a[2] > b[2])
end proc:

ShannonFano := proc(L :: listlist)
local n,k,v,tot,cumul;
    n := nops(L);
    if n < 2 then
        return L[];
    end if;
    tot := add(v[2], v in L);
    cumul := 0;
    for k to nops(L) while cumul < tot/2 do
        cumul := cumul + L[k,2];
    end do;
    [procname(L[1..k-1]), procname(L[k..n])];
end proc:

listA :=[[a,41],[b,33],[c,23],[d,25],[e,100]]:
listB := sort(listA, compare);
            listB := [[e, 100], [a, 41], [b, 33], [d, 25], [c, 23]]

ShannonFano(listB);
             [[[e, 100], [a, 41]], [[[b, 33], [d, 25]], [c, 23]]]


Try

Re(exp(I*k*x)) assuming real;
                                   cos(k x)

A minor correction.  It is not true that explicit looping in Maple is necessarily inefficient.  In fact, for the particular task given, which consists of printing a column of primes, most of the time is likely to be spent in the print routine, if not in the primality testing. Note by the way (this is intended for the original poster) that printing, required here, is not something one ordinarily does with Maple.  It is usually more effective to return output (say as a list of primes) rather than to print it, since we can further manipulate the output but can do little but look at printed output.

To demonstrate my point about explicit looping not necessarily being inefficient, here are two procedures that return a list of primes, from m to n.  The second one, which is essentially what Doug described, is the superior procedure. It is short, clear, and does the job. However, it really is is only marginally faster than the first.  The call to time shows the elapsed duration required for each to return all primes from 1 to 100,000.

GetPrimes1 := proc(m,n)
local cnt,T,i;
    cnt := 0;
    T := table();
    for i from m to n do
        if isprime(i) then
            cnt := cnt+1;
            T[cnt] := i;
        end if;
    end do;
    convert(T,'list');
end proc:

GetPrimes2 := proc(m,n)
    select(isprime,[seq(m..n)]);
end proc:
N := 100\000:
time(GetPrimes1(1,N));
                                     1.880

time(GetPrimes2(1,N));
                                     1.824

 

Since you've already written a procedure to compute A - B, how about computing the intersection using that procedure and some basic set theory.

As Robert hints, it is hard to give advice without knowing what is allowed.  His suggestion of using member and remove is good; they permit an efficient and compact procedure.  My advice, however, is to not use those two and see what you can accomplish with a more traditional (but not Maple-esque) style of programming.  Actually, the best approach would be to develop a few procedures, one using remove and member, another using loops and conditionals, and a third using the builtin in minus operator, then compare their performance and capabilities.  You can use the Maple time function to measure the evaluation time.  For example, if minus were allowed

SetDiff1 := proc(A,B) A minus B end proc:
S := {seq(1..1000)}: # create a set of integers from 1 to 1000
time(SetDiff1(S,S);
                                             0.

Most procedures are likely to run considerably slower, so if you do time one, start with a relatively small set. Remember, too, that Maple is a math tool.  There are some (too) clever algebraic approaches that can solve this problem.

There might be such a command in the GraphTheory package, but one doesn't jump out at me.  Writing a recursive procedure that solves this is simple enough; whether there is a more efficient technique is the real question.  Here's one way:

FindPaths := module()
export ModuleApply, FindPaths;
local cnt :: nonnegint
    , paths :: table
    ;

    ModuleApply := proc(G, u, v)
        cnt := 0;
        paths := table();
        FindPaths(G,u,v,{},[u]);
        convert(paths,'list');
    end proc;

    FindPaths := proc(G, u, v, visited :: set, path :: list)
    local deps, n, newpath;
    uses GraphTheory;
        deps  := convert(Departures(G,u),'set') minus visited;
        for n in deps do
            newpath := [path[],n];
            if n = v then
                cnt := cnt+1;
                paths[cnt] := newpath;
            else
                procname(G,n,v, visited union {n}, newpath);
            end if;
        end do;
        NULL;
    end proc:

end module:

G := GraphTheory:-Digraph({[1,2],[2,3],[1,3],[2,4],[4,2],[4,3]}):
FindPaths(G,1,3);
                                           [[1, 2, 3], [1, 2, 4, 3], [1, 3]]



What do you expect to learn?  Using recursion is simple enough, the best way is through practice.  More complicated is learning when and how to avoid recursion when it is inefficient.

When using recursion with Maple, one can frequently use the remember/cache option to significantly speed up a compuation.  For example, consider the classic Fibonacci sequence:

f(0) = 0:  f(1) = 1;  f(n) = f(n-1) + f(n-2):
fib := proc(n::nonnegint)
   if n = 0 then return 0
   elif n = 1 then return 1
   else return fib(n-1) + fib(n-2);
   end if:
 end proc:

This is quite inefficient:

time(fib(30));
                                 8.150

However, by adding the cache option, so that previous calls are cached, it becomes significantly faster

fib := proc(n::nonnegint)
option cache;
   if n = 0 then return 0
   elif n = 1 then return 1
   else return fib(n-1) + fib(n-2);
   end if:
end proc:

time(fib(1000));
                                     0.012

It is also possible to explicitly store results without using a cache/remember table.  That can be done with an assignment statement, fib(1) := 1. 

fib := proc(n::nonnegint)
   fib(n) := fib(n-1) + fib(n-2);
end proc:
fib(0) := 0:
fib(1) := 1:

time(fib(1000));
                                   0.012

You can pass a procedure to a Matrix constructor that initializes the Matrix:

c := LinearAlgebra:-RowDimension(d):
U := Matrix(3,4, (s,t) -> add((d[s,t]/d[j,t])^2, j=1..c));

Probably not a concern, but slightly more efficient is

U := Matrix(3,4, (s,t) -> d[s,t]*add(1/d[j,t]^2, j=1..c));

If efficiency were an actual concern, you could first create a Vector and then reuse it
V := Vector(c, t -> add(1/d[j,t]^2, j=1..c):
U := Matrix(3,4, (s,t) -> d[s,t]*V[t]));

Your code is missing some steps, in particular, it doesn't indicate how the values in the first column are assigned. Probably just as well, since once you get the general idea you can fill that in.  You should probably make y a procedure (operator).  Also, you might use a Matrix (or Array) rather than the deprecated array structure (your code assign P, but then uses p; be aware that Maple is case-sensitive). Note also that Maple's assignment operator is `:=', not `='.

P := Matrix(51,3):
y := s -> evalf((-1)*0.6e-1*(arctan(10*s/1.3+(-10)*.3)/Pi+1/2)*cos(6*Pi*s/1.3));
for i to 51 do
    P[i, 2] := y(0.26e-1*i);
end do:
 

Simpler is to use seq:

 seq('(k,k+1)', k=0..20,4);
                   0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21
First 94 95 96 97 98 99 100 Last Page 96 of 114