acer

32378 Reputation

29 Badges

19 years, 334 days
Ontario, Canada

Social Networks and Content at Maplesoft.com

MaplePrimes Activity


These are replies submitted by acer

I forgot to mention, above, that you could compare the relative performance between either of,

n := 10^5: # or higher

L := RandomTools:-Generate(list(integer(range=-100..100),n)):

f:=RandomTools:-Generate(integer(range=-100..100),makeproc=true):
L := [seq(f(),i=1..n)]:

and,

n := 10^5: # or higher

V := LinearAlgebra:-RandomVector(n,generator=-100..100):
L := convert(V,list):

Using `if` as condition inside the `seq` constructor (especially with NULL as the fallback value) is a must-know technique, I agree.

And it's easy enough to compare performance of a few appoaches. Sometimes the charge can be levied at Maple (quite fairly) that it is more difficult to use because there are lots of ways to do a given task and the most efficient way is often not the most obvious. But I believe that in this case some of the performance differences can be ascribed to particular qualities of the approaches.

The 6 ways below are all repeated over again, at the end, so as to show that the timings aren't due to the order in which they are tried in the very same session.

Method C) is one of the three fast ways (almost identically quick -- the difference between them seems to vary less that does the difference they show individually when tried repeatedly in several new sessions). And method C) is the only one of the 6 shown which does not involving creating a new list as a temporary (collectible garbage) object.

The worst performer is F), which uses `is`, and that's no surprise. The `is` command is like an umbrella covering many approaches. Using it to accomplish what could be done with just some `evalb` arithmetic comparison is overkill. It's a bit like using `simplify` when you know that `nomal` covers the given expression type.

The difference between B) and D) is conceptually quite like the difference between A) and E), The D) and E) approaches both use some custom "user-defined" operator, wrapped around a builtin arithmetic comparison, which gets called for each entry test. That costs quite a bit more than does testing with just the builtin entry-wise comparison. The moral here is that it you're going to use `select` then always spend a moment wondering whether there is a (possibly creative) way to get the predicate (1st argumnet) to be a fast builtin. The user-defined operators like x->.... are still relatively slower interpreted code, no matter how short and simple they are.

And the difference between A) and B) is something similar to the difference between D) and E). If Maple didn't have the `select` command then we might code as in A) to get the functionality. Note that it becomes a bigger issue when compounded by the problem of wrapping with a user-defined operator.

 

restart;

n := 10^7:

#f:=RandomTools:-Generate(integer(range=-100..100),makeproc=true):
#L := RandomTools:-Generate(list(integer(range=-100..100),n)):
#L := [seq(f(),i=1..n)]:

V := LinearAlgebra:-RandomVector(n,generator=-100..100):
L :=convert(V,list):

# A) builtin seq, builtin `if` called for each call to `<`
CodeTools:-Usage(   nops([seq(`if`(u<0,1,NULL), u in L)])   );

memory used=343.13MiB, alloc change=308.30MiB, cpu time=5.07s, real time=5.10s

4974312

# B) builtin `select`, and builtin predicate `<`
CodeTools:-Usage(   nops(select( `<`, L, 0))   );

memory used=0.78GiB, alloc change=237.95MiB, cpu time=4.77s, real time=4.78s

4974312

# C) builtin `add`, builtin `if called for each call to `<`
CodeTools:-Usage(   add(`if`(L[i] < 0, 1, 0) , i = 1 .. n )   );

memory used=248.88MiB, alloc change=0 bytes, cpu time=4.82s, real time=4.83s

4974312

# D) builtin select, user-defined operator called for each call to `<`
CodeTools:-Usage(   nops(select( a->a<0, L))   );

memory used=0.71GiB, alloc change=0 bytes, cpu time=7.10s, real time=7.09s

4974312

# E) builtin `map`, user-defined operator called for each call to `<`
CodeTools:-Usage(   nops(map( (u->`if`(u<0,1,NULL)), L))   );

memory used=0.71GiB, alloc change=0 bytes, cpu time=9.42s, real time=9.43s

4974312

# F) builtin `select`, interpreted Library routine `is`
CodeTools:-Usage(   nops(select( is, L, negative))   );

memory used=0.71GiB, alloc change=64.00MiB, cpu time=10.45s, real time=10.45s

4974312

#
#
#

CodeTools:-Usage(   nops([seq(`if`(u<0,1,NULL), u in L)])   );

memory used=343.13MiB, alloc change=0 bytes, cpu time=4.51s, real time=4.52s

4974312

CodeTools:-Usage(   nops(select( `<`, L, 0))   );

memory used=0.78GiB, alloc change=0 bytes, cpu time=4.66s, real time=4.67s

4974312

CodeTools:-Usage(   add(`if`(L[i] < 0, 1, 0) , i = 1 .. n )   );

memory used=248.88MiB, alloc change=0 bytes, cpu time=4.79s, real time=4.78s

4974312

CodeTools:-Usage(   nops(select( a->a<0, L))   );

memory used=0.71GiB, alloc change=0 bytes, cpu time=7.07s, real time=7.09s

4974312

CodeTools:-Usage(   nops(map( (u->`if`(u<0,1,NULL)), L))   );

memory used=0.71GiB, alloc change=0 bytes, cpu time=9.34s, real time=9.35s

4974312

CodeTools:-Usage(   nops(select( is, L, negative))   );

memory used=0.71GiB, alloc change=0 bytes, cpu time=10.39s, real time=10.38s

4974312

 

 

Download listselectorcomp1.mw

Maybe I can mention one more. It's similar in spirit to the `is` approach, using `type`. It's much quicker here than is its cousin `is`. 

CodeTools:-Usage(   nops(select( type, L, negative))   );
memory used=114.25MiB, alloc change=0 bytes, cpu time=624.00ms, real time=618.00ms
4974312

acer

@bernie The question -- which I thought might make it easier for responders -- is whether the dummy in that M(r) is the same dummy of integration (by ApproximateInt, which I suspect) or of the outer dsolve/numeric.

It seems from earlier responses that you need better speed on this, is that right? Perhaps it could be rewritten as an expanded DE system so that dsolve/numeric handled the integration. That might be able to give the best accuracy and speed combination.

Maybe good to keep in mind that there is little point in requesting better accuracy from the integrator (be it ApproximateInt or evalf/Int or dsolve/numeric itself) than can be obtained from the given accuracy in the computed approximate dsolve/numeric results.

I'd like to look into this example, but I'm afraid that my spare time is limited these days.

This looks like another recasting of your questions posted on Oct 30 and Nov 19 and (in its followups) of April 17?

Why are you using ApproximateInt?

I find the use of `r` unnecessarily confusing, and somewhat dubious. Consider this snippet of the code,

vrad(x)=(1+r)^(-1/2)*ApproximateInt((1+r)^(1/2)*M(r)/r^2,r=x..10^(20),
                                     output=sum,partition=50):

Why use `r` as the variable of integration (for the quadrature, in ApproximateInt), when it's also being used in the higher scope (eventually, as variable of integration in dsolve/numeric)? Which `r` is it supposed to be, in the M(r) in that fragment?

acer

I don't see how the methodology of the SSP code is suitable for the described task. The SSP routine returns just a single way of attaining 150 with 3 shots, and a single way with 5 shots, and with 4 shots, etc (there is no solution for doing it in 1 shot or two shots, for the given data).

But the SSP routine doesn't look for all 4-shot solutions, say.

Also, the description mentions using 4 darts only. But your usage of the code seems to indicate that you want 5-shot solutions as well?!

I would guess that some other approach would be more suitable to what you've described as the goal. Perhaps a routine which generates all possibilities of 4 shots and then sieves them would be simplest. Or (slightly more involved) a routine similar to that but which abandons any sequence as soon as it is determined to be a guaranteed failure, or one which adjusts its pool of candidates on the basis of its running sum.

acer

For uniform distributions I find that it is easier and faster to use the RandomMatrix and RandomVector commands from the LinearAlgebra package. Their `generator` option is useful.

For other distributions I find that Statistics:-Sample with a RandomVariable or Distribution is fast and easier to understand than RandomTools. But that's just me.

I quite rarely turn to the RandomTools package (an exception being for list creation with random entries). The `makeproc` command does as it suggests and produces a procedure that can emit values. That's why it works in your example of using it with `Matrix`, since that command accepts an initializer (initializing procedure). There is no "list" constructor per se, unless you consider `seq` as being the sequence constructor. (You could do much worse than think of a list as a pair of square brackets around a sequence. The `[]` turns a sequence into a list (at low cost), just as `op` turns a list into a sequence (also cheaply).)

> f:=RandomTools:-Generate(integer(range=1..100),makeproc=true):

> [seq(f(), i=1..5)];

                              [93, 45, 96, 6, 98]

> Vector[row](5, f);

                             [59, 44, 100, 38, 69]

> L := [seq(f(), i=1..5)];

                           L := [1, 70, 77, 39, 92]

> s := op(L);  
           
                            s := 1, 70, 77, 39, 92

> `[]`(s);  
              
                              [1, 70, 77, 39, 92]

> evalb(% = L); # that last list is the very same object as L (lists are immutable)

                                     true


> with(LinearAlgebra):

> RandomVector[row](5,generator=1..100);  # only provides for uniform distr.

                             [57, 72, 73, 92, 27]

> RandomVector[row](5,generator=1.0..100.0);

       [79.4285256263958814, 91.6578169937176455, 42.7543669800012225,
        15.0467475240943180, 80.2277664199912124]

acer

What I'm trying to show about the endpoints is that the piecewise could exclude both (and use symbol=circle) from the support, or include both (and use symbol=solidcircle).

 

restart:

a,b:=-1,1:

G:=piecewise(-1>=x,0,1>x,1/2,0);

G := piecewise(x <= -1, 0, x < 1, 1/2, 0)

plot( G, x=5*a/2..5*b/2, view=0..3/2*1/(b-a), labels=[``,``],
      axes=box, discont=[symbolsize=15,symbol=circle], thickness=2,
      tickmarks=[[a=a,b=b],[1/(b-a)=1/(b-a)]]);

H:=piecewise(-1>x,0,1>=x,1/2,0);

H := piecewise(x < -1, 0, x <= 1, 1/2, 0)

plot( H, x=5*a/2..5*b/2, view=0..3/2*1/(b-a), labels=[``,``],
      axes=box, discont=[symbolsize=15,symbol=solidcircle], thickness=2,
      tickmarks=[[a=a,b=b],[1/(b-a)=1/(b-a)]]);

 

 

Download uniform2.mw

acer

What I'm trying to show about the endpoints is that the piecewise could exclude both (and use symbol=circle) from the support, or include both (and use symbol=solidcircle).

 

restart:

a,b:=-1,1:

G:=piecewise(-1>=x,0,1>x,1/2,0);

G := piecewise(x <= -1, 0, x < 1, 1/2, 0)

plot( G, x=5*a/2..5*b/2, view=0..3/2*1/(b-a), labels=[``,``],
      axes=box, discont=[symbolsize=15,symbol=circle], thickness=2,
      tickmarks=[[a=a,b=b],[1/(b-a)=1/(b-a)]]);

H:=piecewise(-1>x,0,1>=x,1/2,0);

H := piecewise(x < -1, 0, x <= 1, 1/2, 0)

plot( H, x=5*a/2..5*b/2, view=0..3/2*1/(b-a), labels=[``,``],
      axes=box, discont=[symbolsize=15,symbol=solidcircle], thickness=2,
      tickmarks=[[a=a,b=b],[1/(b-a)=1/(b-a)]]);

 

 

Download uniform2.mw

acer

Over the years, we have seen the ``() operator get used many times to suppress automatic simplification. Sure, it has its shortcomings: often it needs to be applied in several places throughout the input, and displaying its unevaluated function calls shows with round brackets around its arguments.

It's a bit of a strange beast, this ``() operator. Could it be given a print-slash extension, as a way to get around those round brackets?

In other words, can it be used to get an effect like this, without the extra bracketing,

 

restart:

F := proc(x) 'procname'(x); end proc:

`print/F`:=proc(x)
              if type(x,`^`) then
                map(procname,x);
              else
                cat(`#mn(`,x,`)```);
              end if;
           end proc:

`expand/F` := proc(x) op(x); end proc:

F(5)^2*F(5)^(1/2);

F(5)^(5/2)

eval(%);

F(5)^(5/2)

expand(%);

25*5^(1/2)

 

 

Download namefun0.mw

acer

Over the years, we have seen the ``() operator get used many times to suppress automatic simplification. Sure, it has its shortcomings: often it needs to be applied in several places throughout the input, and displaying its unevaluated function calls shows with round brackets around its arguments.

It's a bit of a strange beast, this ``() operator. Could it be given a print-slash extension, as a way to get around those round brackets?

In other words, can it be used to get an effect like this, without the extra bracketing,

 

restart:

F := proc(x) 'procname'(x); end proc:

`print/F`:=proc(x)
              if type(x,`^`) then
                map(procname,x);
              else
                cat(`#mn(`,x,`)```);
              end if;
           end proc:

`expand/F` := proc(x) op(x); end proc:

F(5)^2*F(5)^(1/2);

F(5)^(5/2)

eval(%);

F(5)^(5/2)

expand(%);

25*5^(1/2)

 

 

Download namefun0.mw

acer

@Alejandro Jakubi Yes, indeed. And that flexible procedure can also be applied to manipulate just the sign (or not).

restart:

dividend:=proc(ex,f:=numer(ex),t:=[expand,expand])
local n,d;
n:=t[1](numer(ex)/f):
d:=t[2](denom(ex)/f);
n/d;
end proc:

s:=-(x+y)/(x+y-1);

                              x + y  
                          - ---------
                            x + y - 1

dividend(s,sign(numer(s)),
         [u->u,u->`if`(sign(u)=-1,sort(u,[x,y],ascending),u)]);

                             x + y  
                           ---------
                           1 - y - x

s:=(x+y)/(x+y-1);

                             x + y  
                           ---------
                           x + y - 1

dividend(s,sign(numer(s)),
        [u->u,u->`if`(sign(u)=-1,sort(u,[x,y],ascending),u)]);

                             x + y  
                           ---------
                           x + y - 1

s:=-x/(x-1);

                                x  
                            - -----
                              x - 1

dividend(s,sign(numer(s)),
         [u->u,u->`if`(sign(u)=-1,sort(u,[x,y],ascending),u)]);

                               x  
                             -----
                             1 - x

s:=x/(x-1);

                               x  
                             -----
                             x - 1

dividend(s,sign(numer(s)),
         [u->u,u->`if`(sign(u)=-1,sort(u,[x,y],ascending),u)]);

                               x  
                             -----
                             x - 1

I find the above sign adjustments somewhat pleasing, collectively -- it leaves it alone or not. And the very same command can work for each case. And I'm sure that there are other (different, better, etc) uses of that `dividend` procedure.

@Alejandro Jakubi Yes, indeed. And that flexible procedure can also be applied to manipulate just the sign (or not).

restart:

dividend:=proc(ex,f:=numer(ex),t:=[expand,expand])
local n,d;
n:=t[1](numer(ex)/f):
d:=t[2](denom(ex)/f);
n/d;
end proc:

s:=-(x+y)/(x+y-1);

                              x + y  
                          - ---------
                            x + y - 1

dividend(s,sign(numer(s)),
         [u->u,u->`if`(sign(u)=-1,sort(u,[x,y],ascending),u)]);

                             x + y  
                           ---------
                           1 - y - x

s:=(x+y)/(x+y-1);

                             x + y  
                           ---------
                           x + y - 1

dividend(s,sign(numer(s)),
        [u->u,u->`if`(sign(u)=-1,sort(u,[x,y],ascending),u)]);

                             x + y  
                           ---------
                           x + y - 1

s:=-x/(x-1);

                                x  
                            - -----
                              x - 1

dividend(s,sign(numer(s)),
         [u->u,u->`if`(sign(u)=-1,sort(u,[x,y],ascending),u)]);

                               x  
                             -----
                             1 - x

s:=x/(x-1);

                               x  
                             -----
                             x - 1

dividend(s,sign(numer(s)),
         [u->u,u->`if`(sign(u)=-1,sort(u,[x,y],ascending),u)]);

                               x  
                             -----
                             x - 1

I find the above sign adjustments somewhat pleasing, collectively -- it leaves it alone or not. And the very same command can work for each case. And I'm sure that there are other (different, better, etc) uses of that `dividend` procedure.

@Doug Meade With 2D Math input an operator can be created and assigned using the syntax q(t):=...

In 2D Math mode, by default that causes a disambiguation popup menu to appear, offering the choice to parse as either function definition or remember-table assignment. The default behaviour can even be controlled as a typesetting option. See `functionassign` option on this help-page.

I think that it is wrong behaviour that upon choice of "function assignment" the GUI does not replace such input with q:=t->... and in so doing make the input unambiguous and also valid for 1D.

If I may mention one more variant,

restart:

A:=Matrix([[1,2],[2,3]]):
B:=Vector([x1,x2]):
C:=Vector([c1,c2]):

Equate( A.B+C, Vector([0,0]) );

           [x1 + 2 x2 + c1 = 0, 2 x1 + 3 x2 + c2 = 0]

acer

If I may mention one more variant,

restart:

A:=Matrix([[1,2],[2,3]]):
B:=Vector([x1,x2]):
C:=Vector([c1,c2]):

Equate( A.B+C, Vector([0,0]) );

           [x1 + 2 x2 + c1 = 0, 2 x1 + 3 x2 + c2 = 0]

acer

First 385 386 387 388 389 390 391 Last Page 387 of 592