Carl Love

Carl Love

27778 Reputation

25 Badges

12 years, 190 days
Himself
Wayland, Massachusetts, United States
My name was formerly Carl Devore.

MaplePrimes Activity


These are answers submitted by Carl Love

You asked:

  • Also, is there a way to disable the use of remember tables permanently in Maple?

[Disclaimer: I don't claim that you'll achieve any benefit from using the code below. Rather, I provide this code so that you can easily, safely, and reversibly explore the possibility that you asked for above.]

I think that I have below something better than what you asked for. You can permanently, yet reversibly, remove options remember and cache from all Library procedures that have them. This will prevent the accumulation of new data in remember or cache tables when that accumulation is caused by the option remember or option cache mechanism. It doesn't affect direct assignments to the tables as in

f(3):= 7;

where f is a procedure. It affects only Library procedures; it doesn't prevent you from using the options in your own code. It doesn't remove the default initial remember or cache tables which commands have stored in the Library (which would be a very bad thing to do!). The only cost of using this procedure is a one-time use of 30 seconds of time, and permanent storage of 1.6M of files to hold the modified procedures. Once that's done, the new procedures are used by doing restart and updating libname. To return to the original procedures, just use restart.

Permanent, yet reversible, removal of options remember and cache from the Maple library

 Author: Carl Love <carl.j.love@gmail.com> 2025-Apr-1

 

Disclaimers:

1. 

I don't advocate such removal. Rather, my goal here is to show how it can be safely and quickly done in a way that is very easy reversible, thus making this safe and easy for those who want to explore it.

2. 

We remove those options from the Library procedures that have them by default. This is not the same thing as removing any existing remember tables or caches. And these latter things I definitely wouldn't recommend anyway.

3. 

If a command creates a procedure on the fly that has those options, this process will not prevent that; nor do I think that there would be any benefit to doing that.

 

restart
:

#So that we can verify later that this works, here's a Library procedure
#with option remember:
op(3, eval(`simplify/do`));

remember, system, `Copyright (c) 2000 Waterloo Maple Inc. All rights reserved.`

The command LibraryTools:-ShowContents() returns a list or lists. Each member list contains info about 1 name stored in the Library. The first field in each entry is a string form of the name with ".m" appended. The other fields aren't used here. So, for example, if the Library contained only `simplify/do`, then the list of lists might look like

L:= [["simplify/do.m", "other stuff"]]:

So the list of names can be extracted like this:

P:= [seq](cat(``, P[1][..-3]), P= L);

[`simplify/do`]

Any procedure has a 3rd operand that stores the expression sequence of its options, even if that sequence is NULL.

opts:= [op](3, eval(P[]));

[remember, system, `Copyright (c) 2000 Waterloo Maple Inc. All rights reserved.`]

The option is removed by substituting NULL for it:

assign(P[] = subsop(3= subs(remember= (), opts)[], eval(P[]))):

Check that the procedure now has different options:

 

system, `Copyright (c) 2000 Waterloo Maple Inc. All rights reserved.`

restart
:

Now I put these ideas together into a procedure that does the above for the whole Library:

(*
This procedure finds the procedures in the Library that have option remember
or cache and removes those options. The modified procedures are stored in a
new library in the file directory specified by the parameter LD.

Note that removing these options is not the same thing as removing the
remember table or cache.
*)
RemoveAllRemOpts:= proc(LD::string)
uses LT= LibraryTools;
local
    P, p, Opts:= proc(P) option inline; [op](3, eval(P)) end proc,
    SO:= {'remember', 'cache'}=~ (),
    HO:= {identical(lhs~(SO)[]), specfunc('cache')},
    L:= select(
        n-> n::procedure and membertype(HO, Opts(n)),                
        [seq](cat(``, P[1][..-3]), P= LT:-ShowContents())
    )
;
    LT:-Create(LD, nops(L));
    for P in L do

        if (p:= P::protected) then unprotect(P) fi;
        assign(P= subsop(3= subs[eval](SO, Opts(P))[], eval(P)));
        if p then protect(P) fi;
        savelib(P, LD)
    od;
    return
end proc
:

#An empty directory to store the library:
LibDir:= "C:/Users/carlj/OneDrive/Desktop/MaplePackages/NoRem":
save LibDir, "LibDir.mpl":

CodeTools:-Usage(RemoveAllRemOpts(LibDir));
#All these warnings can be ignored. Indeed, they all refer to names that aren't
#used here anyway because they aren't procedures.
#
#This procedure only takes 30 seconds for me.

Warning, the GPIOTools package is only supported on the Raspberry Pi platform

Warning, grobner is deprecated. Please, use Groebner.

Warning, (in anonymous procedure created in Opts) environment variable `_EnvMaxSplit` declared as a global variable

Warning, (in anonymous procedure created in Opts) environment variable `_EnvIsSqrfree` declared as a global variable

Warning, (in anonymous procedure created in Opts) environment variable `_EnvIsSqrfree` declared as a global variable

Warning, (in anonymous procedure created in Opts) environment variable `_EnvMaxSplit` declared as a global variable

Warning, (in anonymous procedure created in Opts) environment variable `_EnvCharacteristic` declared as a global variable

Warning, (in anonymous procedure created in Opts) environment variable `_EnvP` declared as a global variable

Warning, (in anonymous procedure created in Opts) environment variable `_EnvIsSqrfree` declared as a global variable

Warning, (in anonymous procedure created in Opts) environment variable `_EnvIsSqrfree` declared as a global variable

Warning, (in anonymous procedure created in Opts) environment variable `_EnvD` declared as a global variable

Warning, (in anonymous procedure created in Opts) environment variable `_EnvC` declared as a global variable

memory used=3.09GiB, alloc change=210.01MiB, cpu time=11.98s, real time=30.28s, gc time=609.38ms

Test it

Note that the testing is after a restart.

restart:

read "LibDir.mpl":

The new procedures are used by prepending the new directory name to libname:

libname:= LibDir, libname;

"C:/Users/carlj/OneDrive/Desktop/MaplePackages/NoRem", "C:\Program Files\Maple 2023\lib", "C:\Users\carlj\maple\toolbox\Syrup\lib"

#Check that a procedure that used to have option remember no longer does:
op(3, eval(`simplify/do`));

system, `Copyright (c) 2000 Waterloo Maple Inc. All rights reserved.`

To go back to the original Maple procedures, all that's needed is restart:

restart:

op(3, eval(`simplify/do`));

remember, system, `Copyright (c) 2000 Waterloo Maple Inc. All rights reserved.`

NULL

Download RemoveRemOpts.mw

Yes, in almost all cases worksheets created with a newer version of Maple can be opened and edited and resaved with a version several years old. That part is usually still true even if the worksheet has new features. New programmatic features will not execute correctly and new GUI features will not display correctly, but that usually has no impact on reading, editing, and saving.

The Options dialog is in a weird place now: the bottom right corner of the File menu. Being on the right side of a menu is very weird. And why was it moved from the Tools menu? Tools seemed appropriate, but Options is certainly not a File operation.

I fretted for a long time during the beta testing over not being able to find the Options dialog, but I stumbled upon it last night.

I finally found a help page saying that Options was now on the File menu (without specifying the weird exact location). That page is
?worksheet,managing,preferences. Since that's the16th hit for ?options, it's not very helpful. If I capitalize it (?Options), then the relevant help becomes the 21st entry.

Your system has 2 variables,1 equation, and several inequalities, the number of which is irrelevant. Thus, you can only solve for 1 variable. It could be x or y, but you need to specify which. This will get you the solution (without removing the warning):

solve(Sol union area, {y})

If for some strange reason you actually want a solution containing RootOf, change {y} to {x}.

I believe that the warning comes because of your index= real[2]. The solver is able (at least in this case) to convert the RootOf equation to a polynomial before passing it to SemiAlgebraic, but I guess that it's unable to generate the appropriate inequality constraint that's implied by index= real[2]. Since you mean (I assume) the positive square root of y, that constraint is x >= 1. So, if you replace 

x = RootOf(_Z^2 - y, index= real[2]) + 1

with this equivalent

x = RootOf(_Z^2 - y) + 1, x >= 1

then the warning goes away.

There's no need to go through your entire code to modify all occurences of any command procedure (such as simplify). All you need to do is write a simple wrapper for simplify and name it simplify:

restart:
`simplify/orig`:= eval(simplify):
protect(`simplify/orig`):
unprotect(simplify):
simplify:= proc()
local r:= `simplify/orig`(args);
    forget(simplify, 'forgetpermanent', 'subfunctions', 'reintialize');
    r
end proc:
protect(simplify):

That is the "clobbering" approach that acer mentioned. Here is a more-elegant way:

Simplify:= module()
option package;
export 
    simplify:= proc()  
    local r:= :-simplify(args);
        forget(:-simplify, 'forgetpermanent', 'subfunctions', 'reintialize');
        r
    end proc
;
end module:
with(Simplify);

However, that module-based way will not change fhe way that your existing code works.

Using printlevel is one of the crudest possible debugging tools. Why not just use trace on all procedures whose names begin "simplify", like this?:

`&<`:= curry: `&>`:= rcurry:
((trace @ cat&<`` @ index&>(..-3))~ @ select)(
    type, index~(LibraryTools:-ShowContents(), 1), suffixed("simplify")
);

Your example expression for simplify --- 3*x^3/x + sin(x^2)/4 --- is a bad example because x^3/x is converted to x^2 by automatic simplification which has nothing to do with the simplify command. Thus, the command only sees 3*x^2 + sin(x^2)/4, which is already fully simplified,

-a^2 is a PRODUCT%1 (its type is `*` ,with operands -1 and a^2). The identity for `*` is 1. So, if everything is removed from a PRODUCT, then what's left is 1.

Likewise, if all operands are removed from a SUM%1 (type `+`), then what's left is 0

a^2 is not a product (its type is `^`, with operands a and 2). There is no identity for `^`; it's not an associative operator and hence an identity element isn't needed. If everything is removed from a `^`, then what's left is NULL^NULL (or ()^()).

This is the same principal as the one pointed out in a more-theoretical way by sursumCorda.

Footnote %1: PRODUCT and SUM are 2 of the 63 fundamental types (sometimes called "dagtags") of all structures in the Maple kernel. They aren't related to the commands product or sum. In the user-level type system, they are the types `*` and `+`. They are related to (but not identical to) the operators `*` and `+`.

For nonnegative integer k,

sin(k*x)*cos(x)^k = Sum(binomial(k,j)*sin(2*j*x), j= 1..k)/2^k  (* Prop 1 *)

Since Int(sin(2*j*x)/x, x) = Si(2*j*x)Si(0) = 0Si(infinity) = Pi/2, and Sum(binomial(k,j), j= 1..k) = 2^k - 1,

Int(sin(k*x)*cos(x)^k/x, x= 0..infinity) = (Pi/2)*(2^k - 1)/2^k = Pi/2*(1 - 2^(-k))

Looking for the pattern in the following iteration makes the first proposition obvious to me, although that is not proof:

for k to 9 do combine(2^k*sin(k*x)*cos(x)^k) od

The closed interval containing the single point 1 can be entered as simply 1, or as RealRange(1,1), which automatically reduces to 1. Note that all intervals entered in 2D Input are re-expressed in RealRange form. You can see this with lprint, as in

lprint(correct_form);

It is that automatic conversion of RealRange(1,1) to 1 that causes the problem. When you construct the correct_form, use y=1 instead of y::1, because convert(..., relation) will not correctly convert y::1 (although it is valid Maple syntax). To solve, use

solve(Or(convert(correct_form, relation)[]));
or, if you insist on using the cluttery op,
solve(Or(op(convert(correct_form, relation))));
instead of your
solve(convert~(Or(op(correct_form)), relation));
(and note that the ~ does nothing in your command).

Here is an elementary proof:

Author: Carl Love <carl.j.love@gmail.com> 2025-Mar-6

restart:

We want to sum this series:

S:= Sum(arctan(2/n^2), n= 1..infinity);

Sum(arctan(2/n^2), n = 1 .. infinity)

I devised an elementary proof of this. Since I only spent a half hour on it, I wouldn't be surprised if it could be done more simply.

First, Here's a trig identity that's very easy to prove, but I'll state it without proof because Maple already knows it:

arctan(a) + arctan(b):
ATid:= % = combine(%) assuming abs(a*b) < 1;

arctan(a)+arctan(b) = arctan((a+b)/(-a*b+1))

This proposition, proved by induction, will allow us to sum separately the odd and even terms of the series. It's valid for n > 1.

P:= sum(arctan(2/(n+2*k)^2), k= 0..K) = arctan((K+1)/(K*(n-1) + n^2/2));  #where n > 1

sum(arctan(2/(n+2*k)^2), k = 0 .. K) = arctan((K+1)/(K*(n-1)+(1/2)*n^2))

The base case, K = 0: This is obviously true:

eval(P, K= 0);

arctan(2/n^2) = arctan(2/n^2)

Assuming that P is true for the sum of the first K-1 terms, we break off and add separately the Kth term:

IH:= eval(rhs(P), K= K-1) + eval(op(1, lhs(P)), k= K);

arctan(K/((K-1)*(n-1)+(1/2)*n^2))+arctan(2/(n+2*K)^2)

Apply the trig identity:

simplify(eval(rhs(ATid), [a= op(op(1,IH)), b= op(op(2,IH))]));

arctan((2*K+2)/((2*n-2)*K+n^2))

simplify(op(1,%) - op(rhs(P)));

0

Q.E.D.

 

Taking the limit of the partial sums,

SS:= eval(lhs(P), K= infinity) = limit(rhs(P), K= infinity);

sum(arctan(2/(n+2*k)^2), k = 0 .. infinity) = arctan(1/(n-1))

From the original sum, we consider separately n=1, the remaining terms for even n, and the remaining terms for odd n. We get

S = eval(op(1,S), n= 1) + eval(rhs(SS), n= 2) + eval(rhs(SS), n= 3);

Sum(arctan(2/n^2), n = 1 .. infinity) = arctan(2)+(1/4)*Pi+arctan(1/2)

simplify(%);

Sum(arctan(2/n^2), n = 1 .. infinity) = (3/4)*Pi

 

Download ArctanSum.mw

A sequence can be accumulated (as a sum or via any other function) very efficiently at the same time as it's created by using the scan option to seq:

y:= [seq['scan'= rand(1..6)]](1..10);
              y := [1, 5, 2, 5, 6, 2, 3, 4, 4, 6]

(L,H):= selectremove(`<=`, {y[]}, 3); 
                  L, H := {1, 2, 3}, {4, 5, 6}

y:= subs((L=~ -1) union (H=~ 1), y);
            y := [-1, 1, -1, 1, 1, -1, -1, 1, 1, 1]

y:= [seq['scan'= `+`]](y);
             y := [-1, 0, -1, 0, 1, 0, -1, 0, 1, 2]

#The plot can be done by
dataplot(y);

#The 1st 4 commands can be done by this single command:
y:= [seq['scan'= `+`]](seq['scan'= 2*rand(0..1) - 1](1..10));

The Maple expressions cos(x)=sqrt(1-sin(x)^2) or cos(x)=-sqrt(1-sin(x)^2) and x=0 or x<>0 automatically evaluate to false and true, respectively, before they are passed to is. The solution is to replace A or B with its inert form Or(A, B). See help page ?boolean.

To completely achieve the effect that you were hoping for from U:= U(x), you need to use alias as well as PDEtools:-declare:

restart;
alias(U=U(x)); PDEtools:-declare(U);

This will abbreviate U(x) to U for both input and output. Using declare without alias will not let you abbreviate your input.

If is an unassigned symbol, then A[B] is equivalent to A:-B. On the other hand, if is an export of A, and is also an assigned symbol outside of A, then A:-B must be used to disambiguate the Bs.

Like this:

foldl(gcd, lst1[]);

You could also use foldr. Since gcd is associative, it doesn't make any difference.

If is any set, and f is any binary operation on S, then the fold commands can be used to extend f to an arbitrary number of arguments.

After the loop, do

save f, "filename";

I don't know any way to append to a file with the save command.

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