Carl Love

Carl Love

28070 Reputation

25 Badges

13 years, 34 days
Himself
Wayland, Massachusetts, United States
My name was formerly Carl Devore.

MaplePrimes Activity


These are replies submitted by Carl Love

@emendes To set 1D input (aka Maple Input) as the default, go to menu Tools -> Options -> Display -> Input Display and select Maple Notation. Then go to tab Interface and at "Default format for new worksheets," select Worksheet. Then click Apply Globally, then open a new worksheet.

@vv Would you please provide an example where you think that this addressof trick provides some benefit? From my knowledge of how Maple stores things, I can't see how there'd be any benefit. The mapping of identical expressions to the same address happens in the automatic simplification of L, so (as far as I understand) the user never has access to the raw un-identified forms. See the section "The Simplification Table" of Appendix A of the Maple Programming Guide.

@Leocor Several unrelated comments:

1. Code that uses global variabes can't be threadsafe because Threads shares memory across the threads. Most complex Maple commands---regardless of the commonality of their usage---were written many years before Threads, and they use global variables (often environment variables such as Digits).

2. The errors produced by using unthreadsafe code with Threads are unpredictable. Sometimes you will just get a numerically wrong result rather than an error. A kernel crash is a also a common error in this situation. When you do have a kernel crash, there's no need to restart Maple, despite what the error message says. It's much faster to

  1. save your worksheet,
  2. then close your worksheet,
  3. then reopen your worksheet.

This is assuming that you have a normal setup where every worksheet gets a fresh kernel.

3. If you want to find a known-to-be-unique floating-point root of a real function over a real interval (finite or infinite), the command to use in the vast, vast majority of cases is fsolve, not solve or RealDomain:-solve. My opinion of RealDomain is that it only exists for pedagogical reasons for use in low-level courses such as precalculus and first-year calculus where (for strictly pedagogical reasons) one wants to avoid discussion of complex numbers. That pedagogy is flawed in my opinion: There are issues in real-variable calculus that can't be properly addressed without considering complex numbers. For example, Why does the Maclaurin series of arctangent have radius of convergence 1?

If you encounter a situation where fsolve doesn't seem to work (and there are plenty)please post it. It can often be made to work by adjusting Digits. If that doesn't work, there's a freely avaiable third-party package called DirectSearch that can be used.

4. Floating-point solutions which are known to be real for theoretical reasons often come with small imaginary parts (such, as you said, value + 0.0*I). This is due to round-off error in computations which don't have access to the knowledge that the solutions are necessarily real. These imaginary parts can be safely discarded by applying Re to them.

5. It's generally a bad idea efficiency-wise to perform a symbolic integration (int with a lowercase i) inside a procedure that has a single real parameter. If possible, do the int with a symbolic variable, using assuming to assume the variable  real, then construct the procedure by applying unapply with respect to the variable. That way, the symbolic integration is only done once.

On the other hand, if you know that the symbolic integration will fail (i.e., will return unintegrated), it's better to use evalf(Int(...)) inside the procedure. This avoids any attempt at symbolic integration and goes straight to numeric integration.

Either way, it saves a lot of time.

@vv Did you mean to say that ff with lists rather than sets is a bit faster than f4? Yes, the list-to-set conversions take some little bit of time because they involve sorting. Maple sets are always stored sorted.

In the application at hand, the uniqueness of the lists and their elements is already guaranteed: the end result is necessarily a partition of {$1..nops(L)}.

@vv While sleeping, I realized that the explicit pairing of elements to indices via `[]`~ is only needed if using Classify. It can be removed from ff and f4, making the code both simpler and faster:

f5:= proc(L::list)
local T, k;
     for  k to nops(L) do T[L[k]][k]:= () od;
     [indices]~([entries(T, nolist)], nolist)
end proc:

r5:= CodeTools:-Usage(f5(L)):
memory used=12.75MiB, alloc change=0 bytes, cpu time=125.00ms, real time=144.00ms, gc time=31.25ms

evalb(r1 = {(_-> {_[]})~(r5)[]});
     true

@emendes For Maple 14, use this (which I just posted in response to vv):

IndicesOfMatches:= proc(L::list)
local T, k;
     for  k to nops(L) do T[L[k]][k]:= () end do;
     [indices]~([entries(T, nolist)], nolist)
end proc:

This is essentially what you would get if you carefully deconstructed ListTools:-Classify specifically for this application. Once again, if you require the lists to be in a certain order, it's a simple modification.

If you're using Maple's 2d-input, I would strongly encourage you not to. But if you insist, then you may need to change () to NULL in the above.

@vv Whether or not your code is faster depends on the average length of the subsets. In the comparison that I made with Tom's code, that average was ~10. Watch what happens if I make that average ~10000:

R:= rand(1..9):
L:= ['R()' $ 99999]:
r1:= CodeTools:-Usage(
     {entries(((x-> x[2])~)~(ListTools:-Classify(x-> x[1], `[]`~(L, [$1..nops(L)]))), nolist)}
):

memory used=31.10MiB, alloc change=0 bytes, cpu time=422.00ms, real time=426.00ms, gc time=93.75ms

ff:=proc(a)
local aa,sa:=convert(a,set),T,u;
aa:=zip(`[]`,a,[$1..nops(a)]);
for u in sa do T[u]:=NULL od;
for u in aa do T[u[1]]:=T[u[1]],u[2] od;
[seq([T[u]],u=sa)];
end:

r3:= CodeTools:-Usage(ff(L)):

memory used=4.16GiB, alloc change=0 bytes, cpu time=16.61s, real time=11.99s, gc time=13.14s

evalb(r1 = {(_-> {_[]})~(r3)[]});
     true

Your code can be improved by not using iterative appending on the subsets (your table entries). Rather, each of those entries should itself be a table. Thus:

f4:= proc(a)
local T, u;
     for  u in `[]`~(a, [$1..nops(a)]) do T[u[1]][u[2]]:= () od;
     {indices}~({entries(T, nolist)}, nolist)
end proc:

r4:= CodeTools:-Usage(f4(L)):
memory used=22.67MiB, alloc change=0 bytes, cpu time=250.00ms, real time=230.00ms, gc time=78.12ms

evalb(r1 = r4);
     true

 

@taro Yes, lprint is the key to analyzing these funky name constructs. It's what I used to figure out the op numbers for my deconstructors. Working in the opposite direction, constructing names, requires nprintf. The syntax is identical to sprintf.

FourCornerScripts:= (Center, UpperLeft, LowerLeft, UpperRight, LowerRight)->
    nprintf(
        cat("#mscripts(mi(\"%a\"),", "none(),"$4, "mn(\"%a\"),mn(\"%a\"))"),
        Center, LowerLeft, UpperLeft
    )[LowerRight]^UpperRight
:
FourCornerScripts(B, 1, 2, 3, 4);

@ x-> x[1] extracts the first element of a pair [a,b]; x-> x[2] extracts the second element. It should be trivial for you to explode my code step-by-step. Nonetheless, here I have done it for you:

a:=[[x+y+z],[2*x+y+z],[x-y+z],[2*x+y+z]];

[[x+y+z], [2*x+y+z], [x-y+z], [2*x+y+z]]

nops(a);

4

$1..%;

1, 2, 3, 4

[%];

[1, 2, 3, 4]

#`[]` is equivalent to ()-> [args], but is faster because it's builtin.
zip(`[]`, a, %);

[[[x+y+z], 1], [[2*x+y+z], 2], [[x-y+z], 3], [[2*x+y+z], 4]]

map(x-> x[1], %);

[[x+y+z], [2*x+y+z], [x-y+z], [2*x+y+z]]

ListTools:-Classify(x-> x[1], %%);

table( [( [x-y+z] ) = {[[x-y+z], 3]}, ( [2*x+y+z] ) = {[[2*x+y+z], 2], [[2*x+y+z], 4]}, ( [x+y+z] ) = {[[x+y+z], 1]} ] )

map(e-> map(x-> x[2], e), %);

table( [( [x-y+z] ) = {3}, ( [2*x+y+z] ) = {2, 4}, ( [x+y+z] ) = {1} ] )

entries(%);

[{3}], [{2, 4}], [{1}]

entries(%%, nolist);

{3}, {2, 4}, {1}

{%};

{{1}, {3}, {2, 4}}

 

 

Download Classify.mw

@tomleslie I'm not saying that you were claiming that your code was particularly efficient---indeed there's something to be said for its simplicity---but you may be shocked to see just how inefficient it is:

R:= rand(1..999):
L:= ['R()' $ 9999]:
r1:= CodeTools:-Usage(
     {entries(((x-> x[2])~)~(ListTools:-Classify(x-> x[1], `[]`~(L, [$1..nops(L)]))), nolist)}
):
memory used=5.58MiB, alloc change=4.00MiB, cpu time=31.00ms, real time=46.00ms, gc time=0ns

r2:= CodeTools:-Usage(
     {seq({ListTools:-SearchAll(j,L)}, j in L)}
):

memory used=10.47GiB, alloc change=0 bytes, cpu time=89.48s, real time=89.49s, gc time=5.38s

evalb(r1 = r2);
     true

89.48/.031;
     2886.45161290323

The reason for the inefficiency is that your code repeatedly performs linear searches over the same list.

 

@tomleslie I wasn't claiming that you were claiming that any commands were threadsafe. Rather, I was addressing the following comment of yours:

Of course your original calculation should run multithreaded. At the moment I can't figure out why it doesn't....

@tomleslie The commands solve, fsolve, and int---like the vast majority of more-complicated Maple commands---aren't "thread safe". They can't be used with Threads. See ?index,threadsafe.

@taro There's no problem with the accuracy of your use of eval. The problem is with efficiency. Like I said, it forces the recomputation of the symbolic derivative every time that it's used. In other words, every time that you use eval(g(x), x= a), Maple does these steps:

x^2 is converted to 2*x, then a is substituted for x.

Using D, the conversion x^2 to 2*x is done only once, at the time g is defined, and it's only the substitution step that's done for every invocation of g.

Here's an example showing the timing difference for a complicated function:

f:= unapply(randpoly([exp,sin,cos,arctan](x), degree= 23, dense), x):
g:= x-> diff(f(x),x):
gD:= D(f):
time(eval(g(x), x= 2));

     0.218

gc(); time(gD(2));

     0.109

gc(); time(eval(g(x), x= 3));

     0.234

gc(); time(gD(3));

     0.109

By "pre-subscript", do you mean the x in x[1] or x__1? By "pre-superscript", do you mean the x in x^2?

@taro Your use of eval isn't a good way to do this. I almost consider it an accident or a coincidence that it works at all. The biggest problem with it is that it forces the re-computation of the symbolic derivative every time it is used.

It can be done without D by using unapply:

f:= x-> x^2:
g:= unapply(diff(f(x),x), x);
g(2);

Indeed, D is essentially just a combination of unapply and diff.

First 389 390 391 392 393 394 395 Last Page 391 of 709