acer

33188 Reputation

29 Badges

20 years, 209 days
Ontario, Canada

Social Networks and Content at Maplesoft.com

MaplePrimes Activity


These are replies submitted by acer

@JoyDivisionMan You could submit a bug report using this form.

That error appears to have started some time between Maple 2023.2 and Maple2024.2, ie. with some release of Maple 2024.

@nm I'd agree that is undesirable. I'd like to track down what's being remembered.

@Kitonum Those are the same reasons why I used the assumptions 0<x<1 in my Answer from yesterday.

And with x>0 I had already gotten the very same 4sec performance and the very same target result. (Only a part of those assumptions turned out necessary to get that.)

You have (importantly) added a programmatic aspect to such deduction. It might be difficult to take all that same approach in general, but it could be nice if there were somewhat easier ways to convey such detail and have the system figure more of such details as it went.

I thought that I'd checked this when I first Answered, but apparently I didn't.

Using the assumption x>0 (which is the same as the OP was willing to use in hist odetest call) in the dsolve attempt can also work pretty quickly and without undue memory use.

restart;

kernelopts(version);

`Maple 2024.2, X86 64 LINUX, Oct 29 2024, Build ID 1872373`

ode := -x*sqrt((1 - x)/(x + 1))*(x + 1)*arcsech(x)*diff(y(x), x)*exp(y(x)/arcsech(x)
       + exp(y(x)/arcsech(x))) - y(x)*exp(y(x)/arcsech(x) + exp(y(x)/arcsech(x)))
       + 2*x*sqrt((1 - x)/(x + 1))*(x + 1)*arcsech(x)^2 = 0;

-x*((1-x)/(x+1))^(1/2)*(x+1)*arcsech(x)*(diff(y(x), x))*exp(y(x)/arcsech(x)+exp(y(x)/arcsech(x)))-y(x)*exp(y(x)/arcsech(x)+exp(y(x)/arcsech(x)))+2*x*((1-x)/(x+1))^(1/2)*(x+1)*arcsech(x)^2 = 0

sol := CodeTools:-Usage( dsolve(ode) ) assuming x>0;

memory used=485.34MiB, alloc change=106.00MiB, cpu time=4.50s, real time=4.01s, gc time=848.14ms

y(x) = ln(ln(2*x-2*c__1))*arcsech(x)

odetest(sol, ode) assuming x>0;

0

Download de_hard04.mw

I guess I started trying the expln form before I started leveraging that assumption.

note: The above worked directly, if the same assumption was used. But it's not as lightning fast and lean as was the (also) successful trick of doing the temporary change: Y(x)=y(x)/arcsech(x)

The following runs very quickly, with low memory use.

restart;

kernelopts(version);

`Maple 2024.2, X86 64 LINUX, Oct 29 2024, Build ID 1872373`

ode := -x*sqrt((1 - x)/(x + 1))*(x + 1)*arcsech(x)*diff(y(x), x)*exp(y(x)/arcsech(x)
       + exp(y(x)/arcsech(x))) - y(x)*exp(y(x)/arcsech(x) + exp(y(x)/arcsech(x)))
       + 2*x*sqrt((1 - x)/(x + 1))*(x + 1)*arcsech(x)^2 = 0;

-x*((1-x)/(x+1))^(1/2)*(x+1)*arcsech(x)*(diff(y(x), x))*exp(y(x)/arcsech(x)+exp(y(x)/arcsech(x)))-y(x)*exp(y(x)/arcsech(x)+exp(y(x)/arcsech(x)))+2*x*((1-x)/(x+1))^(1/2)*(x+1)*arcsech(x)^2 = 0

 

new2 := eval(ode, y(x)=Y(x)*arcsech(x));

-x*((1-x)/(x+1))^(1/2)*(x+1)*arcsech(x)*((diff(Y(x), x))*arcsech(x)-Y(x)/(x^2*(1/x-1)^(1/2)*(1/x+1)^(1/2)))*exp(Y(x)+exp(Y(x)))-Y(x)*arcsech(x)*exp(Y(x)+exp(Y(x)))+2*x*((1-x)/(x+1))^(1/2)*(x+1)*arcsech(x)^2 = 0

 

new2b := simplify(new2) assuming x>0;

(-(diff(Y(x), x))*exp(Y(x)+exp(Y(x)))+2)*x*(-x^2+1)^(1/2)*arcsech(x)^2 = 0

Sol2 := dsolve(new2b);

Y(x) = ln(ln(2*x+2*c__1))

sol2 := solve(eval(Sol2, Y(x)=y(x)/arcsech(x)), {y(x)})[];

y(x) = ln(ln(2*x+2*c__1))*arcsech(x)

odetest(sol2, ode) assuming x>0;

0

Download de_hard03.mw

Another note on variables, since the OP mentioned "names": the declared globals,
the declared locals, and the lexicals are (the) symbols and not, say, indexed
names as might appear and be used.

restart;


Notice that it is the symbol res that gets implicitly declared local
to the procedure assigned to f, not the name res[1] .

f := proc() local g,x;
  g := proc()
    int(sin(x[1]), x[1]=0..Pi);
  end proc;
lprint("op 7 is the so-called lexical table:",[op(7,eval(g))]);
  res[1] := g();
  return res[1];
end proc:

Warning, (in f) `res` is implicitly declared local


Notice also that the lexical table contains the symbol x and
not the name x[1] .

f();

"op 7 is the so-called lexical table:", [x, x]

2

maplemint(f);

Procedure f()
  These local variables were used but never assigned a value:  x

proc() global G[1]; end proc:

Error, `[` unexpected

proc() global G; end proc:

proc() local L[1]; end proc:

Error, `[` unexpected

proc() local L; end proc:


Download proc_lcl_ex1.mw

And another note: names used as globals in the procedure, but which are not declared as global, are not "global variables" of the procedure, per se.

restart;

p := proc() global g1;
  g2;
end proc;

proc () global g1; g2 end proc

"op 6 is the globalSequence:",op(6,eval(p));

"op 6 is the globalSequence:", g1

maplemint(p);

Procedure p()
  These names were used as global names but were not declared:  g2
  These global variables were declared, but never used:  g1


Download proc_lcl_ex2.mw

@janhardo No, a local variable of a procedure may be used in a practical and useful manner even if it's never assigned any value.

Here's an example in which the local variable x gets (usefully) utilized as a symbolic name, even though it does not get assigned a value.

p := proc(F, t) local x,res;
  res := int(F(x), x=0..t);
  lprint("this is still not assigned any value:", eval(x));
  return res;
end proc:

 

p(sin, s);

"this is still not assigned any value:", x

1-cos(s)

maplemint(p);

Procedure p( F, t )
  These local variables were used but never assigned a value:  x

Download proc_lcl_ex0.mw

That message from maplemint clearly indicates both that x is a local variable and that x is not getting assigned.

It follows from that, logically and directly, that being assigned is not a condition for being a local variable.

That maplemint message directly and completely contradicts janhardo's claim -- as does the runtime behavior of the example above.

janhardo's statement, "A name is  a variable when there is a valued assigned to it" is not true, and it does not convey important aspects of the question.

A variable of a procedure (whether local, global, lexical, etc) has that nature regardless of whether it has been or ever gets assigned a value.

@JoyDivisionMan It also produces the value zero 0 if assuming t<=0.

It would be nice if int(..., allsolutions) were able to handle this example directly.

So (while using supports of RVs might be one way, especially in this simple arithmetic combination), one can also split at the problematic value t=0.

But t::real can be handled as well, (if stepping in to deal with t=0), eg.

with(Statistics)

x := RandomVariable(Uniform(1, 2))

y := RandomVariable(Uniform(2, 3))

 

combine(piecewise(t <= 0, `assuming`([PDF(x*y, t)], [t <= 0]), t >= 0, `assuming`([PDF(x*y, t)], [t >= 0])))

piecewise(t <= 2, 0, t <= 3, ln((1/2)*t), t <= 4, ln(3/2), t <= 6, -ln((1/6)*t), 6 < t, 0)

Download MultiplyPDFFunctions_acc.mw

ps. I don't see why this might be considered any more ad hoc than using conversion via ln (which doesn't alone work for all examples...). Problematic t-values might possibly be found programmatically, though as mentioned it'd be nice if int handled it directly via allsolutions.

Sometimes I prefer workarounds like applying ln (since it's terse and easy to try), and sometimes I prefer ones which (I suspect) might give me additional insight into how things might get improved directly/automatically.

@RafalAblamowicz 

Do the commands use limit, or int, or solve? If so then they may well be not thread-safe, since those Library commands are not.

The list of Maple commands which are documented as thread-safe is not huge (relative to the total number of commands).  Many of those which are are very low-level, and quite a few are kernel builtins as opposed to higher level Library commands.

I don't know of a general tool for determining whether a procedure does or calls anything which in is thread-unsafe. Having a global effect, or calling a thread-unsafe command, is a typical way to be itself thread-unsafe. And there are quite a few ways that can occur. You could try ThreadSafetyCheck from the CodeTools package, but I don't its full strength. I suspect I might be much more inclined to trust it flagging unsafety than safety.

There is option lock which can be put on a procedure. But if you put that on all your procedures then benefits of multi-threading can easily vanish, as it could prevent most or all parallel execution. There is also,
    ?multithreaded,threadlocaldata
as a Help topic, if you have a module whose procedures write to any module locals when run.

There are lots of weird ways for a procedure to be thread-unsafe. The sort command itself may be thread-safe, but its effects on reordering terms in an expression may not be.

An parallelization alternative to Threads is (sometimes) the Grid package. The latter dispatches individual computations to separate spawned Maple engines/kernels, and communication between child&parent kernels is explicitly controlled. But it can be less versatile.

On what basis do you believe that the procedures in your package are thread-safe?

@Carl Love That is nice and crisp.

notes: I believe that it requires Maple 2019 or later, which of course is no problem as the OP is using Maple 2025.

The example relates to an earlier question the OP has about contour plotting. It's doubtful that the OP's table has very many more entries than one might usually have as separate contour values. So I doubt that the efficiency difference for such a modest number of indices makes for a significant efficiency concern.

If you're interested, you can also do it in a loop.

The seq way is nice because it's a 1-liner. It extracts all the indices and then re-references (separately) back into the table to get each associated value. The loop way allows you to extract each index alongside its associated value.

restart;

T := table([ (a,b)=S1, (c,d)=S2, (e,f)=S3, (g,h)=S4 ]):

 

# first way
new1 := table([map(tt->tt[1]=T[tt[]],[indices(T)])[]]):

 

# second way
new2 := table():
for ind,val in eval(T) do
  new2[ind[1]] := val;
end do:

 

eval(T);

table( [( a, b ) = S1, ( g, h ) = S4, ( e, f ) = S3, ( c, d ) = S2 ] )

eval(new1);

table( [( g ) = S4, ( c ) = S2, ( e ) = S3, ( a ) = S1 ] )

eval(new2);

table( [( g ) = S4, ( c ) = S2, ( e ) = S3, ( a ) = S1 ] )


Download nm_table_q2.mw

@nm That is an interesting weakness in plots:-contourplot and in plots:-implicitplot, that it may fail to show the contour for value 0 for your latest followup expression ln(y^2 + 1), if the y-range is y=-1..1 instead of, say, y=0..1.

Please see the attachment, which is revised to better handle empty data. (My Answer's code inherited weakness in this regard Carl's revision of Kitonum's original.)

CPL05.mw

ps. The code in my Answer has been updated again, with this. I find from experience that it's less confusing for readers (down the road, or years from now) if they don't have to read all the Replies and deduce which contains the "latest".

5 6 7 8 9 10 11 Last Page 7 of 607