Joe Riel

9660 Reputation

23 Badges

20 years, 21 days

MaplePrimes Activity


These are replies submitted by Joe Riel

Manipulating an exprseq can be tricky; you have to be careful when passing a sequence to a procedure because Maple then interprets it as separate arguments, which may not be what you want. Also, be careful when doing something like

exprseq := [a,b],[c,d]:
for elim in exprseq do ... end do;

This may not do what you want if the exprseq contains only one sublist, it will then "unpack" the list.

N := 1234567:
seq(irem(N,10,'N'),i=1..length(N));
                              7, 6, 5, 4, 3, 2, 1

If you convert to a string then parse, you don't need to reverse the order:

N := 1234567:                       
seq(parse(d), d = sprintf("%d",N)); 
                              1, 2, 3, 4, 5, 6, 7

N := 1234567:
seq(irem(N,10,'N'),i=1..length(N));
                              7, 6, 5, 4, 3, 2, 1

If you convert to a string then parse, you don't need to reverse the order:

N := 1234567:                       
seq(parse(d), d = sprintf("%d",N)); 
                              1, 2, 3, 4, 5, 6, 7

Yes, on rereading my opening sentence I agree that it is not clear.  As you correctly concluded, both methods using a table are O(n).

If you have an upper bound on the number of entries, using an rtable instead of a table with the "standard" method does use slightly less memory, however, I don't observe a difference in speed.

Addendum: I've edited the blog entry to clarify the meaing.

Are you referring to the displayed output, which would depend on your postscript viewer, or the plotted output?  I don't see any of those effects on the plotted output (plotted with an hp laserjet 1100).  In the ghostview (gv) display on the screen, the y-axis appears thinner than the x-axis, however, that isn't a Maple problem.  If interested I can upload the .ps file.

Try

plotsetup('ps','plotoutput'="plot.ps",'plotoptions'="portrait,noborder");
plot(x^2,x=-1..2);
I don't see any of the jaggies that you mentioned.

As has been pointed out previously, Maple does not have the ability to reassign precedence of operators.  Given that, there can be no further explanation [package writers generally do not get to touch the kernel].  The author of the Logic package was aware of this limitation.  From the Logic,operators help page:

Precedence
- Note that the Logic package operators do not have the same precedence as
  corresponding three-valued operators. In particular, all operators have the
  same precedence, so a &or b &and c is equivalent to (a &or b) &and c, not a
  &or (b &and c). Parentheses should be used to correctly specify the
  precedence. 

The more interesting question is whether we should be able to reassign precedence of otherwise unused neutral operators.  There have been times when I would have found it useful, for example in the ladder notation introduced in the Syrup package as a compact means to describe circuits.  But I see this as a minor convenience. How useful would it be, really?  Jacques mentioned that Haskell provides this ability; has anyone put it to good use?

The reason, I suspect, is that reassigning binding strength is not something to be trifled with. How common is it that languages permit reassigning the binding strength of operators?  That seems a rather low-level operation, it affects the parser.  If the binding strengths of neutral operators could be changed arbitrarily, how would mint (the syntax checker) handle it?   One possibility might be to constrain the binding strength of neutral operators to lie within a range, but allow the user to set their relative strength.  The Logic package, when loaded, would then set the relative strengths of its neutral operators accordingly.

I don't see how the missing binding strengths make the logic operators "useless".  Using parentheses allows one to properly associate them; that isn't as nice as otherwise. 

The reason that this is not done automatically is that, as mentioned previously in this thread, Maple has no mechanism for changing the binding strength (precedence) of operators.  All neutral operators, with the exception of &*, have the same binding strength.  Converting from active operators works because they have the appropriate precedence so the conversion can use that additional information to properly associate the output.

It would be nice if there were a way to reassign the binding strength of neutral operators.  It seems strange to me that &* has a lower binding strength than other neutral operators; I would have expected the opposite.

 

That has been my understanding---the goto implementation is not particularly efficient---however, I've also learned that testing frequently reveals errors in the received view.  In this case, it is easy enough to demonstrate a simple implementation in which, for some inputs, the goto statement is no less efficient.  Compare the following three alternative implementation of a case statement:

f1 := proc(a)
local b,k;
    if a in '[a1,a2,a3,a4,a5,a6,a7,a8,a9]' then
        do
            goto(a);
            a1: b := 1; break;
            a2: b := 2; break;
            a3: b := 3; break;
            a4: b := 4; break;
            a5: b := 5; break;
            a6: b := 6; break;
            a7: b := 7; break;
            a8: b := 8; break;
            a9: b := 9; break;
        end do;
    else
        b := 10;
    end if;
    b;
end proc:

f2 := proc(a)
local b;
    if   'a1' = a then b := 1;
    elif 'a2' = a then b := 2;
    elif 'a3' = a then b := 3;
    elif 'a4' = a then b := 4;
    elif 'a5' = a then b := 5;
    elif 'a6' = a then b := 6;
    elif 'a7' = a then b := 7;
    elif 'a8' = a then b := 8;
    elif 'a9' = a then b := 9;
    else b := 10;
    end if;
    b;
end proc:

f3 := proc(a)
local b;
    try
        error sprintf("%a", a);
    catch "a1": b := 1;
    catch "a2": b := 2;
    catch "a3": b := 3;
    catch "a4": b := 4;
    catch "a5": b := 5;
    catch "a6": b := 6;
    catch "a7": b := 7;
    catch "a8": b := 8;
    catch "a9": b := 9;
    catch:      b := 10;
    end try;
    b;
end proc:

Here we measure the time required for each:

n := 4:
for k to 10 do
    k = (time(proc() to 10^n do f1(a||k); end do end proc())
         ,time(proc() to 10^n do f2(a||k); end do end proc())
         ,time(proc() to 10^n do f3(a||k); end do end proc())
         ,time(proc() to 10^n do f4(a||k); end do end proc())
        );
end do;
                           1 = (0.112, 0.052, 0.232)
                           2 = (0.108, 0.060, 0.252)
                           3 = (0.096, 0.068, 0.252)
                           4 = (0.092, 0.088, 0.240)
                           5 = (0.112, 0.080, 0.240)
                           6 = (0.112, 0.084, 0.252)
                           7 = (0.096, 0.104, 0.232)
                           8 = (0.100, 0.112, 0.236)
                           9 = (0.116, 0.104, 0.256)
                          10 = (0.068, 0.124, 0.240)

For inputs that require more than about 7 comparisons, the goto method is equivalent to if/elif.  The try/catch technique was mainly for comparion.

I'm not suggesting that goto should be used---there are reasons other than speed that it might not be a good idea.

That has been my understanding---the goto implementation is not particularly efficient---however, I've also learned that testing frequently reveals errors in the received view.  In this case, it is easy enough to demonstrate a simple implementation in which, for some inputs, the goto statement is no less efficient.  Compare the following three alternative implementation of a case statement:

f1 := proc(a)
local b,k;
    if a in '[a1,a2,a3,a4,a5,a6,a7,a8,a9]' then
        do
            goto(a);
            a1: b := 1; break;
            a2: b := 2; break;
            a3: b := 3; break;
            a4: b := 4; break;
            a5: b := 5; break;
            a6: b := 6; break;
            a7: b := 7; break;
            a8: b := 8; break;
            a9: b := 9; break;
        end do;
    else
        b := 10;
    end if;
    b;
end proc:

f2 := proc(a)
local b;
    if   'a1' = a then b := 1;
    elif 'a2' = a then b := 2;
    elif 'a3' = a then b := 3;
    elif 'a4' = a then b := 4;
    elif 'a5' = a then b := 5;
    elif 'a6' = a then b := 6;
    elif 'a7' = a then b := 7;
    elif 'a8' = a then b := 8;
    elif 'a9' = a then b := 9;
    else b := 10;
    end if;
    b;
end proc:

f3 := proc(a)
local b;
    try
        error sprintf("%a", a);
    catch "a1": b := 1;
    catch "a2": b := 2;
    catch "a3": b := 3;
    catch "a4": b := 4;
    catch "a5": b := 5;
    catch "a6": b := 6;
    catch "a7": b := 7;
    catch "a8": b := 8;
    catch "a9": b := 9;
    catch:      b := 10;
    end try;
    b;
end proc:

Here we measure the time required for each:

n := 4:
for k to 10 do
    k = (time(proc() to 10^n do f1(a||k); end do end proc())
         ,time(proc() to 10^n do f2(a||k); end do end proc())
         ,time(proc() to 10^n do f3(a||k); end do end proc())
         ,time(proc() to 10^n do f4(a||k); end do end proc())
        );
end do;
                           1 = (0.112, 0.052, 0.232)
                           2 = (0.108, 0.060, 0.252)
                           3 = (0.096, 0.068, 0.252)
                           4 = (0.092, 0.088, 0.240)
                           5 = (0.112, 0.080, 0.240)
                           6 = (0.112, 0.084, 0.252)
                           7 = (0.096, 0.104, 0.232)
                           8 = (0.100, 0.112, 0.236)
                           9 = (0.116, 0.104, 0.256)
                          10 = (0.068, 0.124, 0.240)

For inputs that require more than about 7 comparisons, the goto method is equivalent to if/elif.  The try/catch technique was mainly for comparion.

I'm not suggesting that goto should be used---there are reasons other than speed that it might not be a good idea.

I had assumed that the b1, b2, etc. represented code.  If they are actually just expressions, then a better way to do this would be with a preassigned table:

T := table([a1=b1, a2=b2, ... ]);

R := `if`(assigned(T[a])
              , T[a]
              , some_other_value
             );

I had assumed that the b1, b2, etc. represented code.  If they are actually just expressions, then a better way to do this would be with a preassigned table:

T := table([a1=b1, a2=b2, ... ]);

R := `if`(assigned(T[a])
              , T[a]
              , some_other_value
             );

You can pass the option axis=[mode=log] to plots[odeplot] and it will use a loglog plot.  Use axis[2]=[mode=log] to affect just the y-axis.  See ?plot,axis

You can pass the option axis=[mode=log] to plots[odeplot] and it will use a loglog plot.  Use axis[2]=[mode=log] to affect just the y-axis.  See ?plot,axis

First 135 136 137 138 139 140 141 Last Page 137 of 195