Paul

495 Reputation

8 Badges

14 years, 284 days
Paul DeMarco is the Director of Development at Maplesoft, a position that has him involved with technical planning and development of Maple and the various core technologies that use Maple as a computation engine. He joined Maplesoft in September 1996 while studying at the University of Waterloo in the CS/EEE program -- a track that combines core math and computer science courses with electrical engineering electives. Paul's development work in the Math and Kernel Groups over the years touches a wide variety of areas, including algorithms, data structures, and connectivity with other products. He is also involved with core Maple as well as Maple T.A.

MaplePrimes Activity


These are answers submitted by Paul

 

The "solution" option can be a procedure, where you can pick apart or add to the answer.   You could do something like the following:

Student:-Basics:-PracticeSheet("integer*variable(x)^2+integer*variable(x)+integer", solution = (ans->discrim(ans,x)) );

Student:-Basics:-PracticeSheet("[integer*variable(x)^2+integer*variable(x)+integer, integer]", solution = (ans->Student:-Calculus1:-Tangent(ans[1],x=ans[2])),inline );
 

The second case has two parameters that need to be shown to the student -- the equation and point.  Some explanation would be needed in the message to explain what is being shown in a comma separated list.

 

define_external can be called in two different ways:  (1) specify all of the argument types and let Maple handle the conversion mapping, or (2) tell it that you will handle the conversions on your own.

For this example using function pointers, you will want to use method (2).  This is documented in ?define_external,CustomWrapper (http://www.maplesoft.com/support/help/Maple/view.aspx?path=define_external/CustomWrapper).  

In a nutshell, replace all of the argument type declarations in the define_external calling sequence with the keyword MAPLE.  Then, create a .dll with an entry point that looks like this:

    

#include "maplec.h"
ALGEB  rk4( MKernelVector kv, ALGEB fn_args );

 

In the C code you will need to look through "fn_args"  and pick out the arguments you want before calling your rk4vec procedure directly.

 

You will need to use strings to enter big integers into Maple, and to go back and forth between OpenMaple and Java's BigInteger class.

Somehing like the following should work:

Algebraic a1 = engine.evaluate("39614081257132168796771975168;");
String s = a1.toString();
BigInteger(s);

Here is an approach that uses a separate thread to gather the messages in each grid node.  The thread blocks when calling Grid:-Receive until a message is ready.  When the message comes through, it puts the message in a table.  At the same time, the "worker" procedure can call Messages:-NonBlockingReceive, which will look in the table to see if there is any saved data.  If so, return it, otherwise just return NULL without waiting. 

There are some tricky details when the job is complete.  Here we have all of the senders create a special "done" message so that the receiver threads can shut down.  There is also an important detail about locking around access to the "data" table.  In order to safely unassign the message that has been received, you need to lock around both the assign and unassign statements.

Here is the code, it makes liberal use of printf statements so that you can see what is going on when it is run.  The first part is a "Messages" module that implements the receiver thread, and the NonBlockingReceive procedure.  The second part is a "work" procedure that just loops a bit while sending and receiving messages.  The two commands at the bottom initialize the grid nodes and start the job.

Messages := module()
    local data, dataAccessLock, first, last;

    export Init := proc()
        data := table():
        dataAccessLock := Threads:-Mutex:-Create();;
        first := 0;
        last := 0;
    end proc;

    export NonBlockingReceive := proc()
        local r;
        if first = last then
            r := NULL;
        else
            r := data[first];
            Threads:-Mutex:-Lock(dataAccessLock);
            unassign('data[first]');
            Threads:-Mutex:-Unlock(dataAccessLock);
            first := first+1;
        end if;
        r;
    end proc:

    export ReceiveThread := proc(me)
        local msg;

        printf("Thread started %d\n",me);
        while true do
            msg := Grid:-Receive();
            printf("Node %d stashing message data[%d] = %a\n",me,last,msg);
            if msg = "done" then
                break;
            end if;
            Threads:-Mutex:-Lock(dataAccessLock);
            data[last] := msg;
            Threads:-Mutex:-Unlock(dataAccessLock);
            last := last+1;
        od;
        printf("Thread finished %d\n",me);
        0;
    end;
end module:

work := proc()
    local me := Grid:-MyNode();
    local NN := Grid:-NumNodes();
    local msg, i, id, total := 0;;
    printf("I'm node %d\n",me);

    Messages:-Init();
    id := Threads:-Create(Messages:-ReceiveThread(me));

    # simulate a loop that interleaves work with send & receive
    printf("Node %d starting work loop\n",me);
    for i from 1 to 300 do
       msg := Messages:-NonBlockingReceive();
       if msg <> NULL then
           printf("Node %d got %a\n",me,msg);
           total := total + msg;
       else
           printf(".");
       end if;
       if i mod 100 = 0 then
           printf("Node %d sending message to node %d\n",me,(me+1) mod NN );
           Grid:-Send( (me+1) mod NN, i);
       end if;
    od;
    Grid:-Send( (me+1) mod NN, "done");

    # done generating work; gather up the remaining messages
    Threads:-Wait(id);  #this will wait until the last message is delivered
    while true do
       msg := Messages:-NonBlockingReceive();
       if msg <> NULL then
           printf("Node %d got %a\n",me,msg);
           total := total + msg;
       else
           break;
       end if;
    od;
    printf("Node %d finished\n",me);

    total;
end;

Grid:-Set(work,Messages);
Grid:-Run(work);

 

 

Indeed the problem is a bug when resizing an Array with a datatype that doesn't include zero.  Because type(0,string) fails, Maple needs to choose a different initial value other than zero to fill in the resized memory block with.  The defect lies in the way it tries to pick the 'fill' value.

The workaround as mentioned in an earlier post is to use datatype=anything.  If you really need a string datatype, you could try datatype={string,identical(0)}. 

This will be logged and fixed. 

 

The evalM command is for calling Matlab commands from Maple.  I think Subhra is looking for the reverse direction -- calling Maple commands from within Matlab.  This can be done using the Maple Toolbox for Matlab (MTM).

When you first installed Maple it may have asked you about a path to Matlab in order to set up MTM.  If you have the directory $MATLAB/toolbox/maple (where $MATLAB is the path to your Matlab install), then you likely have everything all ready to go.  Otherwise, run "MapleToolbox.bat", or similar platform specific install script sitting in your root Maple program directory.

The documentation for this toolbox is all inside Matlab.  Reference it by typing the following at the Matlab command prompt:

>> doc maple

There are many commands to seamlessly call into maple to do computations using Matlab syntax.  There is also a general command called "maple", which will accept arbitrary Maple expressions.  For example:

>> x = sym('x');
>> x^3+cos(2*x)-1

 ans =
          3
         x   + cos(2 x) - 1
>> diff(x^3)
 
 ans =
                   2
               3 x
>> maple('int',ans,'x')
 
 ans =
                   3
                  x
>> maple('evalf(Pi,10)')

 ans =
            3.141592654
  
 

The commands above are all typed at a Matlab prompt.  sym declares a variable as a Maple expression, which you can then use with various commands like "diff", that are part of MTM (and call directly through to Maple's diff command).  The first use of the maple command shows how to pass arguments computed in Matlab.  The second use shows a self contained Maple expression.

Automatic Maple-type to Fortran-type conversion is only set up for the core types described in ?define_external/types.  More complicated compound types like arrays of strings require a wrapper layer with hand translations using Maple's external API to pick apart the Maple types. 

If you are adventurous you can try writing the wrapper in C using the Watcom compiler to interface to your Fortran .dll.

 

To restate your question with a simple example, consider the following:

> p := proc(a) option remember; A[1]+A[2]; end:
> A := Array([1,2]):
> p(A);
                                           3

> A[2] := 5:
> p(A);
                                           3
 

The remember table is being used to fetch the result in the second case because it is seeing exactly the same arguments passed into the procedure call.  There has been some discussion at Maplesoft to change the behaviour of remember tables such that they are bypassed when mutable argument is given.  In these cases the procedure cannot really tell if it should returned the cached value or not.   The current behaviour assumes that the given array has not changed since the last call.  This is useful in many situations, but potentially dangerous.

For your example it is not clear that remember tables would help.  Your code can be modified to manually do a remember-like lookup without option remember:

Rook := proc (A, m, n, B, k, rem )
local C, i, j, h, l, count, v;

 #manual option remember
  v :=  rem[ convert(A,listlist),m,n,B,k ];
  if v::integer then
      print("using remembered value");
      return v;
  end if;

count := 0;
  if k = 1 then
    for i from 1 to m do
      for j from 1 to n do
        if `not`(`in`([i, j], B)) then
          if add(A[p, j], p = 1 .. m) = 0 then
            if add(A[i, q], q = 1 .. n) = 0 then
              count := count+1
            end if
          end if
        end if
      end do
    end do
  else
    C := Array(1..m,1..n);   #initialize as an Array so it isn't created as a table
    for i from 1 to m do
      for j from 1 to n do
        if `not`(`in`([i, j], B)) then
          if add(A[p, j], p = 1 .. m) = 0 then
            if add(A[i, q], q = 1 .. n) = 0 then
              for h from 1 to m do
                for l from 1 to n do
                  C[h, l] := A[h, l]
                end do
              end do;
              C[i, j] := 1;
              count := count+Rook(C, m, n, B, k-1,rem);
              C[i, j] := 0
            end if
          end if
        end if
      end do
    end do
  end if;
count := count/k
end proc:


A2 := Array(1 .. 20, 1 .. 20,fill=0):
B1 := {[1, 1]};

t := time();
Rook(A2, op(map(rhs,[ArrayDims(A2)])), B1, 2, table());
time() - t;
 

I tried to keep the code exactly the same, except I added a constructor call to create C as an array -- previously it was being implicitly created as a table.  This just helps a bit with the convert/listlist call in the remember lookup.  Note that the listlist conversion is expensive and uses a lot of memory.  It is necessary to illustrate this example though, as you need to keep a copy of all the elements of the array in order to do a proper remember  lookup.  I wouldn't recommend doing this in practice. 

After running the new example you may notice that ("using remembered value") is never printed.  Due to the nature of this example, it is never the case that a cached value would be fetched from the remember table.  Your original example only ran fast with option remember because it wasn't working as intended.

 

Maple TA 4.0 supports using MapleNet as the infrastructure to evaluate commands.  Using this setup you will get the GUI's plot renderer in Maple TA instead of the commandline version's. Greek characters such as &pi will render correctly.

1.      I have noticed that the time set in the assignments editor does not appear the same on the class homepage. My supplier then told me to fix a the database to GMT+1 and everything seemed consistent. However, for some reason this then started behaving oddly again, being one hour out between the two readings after behaving OK!! Why is this behaving in this way? Surely, there must be a definitive setting? (I live in the UK). Perhaps it is the calendar facility setting that is fickle?

The reason for the behavior you are seeing is that GMT+1 doesn't account for daylight saving time (DST) which gives +-1 hour jumps during the year. To make the TA time switch together with DST, the timezone in the database should be set for the UK to GMT0BST (where the "0" in the middle is zero, not letter O).  
 

2.     The ‘assignments’ page for instructors – it is very slow in loading from whichever page I try to link to it in MapleTA. It may take in excess of half a minute. It is very strange as access and links to all other pages are fine and take place within seconds if not immediately. We carried out the vacuuming recommended by the supplier but no improvement. Why this page?

Vacuuming the database is a good start.  If you are currently using  TA 3.0, make sure that you have installed all the hotfixes issued for this version -- there were some that improved performance.

3.      I have had a handful of complaints from students that, when they have clicked on ‘grade’ on finishing an assignment, then they have been logged out and returned to the login page. When they have then logged in again, there is no record of that particular attempt at the assignment. This appears to be an intermittent, randomly occurring problem in a small minority of cases. We are sending log files to MapleTA as requested. Has anyone experienced such odd behaviour. We have rebooted but to no avail.

The login page will be shown when the TA session expires.  This happens when a student is inactive in TA for more than 30 minutes (whereupon they just need to login again and can continue where they left off).  Answered questions get recorded in the database immediately after submitting the answer, so it shouldn't be possible to lose the record of a particular assignment attempt. If however the test is set up as a practice assignment (rather than a Quiz assignment), then, by design no grade and no history is recorded. 
 

4.      We are not been able to receive emails from Mapleta. This means that, any student who has gone through the ‘forgot your password?” has found the Mapleta has changed it and it has not been sent in an email. Yes, we have checked all the addresses in the database for the relevant servers

TA has to be configured to point to your mail server.  Check that the settings for the "mail" group in the system_properties database table is correct.   The "From:" address used by Maple TA must be a valid address recognized by the mail server.  Also, the mail server must be accessible by the Tomcat user from the host where Maple TA is running.
 

And, no, it is not practical to go to v4 during teaching.

Unlike the upgrade from TA 2.5 to TA 3.0, which involved major architecture changes (use of Postgres database, and Tomcat web server), the upgrade from TA 3 to TA 4 is easy and low risk, even when done in the middle of a semester.  Still, the problems you are seeing with TA 3.0 look like they can be addressed without needing an upgrade.

 

-PD

Just a quick note on workarounds for some of these issues:

(3) Right now, you will get an error when using the LaTex to .qu converter, that the Maple question type isn't known.  You can ignore that message and the .qu file will be generated properly.  The LaTeX converter is available on the maplesoft web site and isn't in the product, but the task of updating it is in the queue.

(4) Try having Maple return a list of expressions and use Maple T.A.'s switch command to get at each one. 

(6) Maple T.A. has traditionally used the graphics export engine provided by the Maple commandline interface.  This is still the default in Maple T.A. 4.0, but you now have the option of connecting to MapleNet as the back-end math and graphics engine.  MapleNet uses the more modern java-based plot drivers.  Try setting up MapleNet to get access to new plot features like gridlines and polar axes, as well as improved quality.

-PD

 



 

The online help ?OpenMaple,C,textCallBack says:

    MAPLE_TEXT_QUIT    Response to a Maple quit, done, or stop command.
 

Theoretically, this could probably show up on some other kind of controlled shutdown like an out-of-memory event.  

To try and reproduce the problem I created a simple OpenMaple app that called EvalMapleStatement to assign expr to the large expression from Tony's last post, followed by  EvalMapleStatement(kv,Logic:-BooleanSimplify(expr)):   Running in the Maple 12 beta, this finished in about 184 seconds.  I had to set my shell's stacksize limit down to 450kB before I started seeing problems, but then I just got the standard "too many levels of recursion" error, not a MAPLE_TEXT_QUIT callback.  The memory and stack required for this example are miniscule, so I doubt you're running into system limits; unless maybe the main driver of your OpenMaple application is resource heavy, and possibly doing other things at the same time in another thread.

Switching back to Maple 11 is an excercise in patience -- it's still running after 30 minutes. 

 -PD

 

I just tried the Upgrade installer of Excel 2007. I previously had a working Maple-Excel addin, but the upgrade removed it. Adding it back in was a bit different. Here are the steps: - click the MS Office Button and select "Excel Options" - click Add-ins - in the "Manage" box select "Excel Add-ins" then click "Go" - click "Browse" - navigate to the Excel subdirectory of your Maple install and select WMIMPLEX.xla (ie. select $MAPLE/Excel/WMIMPLEX.xla) Now, go back into your spreadsheet and try a formula, something like =maple("1+1"). I tried a few things and they all worked fine with Excel 2007. I was using Maple 11.01. If your Excel/Maple link didn't work after upgrading, I'd suggest removing the addon from Excel and installing it again. -PD
To protect against corruption of a repository on a multi-user system, or when multiple Maple sessions are open and writing to the same repository, Maple uses POSIX locks via the lockf() command. I don't know why there would be a lock set on your repository -- possibly there is a hung mserver process still running on your system? If necessary you can bypass repository locking by setting the environment variable DISABLELOCKING=1.
Only one OpenMaple connection is allowed per process, so you can't call StartMaple a second time in another thread. However, with Maple 11's Threads package you can start multiple threads within a shared kernel. Take a look at ?Threads -PD
1 2 Page 1 of 2