acer

32348 Reputation

29 Badges

19 years, 330 days
Ontario, Canada

Social Networks and Content at Maplesoft.com

MaplePrimes Activity


These are replies submitted by acer

You'll need to attend to the issues raised in both (or the first two, by date) Answers below.

acer

I suggest the copy command instead of LinearAlgebra:-Copy, for three reasons (not applicable here, but worth knowing):

The copy command is global, and not part of any package. So it works without requiring that LinearAlgebra be loaded (or that the long-form name LinearAlgebra:-Copy be used).

The copy command works on all of Arrays and Matrices and Vectors, while LinearAlgebra:-Copy only works on Matrices and Vectors.

The copy command does not pass along the readonly attribute that a Vector/Matrix might have. I think that's sensible; the target object might be read-only but in that case there is little purpose to having any new duplicate also be immutable. Who needs two immutable instances of the same data?!

showstat(LinearAlgebra:-Copy,6);

showstat(copy,1..2);

The copy command does pass along other attributes (the rtable constructor handles that part automatically, and the ('attributes') = [attributes(_MV)] part of Copy's source is not needed, I suspect. I don't see much point to LinearAlgebra:-Copy's existing.

acer

I suggest the copy command instead of LinearAlgebra:-Copy, for three reasons (not applicable here, but worth knowing):

The copy command is global, and not part of any package. So it works without requiring that LinearAlgebra be loaded (or that the long-form name LinearAlgebra:-Copy be used).

The copy command works on all of Arrays and Matrices and Vectors, while LinearAlgebra:-Copy only works on Matrices and Vectors.

The copy command does not pass along the readonly attribute that a Vector/Matrix might have. I think that's sensible; the target object might be read-only but in that case there is little purpose to having any new duplicate also be immutable. Who needs two immutable instances of the same data?!

showstat(LinearAlgebra:-Copy,6);

showstat(copy,1..2);

The copy command does pass along other attributes (the rtable constructor handles that part automatically, and the ('attributes') = [attributes(_MV)] part of Copy's source is not needed, I suspect. I don't see much point to LinearAlgebra:-Copy's existing.

acer

Most of the "new in Mma 8" features looked to me to fall into just a few categories. In particular,

Control & Dynamical Systems
(Group &) Graph Theory
Images and wavelet analysis
(Univariate & Multivariate) Statistics

One set in particular, Control, is something Maple has had for a while with the functionality being spread between the DynamicSystems, Linearization, LinearAlgebra's CARE/DARE, and the Control toolbox for MapleSim (which contains higher level routines such as for Linear Quadratic Regulators, etc). The functionality of that toolbox can pretty much be built from the components already in Maple proper, eg. see one of the worksheets on the MapleCloud which introduced the Riccati equation solvers in LinearAlgebra.

As for the others, well, Maple has packages for those disciplines. So a more interesting question might be more along the lines of: what particular functionality of "new in Mma 8" would be useful to have. Without being very specific, it's not so interesting. In other words: what specific new-in-Mma-8 commands would be really useful (and not just cool) in Maple?

I 've always noticed that Wolfram Research has the habit of add lots of routines. They tend to split functionlity into separate routines which might otherwise be combined or omitted in the beginning. (Example, who really needs a dedicated command for generating Pascal matrices, when it can be done 5 ways in 1 line?)

There was some very neat efficiency changes in Mma 8, particulary related to the speed of LinearAlgebra on large exact integer Matrices. See here. It's a great shame if they have not provided both Maple and Mma source code used in the benchmarking, especially given the important distinction between Maple's time and time[real] utilities (I didn't see sources, can anyone else?)

acer

The `else` clause in the system Library routine `-`, for the case of strictly more than 2 arguments, is not at all  funny because it didn't have to be coded recursively. (Is `-` thus quadratic in time as well as memory allocation, as a function of nargs?)

Technically this crash doesn't fit the criteria originally listed in the parent post, as it merely runs out of memory. But the crash manifests as a popup error message that the kernel is gone, not as any nice regular error about failure to allocate enough memory -- so maybe it fits. Certainly it ought to be easy to fix.

The following crashes a 64bit Maple 14 (Windows 7) with 6GB of RAM.

`-`($1..1e5);

 

> restart:
> T:=$1..1e3:

> st,ba:=time(),kernelopts(bytesalloc):
> T[1]-`+`(T[2..-1]);
> time()-st,kernelopts(bytesalloc)-ba;
                            -500498
                             0., 0

> st,ba:=time(),kernelopts(bytesalloc):
> `-`(T);
> time()-st,kernelopts(bytesalloc)-ba;
                            -500498
                         0.016, 4062488

> T:=$1..1e4:
> st,ba:=time(),kernelopts(bytesalloc):
> T[1]-`+`(T[2..-1]);
> time()-st,kernelopts(bytesalloc)-ba;
                           -50004998
                           0., 131048

> st,ba:=time(),kernelopts(bytesalloc):
> `-`(T);
> time()-st,kernelopts(bytesalloc)-ba;
                           -50004998
                        1.498, 400941356

> showstat(`-`);

`-` := proc(x, y)
   1   if nargs = 1 then
   2     -x
       elif nargs = 2 then
   3     x-y
       else
   4     `-`(x-y,args[3 .. -1])
       end if
end proc

acer

@BSchor 

Here below is a Document containing a customized context-sensitive menu addition for splitting a complex number into the polar form you've described (ie, into that expression sequence of two values). You could take the red code portion and stick it in your Maple initialization file, or I suppose in a hidden code region or the Document's Startup Code area. At the end is a link to the displayed Document, as well as to a version containing the code in the Startup Code area.

The new context menu item appears under the usual "Complex Maps" submenu.

The clickable-math style of operating in Maple (context-menus, palettes, command-completion in 2D entry mode, etc) is convenient but cannot encapsulate all that Maple can do. That's because there will always be an infinite amount of mathmatical/scientific computational tasks which are not exactly captured by a prebuilt utility. But Maple is a full fledged programming environment, and so learning Maple as a programming language is useful and important, so that you can extend upon the "canned" clickable functionality. I suggest reading the Maple manuals, and in particular the Programming Manual(s). You can download those here.

 

XYZnewCM := ContextMenu:-CurrentContext:-Copy():

XYZnewCM:-Entries:-Add(

    "Polar Split",

    "(evalc@abs,evalc@argument)(%EXPR)",

    `algebraic`,

    'helpstring'="(evalc@abs,evalc@argument)",

    'operator'=Typesetting:-mover(Typesetting:-mo("→"),
                                  Typesetting:-mtext("polar split")),

    'category'="Category 1",

    'submenu'=["Complex Maps"],

    NULL):

ContextMenu:-Install(XYZnewCM);

 



Download polarsplit.mw

polarsplit_startu.mw

@BSchor 

Here below is a Document containing a customized context-sensitive menu addition for splitting a complex number into the polar form you've described (ie, into that expression sequence of two values). You could take the red code portion and stick it in your Maple initialization file, or I suppose in a hidden code region or the Document's Startup Code area. At the end is a link to the displayed Document, as well as to a version containing the code in the Startup Code area.

The new context menu item appears under the usual "Complex Maps" submenu.

The clickable-math style of operating in Maple (context-menus, palettes, command-completion in 2D entry mode, etc) is convenient but cannot encapsulate all that Maple can do. That's because there will always be an infinite amount of mathmatical/scientific computational tasks which are not exactly captured by a prebuilt utility. But Maple is a full fledged programming environment, and so learning Maple as a programming language is useful and important, so that you can extend upon the "canned" clickable functionality. I suggest reading the Maple manuals, and in particular the Programming Manual(s). You can download those here.

 

XYZnewCM := ContextMenu:-CurrentContext:-Copy():

XYZnewCM:-Entries:-Add(

    "Polar Split",

    "(evalc@abs,evalc@argument)(%EXPR)",

    `algebraic`,

    'helpstring'="(evalc@abs,evalc@argument)",

    'operator'=Typesetting:-mover(Typesetting:-mo("→"),
                                  Typesetting:-mtext("polar split")),

    'category'="Category 1",

    'submenu'=["Complex Maps"],

    NULL):

ContextMenu:-Install(XYZnewCM);

 



Download polarsplit.mw

polarsplit_startu.mw

@Alejandro Jakubi Alejandro this is something like the 3rd time in as many weeks that you have used applyrule to nice effect, deftly providing a more general solution.

This is great because applyrule deserves more notice, if not as a bug-free command then certainly as representative of a symbolic problem-solving methodology. (And heavier use can lead to more bug reports on it, which can ideally lead to it getting stronger. It has its share of weaknesses.)

Sometimes I think that Maple could learn more from Mathematica, in broad terms of how patterns are utilized. I'm not saying that Maple never uses patterns -- maybe see inttrans for example.

It's not really related to the posted topic but I'm reminded of something Alec once wrote here. I can't find the particular post, so I'll make up an example. The essence was that a human can immediately find a candidate explicit solution (namely, 1/4) of something like the following. But `solve` returns only an implicit RootOf:

> expr:=arcsin(exp(erfc(x))-x);
expr := -arcsin(-exp(erfc(x)) + x)

> eval(expr,x=1/4);
arcsin(exp(erfc(1/4)) - 1/4)

> solve(expr=eval(expr,x=1/4),x);
exp(RootOf(_Z - erfc(exp(_Z) - exp(erfc(1/4)) + 1/4))) - exp(erfc(1/4)) + 1/4

> evalf(%);
0.2500000000

With a little initiative one can see that the earlier suggestions can be made to do this example.

> restart: with(Student:-Precalculus):
> expr := x^4/sin(x)^4+2*x^2/sin(x)^2:

> a := algsubs(x^2 = y*sin(x)^2, expr):
> ans1 := CompleteSquare(a, y):
> eval(ans1, y = x^2/sin(x)^2);
                                    2    
                       /   2       \     
                       |  x        |     
                       |------- + 1|  - 1
                       |      2    |     
                       \sin(x)     /     

And,

> restart: with(Student:-Precalculus):
> expr := x^4/sin(x)^4+2*x^2/sin(x)^2:

> thaw(algsubs(x^2=freeze(x^2/sin(x)^2)*sin(x)^2, 'CompleteSquare'(expr, x^2/sin(x)^2) ));
                                    2    
                       /   2       \     
                       |  x        |     
                       |------- + 1|  - 1
                       |      2    |     
                       \sin(x)     /     

Sure, some harder example may also be taken, which in turn might be tractable (with a judicious `isolate` call, or whatever other augmenting trick). Every approach has its limitations, naturally. (Finding such is only sometimes interesting.)

acer

With a little initiative one can see that the earlier suggestions can be made to do this example.

> restart: with(Student:-Precalculus):
> expr := x^4/sin(x)^4+2*x^2/sin(x)^2:

> a := algsubs(x^2 = y*sin(x)^2, expr):
> ans1 := CompleteSquare(a, y):
> eval(ans1, y = x^2/sin(x)^2);
                                    2    
                       /   2       \     
                       |  x        |     
                       |------- + 1|  - 1
                       |      2    |     
                       \sin(x)     /     

And,

> restart: with(Student:-Precalculus):
> expr := x^4/sin(x)^4+2*x^2/sin(x)^2:

> thaw(algsubs(x^2=freeze(x^2/sin(x)^2)*sin(x)^2, 'CompleteSquare'(expr, x^2/sin(x)^2) ));
                                    2    
                       /   2       \     
                       |  x        |     
                       |------- + 1|  - 1
                       |      2    |     
                       \sin(x)     /     

Sure, some harder example may also be taken, which in turn might be tractable (with a judicious `isolate` call, or whatever other augmenting trick). Every approach has its limitations, naturally. (Finding such is only sometimes interesting.)

acer

@Christopher2222 I would say that this Document is an important example of current GUI performance.

If I download and run your latest revision, which is a Document with 2D Math input for the coded procedure, I see following.

I first split the proc defn out from the actual call to IsotopeTable(). That's key to seeing one big effect. It takes the Standard GUI 1.2 CPU seconds and 1.9 real-time (wall clock) seconds just to parse and print that proc code. That is...worrying. I call it a bug.

So I converted the code to 1D Maple Notation. And run it in a Worksheet (just because I find it easier to navigate and execute). Then the proc definition code runs lightning fast, in effectively zero time. Same for Standard as for Classic.

Then I call IsotopeTable(116), in all three variations: 2D code in Document, 1D code in Standard Worksheet, and 1D code in Classic GUI. It plots and displays a result, after a few seconds. The Classic GUI remains very smooth and responsive. The 1D Worksheet and the 2D Document instances both gets a bit sticky and doesn't scroll smoothly whenever the plot transitions from being "off screen" to "on screen" or is half-visible.

If I add more calls to IsotopeTable() then Classic stays smooth and responsive while Standard gets harder and harder to scoll and manipulate. I've heard it suggested that one of the problems seen here is that Standard plots are only ever probe-able. If there were a way to throw up a plots in Standard that only allowed as much post-display interaction as happens in Classic then maybe they would not bring the GUI to its knees so easily.

Here is a 1D editing of the code. Since most of the points in c are very small then it runs faster if order in which the conditionals are tested is reversed from the original code. Also the conditionals now do only one check for each elif (this follows up my earlier comment). You don't need to mess with op(b) just to get the dimensions of b, and note the difference between op(1,b) and op(b)[1]. And you only need compute the dimensions of b once. And now it utilizes `uses`. It's not very much faster, as a lot of time is still spent inside listdensityplot. But maybe it looks a little cleaner.

Try running it in Classic and a Worksheet, to see the differences. And compare with the earlier 2D version that you uploaded (for which you'd have to insert the time() and time[real]() calls in order to measure just the 2D proc parsing and printing portion.

restart:st, str := time(), time[real]():
 IsotopeTable := proc(elements)
 local a,b,c,d,i,j,ja,jb,jc,jd,sy,sd,sh,sm,Isoj,nIsoj,
       maxopopb1,maxopopb2;
 uses ScientificConstants, plots;
 a := table();
 for j to elements do
    Isoj := GetIsotopes(element = j);
    nIsoj := nops([Isoj]);
    if nIsoj <> 1 then
       for i from op(Isoj[1]) to op(Isoj[nIsoj]) do
          try
             a[i, j] := convert(rhs(rhs(GetElement([j, i], halflife)[2])[1]),
                                'units',
                                rhs(rhs(GetElement([j, i], halflife)[2])[3]), s)
          catch:
             try
                if is(GetElement([j, i], abundance) <> 0) then
                   a[i, j] := 0.10e12
                end if
             catch:
                a[i, j] := 1
             end try
          end try
       end do
    elif nIsoj = 1 then
       i := op(Isoj);
       try
          a[i, j] := convert(rhs(rhs(GetElement([j, i], halflife)[2])[1]),
                             'units',
                             rhs(rhs(GetElement([j, i], halflife)[2])[3]), s)
       catch:
          try
             if is(GetElement([j, i], abundance) <> 0) then
                a[i, j] := 0.10e12
             end if
          catch:
             a[i, j] := 1
          end try
       end try
    end if
 end do;
 b := Array(convert(a,array), datatype=float[8]);
 
 # We could alternatively use rtable_dims(b)
 maxopopb1 := op([2,1,2],b); #max(op(op(b)[1]));
 maxopopb2 := op([2,2,2],b); #max(op(op(b)[2]));
 
 c := Array(1 .. maxopopb1, 1 .. maxopopb2);
 sy := convert(1, 'units', year, second);
 sd := convert(1, 'units', day, second);
 sh := 3600; sm := 60;
 
 for i to maxopopb1 do
 for j to maxopopb2 do
 if b[i, j] = 0.0 then c[i, j] := 13
 elif b[i, j] < 0.1e-2 then c[i, j] := 3
 elif b[i, j] < 0.1e-1 then c[i, j] := 4
 elif b[i, j] < .1 then c[i, j] := 5
 elif b[i, j] < 1 then c[i, j] := 7
 elif b[i, j] < sm then c[i, j] := 8
 elif b[i, j] < sh then c[i, j] := 10
 elif b[i, j] < sd then c[i, j] := 15
 elif b[i, j] < sy then c[i, j] := 18
 else c[i, j] := 20 # b[i, j] >= sy
 end if end do end do;
 
 ja := [13, 3, 4, 5, 6, 7, 8, 10, 15, 18, 20];
 jb := [seq(plottools[rectangle](
          [maxopopb1+5, (1/11)*maxopopb2*i-(1/11)*maxopopb2],
          [maxopopb1+15, (1/11)*maxopopb2*i],
                                 color = COLOR(HUE, (1/20)*op(i, ja))),
            i = 1 .. nops(ja))];
 jc := maxopopb1+20;
 jd := textplot({
   [jc, (1/2)*maxopopb2, "unknown"], [jc, (1/22)*maxopopb2, "---"],
   [jc, (3/22)*maxopopb2, "0 - 0.001"], [jc, (5/22)*maxopopb2, "0.001 - 0.01"],
   [jc, (7/22)*maxopopb2, "0.01 - 0.1"], [jc, (9/22)*maxopopb2, "0.1 - 1"],
   [jc, (13/22)*maxopopb2, "seconds"], [jc, (15/22)*maxopopb2, "minutes"],
   [jc, (17/22)*maxopopb2, "hours"], [jc, (19/22)*maxopopb2, "days"],
   [jc, (21/22)*maxopopb2, "years"]}, align = right);
 d := listdensityplot(c, colorstyle = HUE, range = 0 .. 20,
         title = ["Half-Life Table of the Isotopes",
         font = [TIMES, BOLD, 20]],
         labels = ["Atomic Mass \n            A",
                   "Atomic Number \n              Z"]);
 display(d, jb, jd);
 end proc:
 time()-st, time[real]()-str;
 st,ba:=time(),kernelopts(bytesalloc):
    IsotopeTable(116);
 time()-st,kernelopts(bytesalloc)-ba;

acer

That is quite fun. Please don't mind if I make a few really minor suggestions.

Is there an `option remember` on (or under) convert/units? I ask because the code is converting each of 1 {year,day,hour,minute} into seconds. And it does that inside a double (nested) loop, hence repeating each of those conversions tens of thousands of times for your original size. It would look much cleaner (and be more good efficient practice) if instead it computed those values just once outside the loops, assigning to a few locals say.

Is it necessary to make `c` a table rather than an outright Array? Is it necessary to call plots[display] when forming `jb`?

In the loop in which you assign entries of `c`, using if..elif.. could it be that most all the conditions are unnecessarily being tested twice? I mean, consider the fact that you've ordered all the conditionals (great). So if b[i,j] is found to not be in a given range (b[i,j]<A and b[i,j]>=B) then why subsequently retest b[i,j]<B, given that you've already sorted the conditionals so that A>B>C, etc?

It's not great form to load packages outside the proc definition (if members are used in that proc) when it can be done some much more reliably and cleanly inside the proc body with the `uses` construct.

Maybe you could label the axes more helpfully, for the non-expert?

acer

It might do with some improvement.

If I may make some suggestions:

Use the modern return statement, not the RETURN() routine which has been out of fashion for about 10 years.

It's not a good idea to load a package like LinearAlgebra outside of the proc which relies on it. Use the modern `use` or `uses` facilities instead, or just utilize the full long command names in the proc body.

It's a bad idea to unprotect D (even if it's not necessary and you don't end up assigning to it, like in your code).

The code is missing the semicolon or colon terminatior in the proc's penultimate line, making it a syntax error. And the RETURN function call is missing its close-bracket, also a syntax error.

The Pinv and P locals are not strictly necessary, as they get assigned but then only used the once, in the very same line. So that line could just utilize MatrixInverse(Evecs) and Evecs in the line, and save the pair of locals.

The routine posted computes Pinv and then throws it away. That's a waste. Either use the eigenvalues to produce the diagonal factor, or return Pinv. Or normalize P so that (provided it's columns are linearly independent and a full span. (I suggest testing for diagonalizability in some other way, pls see below.)

A good routine for this would distinguish between the exact symbolic and the pure floating-point cases.

I don't like the use of computing Pinv just so that one can test the eigenvectors for linear independence & full span. I'd suggest instead to use JordanForm in the exact or symbolic case (with a simple test that the J is of type 'Matrix'('diagonal')) or to use SchurForm in the pure float case. For the float case it may depend on one's needs and goals, since diagonalizability is another ballgame there. (I also doub't I'd compute P^(-1).M.P when the diagonal factor is available by the eigenvalues -- it's an overly costly way to test.)

I'm not trying to sound harsh, but I don't quite see the point of such a new routine. What would it given that is either not a) available by other direct means, or b) not best-advised?

acer

The rather simple reason why the repetitions work (and of which length) came to me while waiting at the supermarket checkout. Isn't that a good reason to do math, so as to avoid being bored while waiting in queues?

acer

The rather simple reason why the repetitions work (and of which length) came to me while waiting at the supermarket checkout. Isn't that a good reason to do math, so as to avoid being bored while waiting in queues?

acer

First 446 447 448 449 450 451 452 Last Page 448 of 592