Carl Love

Carl Love

26488 Reputation

25 Badges

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

MaplePrimes Activity


These are answers submitted by Carl Love

If the animation is produced with the Explore command, as shown below, the frames are displayed "on the fly" (i.e., as they are produced). So, unlike Maple's other animation commands, this has the benefit of starting play immediately. The memory used by the kernel for this is trivial, under 50 Mb; however, the memory used by the GUI grows unboundedly. I killed the below (just by pressing the stop button under the animation) when my GUI was using about 8 Gb. Still, it displayed a few thousand frames. (If you delete the Explore window after stopping it, those Gigs of memory will soon be garbage collected and returned to the O/S.)

The trick that I show in the code below---using ArrayTools:-Alias to create a direct memory link to the animation frame---can only work if the frames are displayed on the fly.

restart:
#
#Build unit sphere as static background for the animation. The back half is
#opaque, and the front half is wire mesh, so we can see inside.
#
Sphere:= plots:-display(
    plot3d~(
        1, [-Pi..0, 0..Pi], 0..Pi, coords= spherical, style=~ [patch, wireframe],
        lightmodel= light1, grid= [100$2], axes= normal, orientation= [60,80,10]
    )
):
N:= 5000: #number of points and animation frames
#Construct matrix each column of which is a random point on unit sphere:
Pts:= rtable(1..3, 1..N, frandom(-1..1), datatype= hfloat, subtype= Matrix):
Pts[3]:= csgn~(Pts[3])*~(1 -~ Pts[1]^~2 -~ Pts[2]^~2)^~(1/2):
Z:= Vector(3, 0, datatype= hfloat): #the origin
Frame:= plots:-display( #Construct one animation frame 
    Sphere, plots:-pointplot3d(<Z | Pts[.., 1]>, style= pointline, color= red)
):
#Create a direct memory link to the 2x3 matrix inside the pointplot3d structure.
#Thus, we can change the frame simply by changing the matrix.
A:= ArrayTools:-Alias(indets(Frame, Matrix)[]):
#
#Procedure that changes the frame:
P:= k-> 
    if k::posint then :-A[2]:= :-Pts[..,k]^+; :-Frame
    else 'procname'(k)
    fi
:
Explore(
    P(k), parameters= [[k= 1..N, shown= false, animate]], autorun, numframes= N,
    initialvalues= [k= 1]
);

One frame:

I suggest that you create an object (see help page ?object) to represent the 32-bit floats. The internal storage of the object should use strictly nonnegative integers. The floats can be packed into a 1-word integer. The Bits package can be used for reasonably efficient sub-word-sized manipulations. All arithmetic operations can overloaded to work with the floats.

How much programming experience do you have, and does that include any experience in object-oriented programming (OOP)?

The purpose of my suggestion is to facilitate experimentation as you develop the firmware code. Execution speed is not a concern.

If your document begins with restart (which is almost always a good idea), then the code for a procedure must come before the attempt to use the procedure.

The "unable to parse" error is caused by the semicolon at the end of the first line of myProc. Consider these three variations:

  1. myProc:= proc(pA)
  2. myProc:= proc(pA)::string;
  3. myProc:= proc(pA);

The first two of those are valid syntax; the third is not (using 2D Input). 

Try rtable_eval(eval(solution, {t= 1})).

Not equals: <>

Solving an equation is almost equivalent to solving the numerator of the difference of the two sides. This gives a usable solution:

solve(numer(p0 - p1),  y);

It still gives that warning, but a warning is not an "error", and "may have been lost" is not necessarily "were lost". 

You should collect the data inside the loop into matrices, then use a plot command after the loop.

This does side-by-side plots for your 3 values of k1. In your data-collection loop, the lines that I added or modified are followed by ####. For brevity here, I omitted lines that weren't needed to get the plots; however, the code executes fine if those lines are included.

#Data-collection loop:
beta:= {$1..8}:  ####
for k1 in K do
    plotdata[k1]:= Matrix(nops(beta), 4); ####
    for i to nops(beta) do ####
        b:= beta[i]; ####
        Etemp := eval(
            `&pi;central`(p, e, z), 
            [A = 0, B = 2, alpha = 50, beta = b, c = 5, k = k1, mu = 10, v = 1]
        );
        Soln:= NLPSolve(Etemp, p = 5 .. 500, e = 0.5 .. 10, z = 0 .. 10, maximize);
        (etemp, ptemp, ztemp):= eval([e, p, z], Soln[2])[]; ####
        `&pi;temp` := Soln[1];
        y_temp:= eval(y(p, e), [alpha = 50, beta = b, p = ptemp, k = k1, e = etemp]);
        q_temp:= y_temp + ztemp;
        plotdata[k1][i] := <b | ptemp | etemp | q_temp> ####
    od
od:
plots:-display(
    <seq(
        plot(
            [seq](plotdata[k1][..,[1,j]], j= 2..4), legend= ['p', 'e', 'q'],
            style= pointline, symbol= [box, diamond, solidcircle], 
            labels= ['beta', ``], title= sprintf("k1 = %a", k1), axes= boxed
        ),
        k1= K
    )>^%T
);

Yes, this is called a traveling-salesman problem. In the code below, the variable met indicates which norm (or metric) is used to measure the distance between points. You may not know that your points are already sorted with respect to the standard Euclidean (or "2") norm. If the 1-norm (sum of distances in each dimension) is used, the order is different. The code below takes about 4 minutes. This problem is a canonical example of an NP-complete problem, for which there's no known fast algorithm for guaranteed shortest path.

In my initial matrix below, note that I trimmed off the repetition of the 1st point as the last point.

met:= 1: #Use 1-norm.
LT:= Matrix([
    [1, 1, 0], [3, 2, 0], [2, 3, 1], [1, 3, 1], [1, 4, 2], [1, 5, 0], [2, 5, 1], 
    [3, 5, 3], [4, 5, 3], [3, 4, 5], [4, 3, 2], [5, 3, 2], [5, 4, 1], [5, 2, 1],
    [5, 1, 0], [4, 1, 2], [3, 1, 2], [2, 1, 2], [1, 2, 1]
]):
W:= Matrix( #"Weight" matrix, or pairwise distances
    upperbound(LT)[1]$2, (i,j)-> LinearAlgebra:-Norm(LT[i]-LT[j], met),
    shape= symmetric, datatype= hfloat
):
(d,P):= CodeTools:-Usage(GraphTheory:-TravelingSalesman(GraphTheory:-Graph(W)));
memory used=21.20GiB, alloc change=0 bytes, 
cpu time=3.87m, real time=3.60m, gc time=33.45s

d, P := 42., [1, 19, 4, 3, 7, 6, 5, 10, 8, 9, 11, 12, 13, 14, 15, 
  2, 16, 17, 18, 1]

#d = 42 is the total distance.

LT__sorted:= convert(<LT, LT[1]>[P], listlist);
LT__sorted := [
    [1, 1, 0], [1, 2, 1], [1, 3, 1], [2, 3, 1], [2, 5, 1], 
    [1, 5, 0], [1, 4, 2], [3, 4, 5], [3, 5, 3], [4, 5, 3], 
    [4, 3, 2], [5, 3, 2], [5, 4, 1], [5, 2, 1], [5, 1, 0], 
    [3, 2, 0], [4, 1, 2], [3, 1, 2], [2, 1, 2], [1, 1, 0]
]

 

There are cases where a discrete, plot-based technique such as you suggest is necessary, but this isn't one of them: Standard algebraic, analytic, numeric techniques will work for this. I think that you should use them when they work, because they'll give you much more mathematical flexibility. 

fsolve(1 - binomial(180000,r)*r!/180000^r = 0.25, r= 1..infinity);
                          322.2204929

This works because the right side of the equation is a continuous, increasing function of r for real r >= 1r isn't restricted to integers.

There may be some cases where you'd need to use a plot-based technique (such as you suggest) to answer that question, but this isn't one of them. Here, straightforward algebraic, analytic, numerical techniques work, and I think it's more mafhematically robust for you to use them. 

fsolve(1 - binomial(180000,r)*r!/180000^r = 0.25, r= 1..infinity);
             322.2204929

Note that Maple's plotting commands produce somewhat high-level and human-readable data structures before they're displayed as plots. The relevent data can be extracted from those, as in the following example. The particular data that you asked about is in two-column matrices, which there may be several of.

P:= plot(x^2, x= -2..2); #Store plot in variable P.
op(P); #Show the entire data structure.
data:= indets(P, And(rtable, (posint, 2) &under upperbound)); #Extract the 2-column matrices

In this case, there's one such matrix, which I now extract from the set produced by the previous command:

Curve:= data[1]; #1st (and only) item in the set

Curve contains about 200 points (version dependent) in this case. Mine has exactly 200. Each row is an (xy) pair in Cartesian coordinates (even if you used a different coordinate system, for example, polar).

Here's how to index matrices. The 1st entry in the 99th row is Curve[99, 1]; the 19th row is Curve[19]; the 2nd column (the y-coordinates) is Curve[.., 2]; etc. The are many indexing variations possible.

The command usually recommended for extracting data from a plot is plottools:-getdata. However, I strongly prefer the method that I described above.

If you make a numeric dsolve call such as

P:= dsolve({diff(y(x), x) = y(x), y(0)=1}, numeric, method= rkf45)

then will be a procedure. List its contents with

showstat(P)

For a procedure of this size, showstat will give you more-human-readable results than print(P).

The procedure P has a **local** Array _dat, which has another procedure stored in _dat[1]. This latter procedure does the bulk of the work.

You said that this was in a procedure. In the procedure's declarations area, include

uses plots;

Then within that procedure, any reference to a command from package plots will not need the plots:- prefix.

I'd recommend against using alias or macro inside a procedure, but I'm only guessing that they might cause problems, potentially by altering the global state. I don't know from experience.

Regarding your statement odeplot:= plots:-odeplot: If odeplot is a local variable of the procedure, there would be no problem with doing it that way. But I think that uses is very, very slightly more efficient because there's no need to allocate and dereference a local.

@Ronan You asked:

  • Q1. if A :=[2,3] how do I get the procedure to detect and print that it is _T2L?

See my additions to the attached worksheet/module, in green again. I also modified ModuleUnload so that you won't get those distracting but totally harmless warning messages about overwriting the types.

  • Q2. why does it need [ModuleLoad() right before end module]?

Good question. It's just for editing, testiing, rewriting the code. A ModuleLoad is automatically called when the module is loaded from a library/archive. When we're rewriting/editing the code in a worksheet session, the new code is not in a library, so that automatic execution of ModuleLoad doesn't happen. But we need the effects of ModuleLoad() to test the code.

restart

 

rt:=module()
option package;
export f1,f2;
local MyModule;

MyModule:= module()
uses TT= TypeTools;
global _T1, _T2L, _T2V, _T3L, _T3V, _MyType;
local
     MyTypes:= {_T1, _T2L, _T2V, _T3L, _T3V},
     AllMyTypes:= MyTypes union {_MyType},
     
     ModuleUnload:= proc()
     local T;
          for T in AllMyTypes do if TT:-Exists(T) then TT:-RemoveType(T) fi end do;
          return
     end proc,

     ModuleLoad:= proc()
     local
          g, #iterator over module globals
          e
     ;
          ModuleUnload();
          #op([2,6], ...) of a module is its globals.
          for g in op([2,6], thismodule) do
               e:= eval(g);
               #print("e",e);
               if g <> e and e in AllMyTypes then
                    error "The name %1 must be globally available.", g
               end if
          end do;
          TT:-AddType(_T1, algebraic);
          TT:-AddType(_T2V, 'Vector(2, algebraic)');
          TT:-AddType(_T2L, [algebraic $ 2]);
          TT:-AddType(_T3V, 'Vector(3, algebraic)');
          TT:-AddType(_T3L, [algebraic $ 3]);
          TT:-AddType(_MyType, MyTypes);
          return
     end proc;          

export
     WhichMyType:= proc(X)
     local S:= select(T-> X::T, MyTypes), n:= nops(S);
         printf("%a is ", X);
         if n=0 then printf("not any of the special types.\n")
         else printf("type %a.\n", `if`(n=1, S[], Amd(S[])))
         fi
      end proc;

      ModuleLoad()    
      end module;
     

#Proceduews for export
     f1:= overload([
          proc(A::_T1, B::_T1, C::_T1)
          option overload;
          local r:= "A, B, C are T1."; #unnecessary; just an example.
               #statements to process this type
          end proc,

          proc(A::_T2L, B::_T2L, C::_T2L)
          option overload;
          local r:= "A, B, C are T2L.";
               #
          end proc,

          proc(A::_T2V, B::_T2V, C::_T2V)
          option overload;
          local r:= "A, B, C are T2V.";
               #
          end proc,

          proc(A::_T3L, B::_T3L, C::_T3L)
          option overload;
          local r:= "A, B, C are T3L.";
               #         
          end proc,

          proc(A::_T3V, B::_T3V, C::_T3V)
          option overload;
          local r:= "A, B, C are T3V.";
               #
          end proc,

          proc(A::_T2L, B::_T3L,$)
          option overload;
          local r:= "A, B, are mixed.";#I added this
               #
          end proc
     ]);

     
     f2:=overload([
          proc(A::_T2L,B::_T1)
               option overload;
               MyModule:-WhichMyType(A);
               A*B^2
          end proc,

          proc(A::_T3L,B::_T1)
               option overload;
               MyModule:-WhichMyType(A);
               A*B^3-2*B
          end proc
     ]);
          
end module;

#maplemint(rt);
#Example usage:





 

_m1759336810304

x:=[9,4]:
y:=[5,67]:
z:=[1,2]:                                 

rt:-f1(x,y,z);
rt:-f1(2,y,s);  #should produce an exception
x:=<9,4,r>:
y:=<5,6,r>:
z:=<1,2,w>:                                 
rt:-f1(x,y,z);
x:=[9,4]:
y:=[5,6,7]:
z:=[1,2]:
rt:-f1(x,y);
rt:-f2([2,3],5);
rt:-f2([2,3,8],19);

"A, B, C are T2L."

Error, invalid input: no implementation of f1 matches the arguments in call, 'f1(2,y,s)'

"A, B, C are T3V."

"A, B, are mixed."

[2, 3] is type _T2L.

[50, 75]

[2, 3, 8] is type _T3L.

[13718, 20577, 54872]-38

 

 

Download Module_Test_Types_2.mw

I guess that this is just a a very simplified example of what you actually want to do?

Matrix indices start at 1, not 0. So perhaps you want an Array or a table instead of a Matrix?

A Matrix can be indexed A[i, j] or A(i, j), but these mean slightly different things. A[i, j] assumes that i and j are valid indices. A(i,j):= ... will create them as valid indices if need be.

First 20 21 22 23 24 25 26 Last Page 22 of 382