Carl Love

Carl Love

28015 Reputation

25 Badges

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

MaplePrimes Activity


These are answers submitted by Carl Love

The basic technique for creating dynamic nested loops is to apply the foldl (fold-left) command to seq or one of its companion looping commands such as add. This is what @sursumCorda did. As he showed, making the loops dynamic by folding doesn't make them any faster, nor should you expect it to. But I did find 2 major ways to make the code faster, speeding up yours and @sursumCorda 's by a factor of at least 40 (i.e., 40 times faster).

The first improvement was to eliminate your innermost loop. That loop is simply counting (by repeatedly adding 1) a sequence of consecutive integers. If you know the integer bounds, the count can be done by simple subtraction of those bounds, plus 1. That's the significance of this expression, which is the innermost addend in my add loops:

max(0, min(_v||n1 + 1, V[-1]) - Ceil(V[-1]/2))

The second improvement is due to a Maple idiosyncracy: The command trunc is many times faster than ceil (or floor or the other commands of that ilk). By making a slight adjustment to trunc, it can replace ceil:

ceil(x) = trunc(x) + `if`(trunc(x)=x or x < 0, 0, 1)

With these changes, my final code is able to do the n=6 case in under 9 seconds.

nequaln:= (n::And(posint, Not(1)))->
local 
    i, %add, n1:= n-1, 
    V:= (n-2)*24 -~ (0, seq['scan'= `+`](_v||i, i= 2..n1)), #seq of partial sums

    #Maple's library 'ceil' has a highly symbolic aspect that slows it significantly. (You
    #can confirm this by showstat(ceil).) But 'trunc' is kernel builtin and doesn't have
    #this problem. Thus, I wrote this version of 'ceil' that only uses 'trunc'.
    Ceil:= x-> local T:= trunc(x);  
        `if`(T::integer, (thisproc(x):= T + `if`(T=x or x<0, 0, 1)), 'procname'(x))
;
    (eval@subs)(
        _v||1= V[1] - n1, %add= add,
        foldl(
            %add,
            max(0, min(_v||n1 + 1, V[-1]) - Ceil(V[-1]/2)),
            seq(_v||i= Ceil(V[i-1]/(n-i+2)).._v||(i-1), i= n1..2, -1)
        )        
    )           
:
[seq](CodeTools:-Usage(nequaln(k)), k= 2..6);
memory used=14.30KiB, alloc change=0 bytes,       #Usage for k=2
cpu time=0ns, real time=2.00ms, gc time=0ns

memory used=285.20KiB, alloc change=0 bytes,      #Usage for k=3
cpu time=15.00ms, real time=14.00ms, gc time=0ns

memory used=475.34KiB, alloc change=0 bytes,      #Usage for k=4
cpu time=0ns, real time=9.00ms, gc time=0ns

memory used=13.45MiB, alloc change=0 bytes,       #Usage for k=5
cpu time=79.00ms, real time=80.00ms, gc time=0ns

memory used=1.58GiB, alloc change=0 bytes,        #Usage for k=6
cpu time=8.58s, real time=8.35s, gc time=437.50ms

                  [0, 48, 816, 10642, 117788]

 

You're trying to use a variable named delta[h]_range. That's not allowed as an unquoted  variable name. But, if you wish, you can use back-quotes (aka left-quotes) to make anything at all a variable name:

`delta[h]_range`:= 0.55 .. 0.75;

Click anywhere in the output field--no need to highlight it--and press Ctrl-Delete.

It can be done like this:

period:= 6:  x:= 78:
d:= period /~ NumberTheory:-PrimeFactors(period):
select(
    b-> igcd(x,b)=1 and b&^period mod x = 1 and andseq(b&^i mod x <> 1, i= d),
    [$2..x-1]        
);
                    [17, 23, 29, 35, 43, 49]

The asymptotic time complexity with respect to period can be further reduced by using some kind of "factor tree" to compute the powers b &^ i mod x, where i runs over the proper divisors of period. There's no benefit to this if the period is square-free, as is 6

Edit: The idea mentioned in the previous paragraph is now implemented by the new 2nd line above:

d:= period /~ NumberTheory:-PrimeFactors(period);

You can put the evaluation of the Newton iteration in a try-catch statement to trap both singularities of f and points where its derivative is 0. 

NM2:= proc(
    f, xold::complexcons, {precision::positive:= 10.^(1-Digits), max_iters::posint:= 9}
)
local x0:= xold, x1:= x0+2*precision, Df:= D(f), k;
    for k to max_iters do
        try 
            (x0,x1):= (x1, evalf(x1 - f(x1)/Df(x1)))
        catch:
            error "Singularity at %1", x1
        end try;
        userinfo(1, procname, 'NoName', x1)
    until abs(x0-x1) < precision; 
    if k > max_iters then error "Maximum iterations exceeded" fi;
    x1 
end proc
:
p:= randpoly(x, degree= 9, dense);
            9       8       7       6       5       4       3
   p := 72 x  + 37 x  - 23 x  + 87 x  + 44 x  + 29 x  + 98 x 

            2            
      - 23 x  + 10 x - 61

f:= unapply(p, x):
infolevel[NM2]:= 1:
r:= NM2(f, 1.3);
1.121934407
.9609516325
.8274608051
.7423627912
.7136509949
.7110238945
.7110039767
.7110039755
.7110039755
                       r := 0.7110039755
f(r);
                               0.
r:= NM2(f, 1.+I);
.9145078329+.9127717630*I
.8599212591+.8460365442*I
.8403634004+.8059364156*I
.8411389647+.7949972141*I
.8416536274+.7947359908*I
.8416536540+.7947375421*I
.8416536539+.7947375422*I
               r := 0.8416536539 + 0.7947375422 I
f(r);
                                    -7  
                        0. + 1.42 10   I

 

I think that the following is what you have in mind, although it's not quite correct to say that it's the surface common to the two cylinders. Rather, it's the portion of each cylinder that's inside the other.

plots:-display(
    plot3d(  # y^2 + z^2 = 1:
        [[r, t, sqrt(1-r^2*sin(t)^2)], [r, t, -sqrt(1-r^2*sin(t)^2)]],
        r= 0..1, t= -Pi..Pi, coords= cylindrical
    ),
    plot3d(  # x^2 + y^2 = 1:
        [1, t, z], 
        t= -Pi..Pi, z= -sqrt(1-sin(t)^2)..sqrt(1-sin(t)^2), coords= cylindrical
    ),  
    scaling= constrained, labels= [x,y,z]
);

You seem to be having trouble distinguishing a procedure's input from its output. You want a procedure whose input is the integer dimensions of the matrix and whose output is the matrix itself. 

Matrix01:= proc(m::nonnegint, n::nonnegint:= m)
    Matrix((m,n), (i,j)-> modp(i+j, 2)) 
end proc
:
#Examples:
Matrix01(4);
Matrix01(3,5);

 

A fundamental motivation of the discipline of Combinatorics is that counting combinatorial structures can often be done using far less computational effort than generating the structures. Counting partitions is like that.

It can be done quite efficiently with a very short recursive procedure:

restart:
CountSums:= (k::posint, N::set(posint))->
    ((k,n)-> (thisproc(args):= 
        `if`(k*n > 0, thisproc(k, n-1) + thisproc(k-N[n], n), `if`(k=0, 1, 0))
    ))(k, nops(N))
:  
CodeTools:-Usage(CountSums(1000, {2,3,6,9}));
memory used=421.16KiB, alloc change=0 bytes,
cpu time=15.00ms, real time=7.00ms, gc time=0ns

                             526848
CountSums(9, {2,3,6,9});
                               4
CountSums(8, {2,3,6,9});
                               3
#Verify correctness:
CodeTools:-Usage(combinat:-numbpart(100));
memory used=2.14MiB, alloc change=0 bytes,
cpu time=31.00ms, real time=33.00ms, gc time=0ns

                           190569292

CodeTools:-Usage(CountSums(100, {$100}));
memory used=1.18MiB, alloc change=0 bytes, 
cpu time=16.00ms, real time=13.00ms, gc time=0ns

                           190569292

So, for this example, my procedure's time beats the library procedure combinat:-numbpart.

@Pepini You wrote:

  • I thought about use parametrization of torus:
    plot3d([(R + r*cos(t)*cos(s), (R + r*cos(t)*sin(s), r*sin(t)], t = 0 .. 2*Pi, s = 0 .. 2*Pi)

You are missing some parentheses in that parametrization: The R also needs to be multiplied by the cos(s) or sin(s). That omission may be why your plot wasn't satisfactory as a surface of revolution. Here's a correction:

r:=  t-> 1 + sin(8 + sin(16 + sin(32*t)))/4:  #This works for any polar curve in form r = f(t)
R:= 2:
plot3d(
     [(R + (r*cos)(t))*~(cos,sin)(s), (r*sin)(t)], t= -Pi..Pi, s= -Pi..Pi,
     scaling= constrained,  
#usually a better option than using 'view'
     grid= [101,49]   #Increase points used for t to show wrinkling
);

This is a figure homeomorphic to an ordinary torus, not the "flat torus" that @sand15 gave links to a PDF about and you showed a picture of. And it has only one level and direction of what those authors call "corrugation" (you might call it "wrinkling"). I think that 2 directions would be the minimum for a reasonable plot, but 1 direction is the most that can be accommodated by a surface of revolution. 

Here's a Matrix with all the information you need. You could display it more elegantly with DocumentTools, I suppose.

restart:

interface(rtablesize= [37,11]):

<
    <x, seq(nprintf("%4.2f", j/100), j= 0..9)>^%T,
    <
        <seq(nprintf("%3.1f", i/10), i= 0..35)> |
        Matrix((36,10), (i,j)-> evalf[4]((1+erf((10*i+j-11)/100/sqrt(2)))/2))
    >
>;

Matrix(37, 11, {(1, 1) = x, (1, 2) = `0.00`, (1, 3) = `0.01`, (1, 4) = `0.02`, (1, 5) = `0.03`, (1, 6) = `0.04`, (1, 7) = `0.05`, (1, 8) = `0.06`, (1, 9) = `0.07`, (1, 10) = `0.08`, (1, 11) = `0.09`, (2, 1) = `0.0`, (2, 2) = .5000, (2, 3) = .5040, (2, 4) = .5080, (2, 5) = .5120, (2, 6) = .5160, (2, 7) = .5199, (2, 8) = .5239, (2, 9) = .5279, (2, 10) = .5319, (2, 11) = .5358, (3, 1) = `0.1`, (3, 2) = .5398, (3, 3) = .5438, (3, 4) = .5478, (3, 5) = .5517, (3, 6) = .5556, (3, 7) = .5596, (3, 8) = .5636, (3, 9) = .5675, (3, 10) = .5714, (3, 11) = .5753, (4, 1) = `0.2`, (4, 2) = .5792, (4, 3) = .5832, (4, 4) = .5870, (4, 5) = .5910, (4, 6) = .5948, (4, 7) = .5987, (4, 8) = .6026, (4, 9) = .6064, (4, 10) = .6102, (4, 11) = .6140, (5, 1) = `0.3`, (5, 2) = .6179, (5, 3) = .6217, (5, 4) = .6255, (5, 5) = .6293, (5, 6) = .6330, (5, 7) = .6368, (5, 8) = .6406, (5, 9) = .6443, (5, 10) = .6480, (5, 11) = .6517, (6, 1) = `0.4`, (6, 2) = .6554, (6, 3) = .6591, (6, 4) = .6627, (6, 5) = .6664, (6, 6) = .6700, (6, 7) = .6736, (6, 8) = .6772, (6, 9) = .6808, (6, 10) = .6844, (6, 11) = .6879, (7, 1) = `0.5`, (7, 2) = .6914, (7, 3) = .6950, (7, 4) = .6984, (7, 5) = .7019, (7, 6) = .7054, (7, 7) = .7088, (7, 8) = .7122, (7, 9) = .7156, (7, 10) = .7190, (7, 11) = .7224, (8, 1) = `0.6`, (8, 2) = .7257, (8, 3) = .7290, (8, 4) = .7323, (8, 5) = .7356, (8, 6) = .7389, (8, 7) = .7422, (8, 8) = .7454, (8, 9) = .7486, (8, 10) = .7518, (8, 11) = .7548, (9, 1) = `0.7`, (9, 2) = .7580, (9, 3) = .7612, (9, 4) = .7642, (9, 5) = .7672, (9, 6) = .7703, (9, 7) = .7733, (9, 8) = .7764, (9, 9) = .7793, (9, 10) = .7823, (9, 11) = .7852, (10, 1) = `0.8`, (10, 2) = .7881, (10, 3) = .7910, (10, 4) = .7938, (10, 5) = .7967, (10, 6) = .7995, (10, 7) = .8023, (10, 8) = .8050, (10, 9) = .8078, (10, 10) = .8106, (10, 11) = .8132, (11, 1) = `0.9`, (11, 2) = .8159, (11, 3) = .8186, (11, 4) = .8212, (11, 5) = .8238, (11, 6) = .8264, (11, 7) = .8289, (11, 8) = .8314, (11, 9) = .8340, (11, 10) = .8364, (11, 11) = .8388, (12, 1) = `1.0`, (12, 2) = .8413, (12, 3) = .8438, (12, 4) = .8461, (12, 5) = .8484, (12, 6) = .8508, (12, 7) = .8531, (12, 8) = .8554, (12, 9) = .8576, (12, 10) = .8599, (12, 11) = .8621, (13, 1) = `1.1`, (13, 2) = .8643, (13, 3) = .8664, (13, 4) = .8686, (13, 5) = .8707, (13, 6) = .8728, (13, 7) = .8749, (13, 8) = .8770, (13, 9) = .8790, (13, 10) = .8810, (13, 11) = .8830, (14, 1) = `1.2`, (14, 2) = .8849, (14, 3) = .8868, (14, 4) = .8887, (14, 5) = .8906, (14, 6) = .8925, (14, 7) = .8944, (14, 8) = .8962, (14, 9) = .8980, (14, 10) = .8997, (14, 11) = .9014, (15, 1) = `1.3`, (15, 2) = .9032, (15, 3) = .9049, (15, 4) = .9066, (15, 5) = .9082, (15, 6) = .9098, (15, 7) = .9114, (15, 8) = .9130, (15, 9) = .9146, (15, 10) = .9162, (15, 11) = .9177, (16, 1) = `1.4`, (16, 2) = .9192, (16, 3) = .9207, (16, 4) = .9222, (16, 5) = .9236, (16, 6) = .9250, (16, 7) = .9264, (16, 8) = .9278, (16, 9) = .9292, (16, 10) = .9304, (16, 11) = .9318, (17, 1) = `1.5`, (17, 2) = .9330, (17, 3) = .9346, (17, 4) = .9358, (17, 5) = .9370, (17, 6) = .9382, (17, 7) = .9394, (17, 8) = .9406, (17, 9) = .9418, (17, 10) = .9429, (17, 11) = .9440, (18, 1) = `1.6`, (18, 2) = .9452, (18, 3) = .9462, (18, 4) = .9473, (18, 5) = .9484, (18, 6) = .9494, (18, 7) = .9506, (18, 8) = .9516, (18, 9) = .9526, (18, 10) = .9536, (18, 11) = .9545, (19, 1) = `1.7`, (19, 2) = .9554, (19, 3) = .9564, (19, 4) = .9572, (19, 5) = .9582, (19, 6) = .9590, (19, 7) = .9599, (19, 8) = .9608, (19, 9) = .9616, (19, 10) = .9624, (19, 11) = .9633, (20, 1) = `1.8`, (20, 2) = .9641, (20, 3) = .9648, (20, 4) = .9656, (20, 5) = .9664, (20, 6) = .9671, (20, 7) = .9678, (20, 8) = .9686, (20, 9) = .9692, (20, 10) = .9699, (20, 11) = .9706, (21, 1) = `1.9`, (21, 2) = .9712, (21, 3) = .9719, (21, 4) = .9725, (21, 5) = .9732, (21, 6) = .9738, (21, 7) = .9744, (21, 8) = .9750, (21, 9) = .9756, (21, 10) = .9762, (21, 11) = .9767, (22, 1) = `2.0`, (22, 2) = .9772, (22, 3) = .9778, (22, 4) = .9783, (22, 5) = .9788, (22, 6) = .9793, (22, 7) = .9798, (22, 8) = .9802, (22, 9) = .9808, (22, 10) = .9812, (22, 11) = .9817, (23, 1) = `2.1`, (23, 2) = .9822, (23, 3) = .9826, (23, 4) = .9830, (23, 5) = .9834, (23, 6) = .9838, (23, 7) = .9842, (23, 8) = .9846, (23, 9) = .9850, (23, 10) = .9854, (23, 11) = .9857, (24, 1) = `2.2`, (24, 2) = .9860, (24, 3) = .9864, (24, 4) = .9868, (24, 5) = .9872, (24, 6) = .9874, (24, 7) = .9878, (24, 8) = .9881, (24, 9) = .9884, (24, 10) = .9887, (24, 11) = .9890, (25, 1) = `2.3`, (25, 2) = .9892, (25, 3) = .9896, (25, 4) = .9898, (25, 5) = .9901, (25, 6) = .9904, (25, 7) = .9906, (25, 8) = .9908, (25, 9) = .9911, (25, 10) = .9914, (25, 11) = .9916, (26, 1) = `2.4`, (26, 2) = .9918, (26, 3) = .9920, (26, 4) = .9922, (26, 5) = .9924, (26, 6) = .9926, (26, 7) = .9928, (26, 8) = .9930, (26, 9) = .9932, (26, 10) = .9934, (26, 11) = .9936, (27, 1) = `2.5`, (27, 2) = .9938, (27, 3) = .9940, (27, 4) = .9942, (27, 5) = .9943, (27, 6) = .9944, (27, 7) = .9946, (27, 8) = .9948, (27, 9) = .9949, (27, 10) = .9950, (27, 11) = .9952, (28, 1) = `2.6`, (28, 2) = .9954, (28, 3) = .9954, (28, 4) = .9956, (28, 5) = .9957, (28, 6) = .9958, (28, 7) = .9960, (28, 8) = .9961, (28, 9) = .9962, (28, 10) = .9963, (28, 11) = .9964, (29, 1) = `2.7`, (29, 2) = .9966, (29, 3) = .9966, (29, 4) = .9968, (29, 5) = .9968, (29, 6) = .9969, (29, 7) = .9970, (29, 8) = .9971, (29, 9) = .9972, (29, 10) = .9972, (29, 11) = .9974, (30, 1) = `2.8`, (30, 2) = .9974, (30, 3) = .9975, (30, 4) = .9976, (30, 5) = .9976, (30, 6) = .9978, (30, 7) = .9978, (30, 8) = .9979, (30, 9) = .9980, (30, 10) = .9980, (30, 11) = .9980, (31, 1) = `2.9`, (31, 2) = .9982, (31, 3) = .9982, (31, 4) = .9982, (31, 5) = .9983, (31, 6) = .9984, (31, 7) = .9984, (31, 8) = .9984, (31, 9) = .9985, (31, 10) = .9986, (31, 11) = .9986, (32, 1) = `3.0`, (32, 2) = .9986, (32, 3) = .9987, (32, 4) = .9988, (32, 5) = .9988, (32, 6) = .9988, (32, 7) = .9988, (32, 8) = .9989, (32, 9) = .9990, (32, 10) = .9990, (32, 11) = .9990, (33, 1) = `3.1`, (33, 2) = .9990, (33, 3) = .9990, (33, 4) = .9991, (33, 5) = .9991, (33, 6) = .9992, (33, 7) = .9992, (33, 8) = .9992, (33, 9) = .9992, (33, 10) = .9992, (33, 11) = .9993, (34, 1) = `3.2`, (34, 2) = .9993, (34, 3) = .9994, (34, 4) = .9994, (34, 5) = .9994, (34, 6) = .9994, (34, 7) = .9994, (34, 8) = .9994, (34, 9) = .9994, (34, 10) = .9995, (34, 11) = .9995, (35, 1) = `3.3`, (35, 2) = .9995, (35, 3) = .9996, (35, 4) = .9996, (35, 5) = .9996, (35, 6) = .9996, (35, 7) = .9996, (35, 8) = .9996, (35, 9) = .9996, (35, 10) = .9996, (35, 11) = .9996, (36, 1) = `3.4`, (36, 2) = .9996, (36, 3) = .9996, (36, 4) = .9997, (36, 5) = .9997, (36, 6) = .9997, (36, 7) = .9997, (36, 8) = .9998, (36, 9) = .9998, (36, 10) = .9998, (36, 11) = .9998, (37, 1) = `3.5`, (37, 2) = .9998, (37, 3) = .9998, (37, 4) = .9998, (37, 5) = .9998, (37, 6) = .9998, (37, 7) = .9998, (37, 8) = .9998, (37, 9) = .9998, (37, 10) = .9998, (37, 11) = .9998})

 

Download NormalTable.mw

Perhaps you will understand better if things are made more explicit rather than using the geometry package. MaplePrimes won't let me display this worksheet inline at the moment, but you can download it...

Download Ellipse.mw

...or just copy and paste this code into a Maple session:

Dist:= (P,Q)-> sqrt(add((P-Q)^~2)):  #Euclidean distance between points P and Q
Mid:= (P,Q)->  (P+Q)/2:              #Midpoint between P and Q

P:= <x,y>:                       #An arbitrary symbolic point on the ellipse
F:= [<0,-5>, <5, 0>]:  MA:= 12:  #Foci and major-axis length

(* An ellipse's defining property: The sum of the distances from any of its
points to its foci is constant. I'll call that constant C for the moment. 
We'll use that other piece of given information, the length of the major axis,
to figure out C in a moment. *)

Ell_eqn:= C = add(map(Dist, F, P));

# Perhaps you'll accept without further explanation that the line through 
# the foci (which is collinear with the major axis) is
MA_line:= y = x - 5;

(* The next step to getting C is finding numerically any point on the ellipse. 
Two such points are the points on that line that are at distance MA/2 from the
midpoint of the foci. We solve for them: *)

%solve({MA_line, Dist(P, Mid(F[])) = MA/2}, explicit);
sols:= value(%); 

# As suspected, there are 2 solutions. We only need 1, and I arbitrarily choose
# the first. To find C, we just use those x and y in the ellipse's equation:

eval(Ell_eqn, sols[1]);
eval(Ell_eqn, %):  #Put that in for C

# Subtract one side of the equation from the other to make an expression 
# implicitly equated to 0:

(lhs-rhs)(%);    
evala(Norm(%));      #Convert that to a polynomial
(primpart/sign)(%);  #Cancel common integer factors of the coefficients
#Final:
             119*x^2 - 50*x*y + 119*y^2 - 720*x + 720*y - 1584 

Your expression involves extreme underflows and overflows that can't be handled by the default hardware floats. So, the easy correction is

UseHardwareFloats:= false: 

An alternative is to simplify the expression to

f2:= exp(5002.646494 + 2499*ln(t) - 5000.*sqrt(t));

Then hardware floats can be used by plot.

My preferred syntax for situations like this is decisions[`if`(1 > T, 1, 2)].

I told you before that you need to change Gamma to GAMMA. You said that you did, but I still see Gamma.

Try entering it as A[b,c]. This makes it an indexed variable. The output will be subscripted like you want. An indexed variable is not quite the same thing as the atomic variable that you were trying to create, but it'll work if you do not assign values to Ab, or c.

The characters that you see are not apostrophes. Note that they lean to the left. They're called "back quotes" or "accents graves" or, in Maple, "name quotes". They let you make any string of characters, no matter how weird, into a variable.

However, you shouldn't be seeing those back quotes in your output. If I enter 

`A__b,c`;

then my output appears without quotes as Ab,c

First 22 23 24 25 26 27 28 Last Page 24 of 394