acer

33360 Reputation

29 Badges

20 years, 310 days
Ontario, Canada

Social Networks and Content at Maplesoft.com

MaplePrimes Activity


These are replies submitted by acer

@Ronan Yes, using numer around SV1[1] and SV1[i] is one aspect.

But notice also that M may contain entries that are actually zero (but not yet simplified to identically 0). That's the case with your example A. And (since numer expands and finds the actual zero), numer(SV1[1]) produces the actual 0. So your line,
    convert(M, set) minus {0}
fails to reject that zero entry. So I also added calls to normal around M, for creating V1 and SV1., so that such a hidden zero is caught & rejected before being used for numer(SV1[1]) or numer(SV1[i]).

You could also use simplify(M) there instead of normal(M), for that early step.  (You wrote of algebraic values, but your examples are just rational polynomial -- which is not the same thing. The normal command will resolve the latter. If you really do have Matrices with algebraic quantities then you might need simplify or evala.) Fully representative examples of your problem space are better.

ps. Do you perhaps want to utilize a similar approach for both numerator vs denominator "common" factors?

@C_R I thought that dharr's code was clear and legible and easily understandable. Hence I upvoted.

Btw, the argument checking and evalb are not strictly necessary there (if it mattered).

 

L := H = 0.01*Unit('m'), R = 0.006*Unit('m'), r_sub = 0.003*Unit('m'), k = 0.540*Unit(('W')/('m'*'K')), rho = 1060.0*Unit(('kg')/'m'^3), Cp = 3745*Unit(('J')/('kg'*'K')), Q_flux = 5000*Unit(('W')/'m'^2), Nz = 20, Nr = 20, t_final = 30*Unit('s'), t_step = Unit('s'), test_1 = Unit('kW'), test_2 = 2*Unit('N');

H = 0.1e-1*Units:-Unit(m), R = 0.6e-2*Units:-Unit(m), r_sub = 0.3e-2*Units:-Unit(m), k = .540*Units:-Unit(W/(m*K)), rho = 1060.0*Units:-Unit(kg/m^3), Cp = 3745*Units:-Unit(J/(kg*K)), Q_flux = 5000*Units:-Unit(W/m^2), Nz = 20, Nr = 20, t_final = 30*Units:-Unit(s), t_step = Units:-Unit(s), test_1 = Units:-Unit(kW), test_2 = 2*Units:-Unit(N)
 

inbaseu1 := p -> convert(p,'unit_free')=convert(simplify(p),'unit_free'):

 

The remove command itself does an evalb test, so that's not needed in the predicate inbaseu1.

remove(inbaseu1@rhs, [L]);

[test_1 = Units:-Unit(kW)]


Download ub_acc.mw

@dharr That's the same reason why I was confused as to why the OP considers this necessary.

@emendes So you're saying that,

svars:={x,y,z}:
Grid:-Set('svars'):
convert(Grid:-Map(w->map(v->[op](v),indets(w,name) minus svars),models),set)

works, but even,

svars:={x,y,z}:
Grid:-Set('svars'):
convert(Grid:-Map(w->map([op],indets(w,name) minus svars),models),set)

does not? That would surprise me.

Also, I've mentioned up above, a few times, that for me Grid:-Map was slower for the 10^5, 10^7 examples, etc, on Linux. I'd asked you a few times whether you had seen that too, but not got a response.

Similarly for my queries about whether you'd seen stack-limit issues for any of the other example sets and variants.

Similarly for whether you can set the ulimit or ulimits -s to unlimited in launching shells, eg ulimit -s unlimited and ulimit unlimited on your Linux (I know thta on OSX it needs a finite value).

I also find it hard to follow, since even for the smaller example sets I gave you didn't show the same kind of (easy-to-do) timing set results (including both with & without Grid:-Map).

Sorry, but I think I must bow out, because I can't get a clear picture of how things perform for you all round. And if I make three or four queries that I think might be pertinent I seem to be able to get a partial answer at most.

@emendes Isn't the fastest non-parallelized variant (with just plain map, not Threads:-Map) faster than the equivalent with Grid:-Map?

Actually, are all the non-parallelized variants faster than their equivalent with Grid:-Map? For the 10^7 examples I tried, that seemed the case.

Could you complete the 10^7 example in code I gave above, with any method?

My OS shell on Linux has the limit set to "unlimited".

 

ps. It might not be related, but I think that I don't know what Maple version you're using on each platform.

@emendes That's interesting, about the stacklimit.

You might be able to increase it, using the kernelopts option stacklimit. (It might depend on the limits set in the shell in which Maple is launched. I don't know well how that works on OSX.)

Are you saying that Grid:-Map actually improved timing performance on any of the base unparallelized approaches? For me, it just seemed slower...

@emendes Below, A2 construction (mine, without indets use) seems to be done faster than everything else except A5.

The measurement that matters most is "real time".

And A5 construction uses Threads:-Map with indets. But it might be the case that the thread-unsafeness of indets relates only (maybe) to its use on expressions of different nature than yours. I mean, perhaps the thread-unsafeness of indets depends on some aspect of the expression type -- rather than only to the way indets itself it coded. Maybe(?) it is safe on your examples.

restart; randomize():

svars:={x,y,z}: f := rand(0..2): g := rand(1..20): p := rand(0..1):

models:=[seq([seq(x^f()*y^f()*z^f()*alpha[g(),g()]
                  +p()*x^f()*y^f()*z^f()*alpha[g(),g()],
                  i=1..3)],j=1..10^5)]:

H:=map(`=`,svars,1):

# mine
A1 := CodeTools:-Usage( map(w->map(v->ifelse(v::`+`,op(map([op],[op(v)])),
                                             [op(v/content(v))]),eval({w[]},H)),
                            models) ):

memory used=201.97MiB, alloc change=87.00MiB, cpu time=2.15s, real time=1.74s, gc time=605.40ms

# mine, Thr
A2 := CodeTools:-Usage( Threads:-Map(w->map(v->ifelse(v::`+`,op(map([op],[op(v)])),
                                             [op(v/content(v))]),eval({w[]},H)),models) ):

memory used=192.70MiB, alloc change=496.81MiB, cpu time=5.13s, real time=550.00ms, gc time=1.50s

# OP original
A3 := CodeTools:-Usage( map(w->map(v->[op](v),indets(w,name) minus svars),models) ):

memory used=69.26MiB, alloc change=0 bytes, cpu time=1.16s, real time=759.00ms, gc time=457.15ms

# my tweak of OP original
A4 := CodeTools:-Usage( map(w->map([op],indets(w,indexed)),models) ):

memory used=69.51MiB, alloc change=0 bytes, cpu time=946.00ms, real time=590.00ms, gc time=401.00ms

A5 := CodeTools:-Usage( Threads:-Map(w->map([op],indets(w,indexed)),models) ):

memory used=66.89MiB, alloc change=0 bytes, cpu time=1.01s, real time=109.00ms, gc time=0ns

A6 := CodeTools:-Usage( Grid:-Map(w->map([op],indets(w,indexed)),models) ):

memory used=61.70MiB, alloc change=136.95MiB, cpu time=17.68s, real time=3.30s, gc time=4.66m

add(A2 - A3), add(A4 - A5), add(A6 - A5), add(A1 - A2);

0, 0, 0, 0

 

Download emendes_exS3.mw

I note also that your original is itself much faster with map than it is with Grid:-Map. I'll just stop timing that approach, below.

For an even larger number of lists in models, it removes some overhead if the procedure,
    v->ifelse(v::`+`,op(map([op],[op(v)])),[op(v/content(v))])
is pulled out of the middle mapped operator. At a smaller number its effect is less obvious.   emendes_exS3b.mw

Here's 10^6 such entries in models.

restart; randomize():

svars:={x,y,z}: f := rand(0..2): g := rand(1..20): p := rand(0..1):

models:=[seq([seq(x^f()*y^f()*z^f()*alpha[g(),g()]
                  +p()*x^f()*y^f()*z^f()*alpha[g(),g()],
                  i=1..3)],j=1..10^6)]:

H:=map(`=`,svars,1):

P := v->ifelse(v::`+`,op(map([op],[op(v)])),[op(v/content(v))]):

# mine
time[real]( map(w->map(P,eval({w[]},H)),models) );

18.112

# mine, Thr
time[real]( Threads:-Map(w->map(P,eval({w[]},H)),models) );

3.372

# OP original
time[real]( map(w->map(v->[op](v),indets(w,name) minus svars),models) );

7.900

# my tweak of OP original
time[real]( map(w->map([op],indets(w,indexed)),models) );

6.752

time[real]( Threads:-Map(w->map([op],indets(w,indexed)),models) );

1.127


Download emendes_exS3_6.mw

And here's that, for 10^7.

restart; randomize():

svars:={x,y,z}: f := rand(0..2): g := rand(1..20): p := rand(0..1):

models:=[seq([seq(x^f()*y^f()*z^f()*alpha[g(),g()]
                  +p()*x^f()*y^f()*z^f()*alpha[g(),g()],
                  i=1..3)],j=1..10^7)]:

H:=map(`=`,svars,1):

P := v->ifelse(v::`+`,op(map([op],[op(v)])),[op(v/content(v))]):

# mine
time[real]( map(w->map(P,eval({w[]},H)),models) );

214.726

# mine, Thr
time[real]( Threads:-Map(w->map(P,eval({w[]},H)),models) );

52.764

# OP original
time[real]( map(w->map(v->[op](v),indets(w,name) minus svars),models) );

87.201

# my tweak of OP original
time[real]( map(w->map([op],indets(w,indexed)),models) );

70.308

time[real]( Threads:-Map(w->map([op],indets(w,indexed)),models) );

23.144

 

 

Download emendes_exS3_7.mw

The timings grow by more than a factor of ten, for ten times as many elements. I suspect that garbage-collection may be taking its toll. I don't see a clear way to reduce garbage production in these approaches.

ps. Can the same alpha[n,m] appear twice in one of the sums, eg,
       x*z^2*alpha[3, 19] + z^3*alpha[3, 19]]
? If not then a call to content might be removed.

@emendes That's great, thanks.

I suspect that something fast can be cooked up, and without using indets. (...a bit like my variant above that didn't use indets, but likely faster as there is more structural detail known now.)

Gosh, even that 11pt (MS-Windows?) looks too heavy, to me.

Here's how it looks on my Ubuntu 24.04.4 LTS, in Maple 2026.1, without any Style-set use. This is a screenshot.

The size in this screenshot is not accurate, compared to what I see in the Maple GUI (which is actually good, for the 11pt non-bold). The ratio of the size of the 2D Input to that of the 11pt text is accurate. 

The weighting shown in this image is an accurate comparison to what I see in the product (which is actually good, for the 11pt non-bold).

Text_Linux_20261.mw

For fun,

restart;

`value/F` := proc()
   return W(args);
end proc:

 

expr1 := sin(F(p,q)) + F(cos(t),tan(t)) + %F(a,b);

sin(F(p, q))+F(cos(t), tan(t))+%F(a, b)

value(expr1);

sin(W(p, q))+W(cos(t), tan(t))+F(a, b)

value(%);

sin(W(p, q))+W(cos(t), tan(t))+W(a, b)

 

`print/Q` := proc()
   return Z(args);
end proc:

 

expr2 := sin(Q(p,q)) + Q(cos(t),tan(t)) + %Q(a,b);

sin(Q(p, q))+Q(cos(t), tan(t))+%Q(a, b)

lprint(%); # what expr2 actually contains

sin(Q(p,q))+Q(cos(t),tan(t))+%Q(a,b)


Download old_externsion_mech_ex2.mw

@C_R The way that the kernel determines that the extension procedure (user-written) exists, and passes to it, is in the kernel and not visible (if that's what you mean).

Note that your,

`value/__K`:=ex->op(ex):

would not be correct here, since (as mentioned) `value/__K` receives argument s when the kernel sees value(__K(s)) and then calls `value/__K`(s) .

By that I mean that the kernel uses the user-written `value/__K` for dealing with separate function calls of __K, whereever present as subexpressions in the expression. It gets applied separately to indets of type specfunc(__K) in the expression, when value is called on the expression.

expr := __K( sin(4*p) ) + __K( cos(3*t) ):

`value/__K` := ex->op(ex):
value(expr);

              4 p + 3 t

`value/__K` := ex->ex:
value(expr);

          sin(4 p) + cos(3 t)

@C_R Yes, the idea was to hide (temporarily freeze) products where at least one of the multiplicands was a Units:-Unit call and there were other multiplicands than just -1.

Some parts of the code may seem unnecessarily general, because I wasn't sure when I started where it would end up.

When an extension like `value/F` is created as a procedure, then it will get used for dealing with calls like
    value( F(...) )
I suppose that the designers of this mechanism thought that they might as well only pass the arguments of the F(...) call on to this new procedure.  Eg, value(F(s*t)) gets just the agument s*t passed into `value/F`.  So in my usage value(__K(s)) is just returning the argument, here just s.

@FDS_ERT That seems like a workable idea.

I created the attached Workbook, and then attached the data.xlsx file into it using the Navigator in the Workbook view in the left-panel.

I accessed it from the worksheet within the workbook using the following syntax:

   dat := ExcelTools:-Import("this://data.xlsx");

I zipped up the imp_test.maple file just because this site doesn't always deal well with files with ".maple" file-name extension.

imp_test.zip

The basic idea is that a Workbook can contain a Worksheet/Document part as well as additional files, ie. they are carried entirely within it. And such additional files may be referenced and accessed programmatically from with the worksheet part.

When the attached Workbook file (.maple extension) is opened using the Maple GUI (File->Open) then the GUI shows the worksheet part, which appears as usual.

What happens if you put,

    Units:-UseUnit(J/kg/K):

at the start of your session?

Does that alter what you get from your call to GetUnit? (In either of your two Maple versions available?)

@erik10 

I believe that your best course of action would be to contact Maplesoft Customer Service directly, to figure out your EMP status, etc.

https://www.maplesoft.com/contact/index.aspx

1 2 3 4 5 6 7 Last Page 1 of 611