acer

32632 Reputation

29 Badges

20 years, 46 days
Ontario, Canada

Social Networks and Content at Maplesoft.com

MaplePrimes Activity


These are replies submitted by acer

@jeffb You haven't shown your revised code, so we cannot tell the source of the error message.

mymatrix:=proc(A::Matrix,B::Matrix)
local i,j,q,C,numrowsA,numcolsA,numcolsB;
   numrowsA,numcolsA:=op(1,A);
   numcolsB:=op([1,2],B);
   C:=Matrix(numrowsA,numcolsB);
   for i from 1 to numrowsA do
      for j from 1 to numcolsB do
         for q from 1 to numcolsA do
            C[i,j]:=C[i,j] + A[i,q]*B[q,j];
         od;
      od;
   od;
   return C;
end proc:

x:=Matrix(3,2,symbol=X):
y:=Matrix(2,4,symbol=Y):

mymatrix(x,y) - x . y;

                                [0  0  0  0]
                                [          ]
                                [0  0  0  0]
                                [          ]
                                [0  0  0  0]

Should you add a check that the number of columns of A equals the number of rows of B?

If you've been instructed to not use any "built-in" routines then the spirit of that instruction is presumably to prevent you from simply using `.` or MatrixMatrixMultiply or something similar. You'll still have to use something to pick off the dimensions of A and B or else you'd have to pass those in as additional arguments in order to have the code get them right. I would guess that you probably are allowed to use LinearAlgebra:-Dimensions(), but if not then you might be allowed to use op() as above.

Don't blindly trust that code above: check it, via understanding.

@andrewfortune Applying the ``() procedure to something makes a function call out of it, which prettyprints with round brackets. Thus, ``(17) gets printed as (17), which is useful. And `expand` undoes this, which is also useful.

So, ``(17)! gets printed just as (17)!

The operation subsindets(A,B,C) changes the expression A by substituting C(z) for all subexpressions z in A which are of type B.

For example,

expr:=(sin(2*x)+7)*exp(3*t);

                       expr := (sin(2 x) + 7) exp(3 t)

subsindets(expr,integer,z->z^2);

                          (sin(4 x) + 49) exp(9 t)

Here we have substituted each integer in `expr` by its square.

In simpler terms, what I did to my `T` to get my `Q` was to substitute for everything of a type matching z! with ``(z)!, where z could be anything.

You can `lprint` both `T` and `Q`, to see the difference.

You can also create your own Taylor series operator in Maple. And you can adjust it to suspend the factorial execution, as well.

restart:

taylor(sin(x),x=0,11); # The stock Library routine for this

                  1  3    1   5    1    7     1     9    / 11\
              x - - x  + --- x  - ---- x  + ------ x  + O\x  /
                  6      120      5040      362880            

convert(%,polynom);

                       1  3    1   5    1    7     1     9
                   x - - x  + --- x  - ---- x  + ------ x 
                       6      120      5040      362880   

t:=(e,x,x0,n)->add((x-x0)^i/i!*eval(diff(e,x$i),x=x0),i=1..n):
t(sin(x),x,0,9);

                       1  3    1   5    1    7     1     9
                   x - - x  + --- x  - ---- x  + ------ x 
                       6      120      5040      362880   

q:=(e,x,x0,n)->add((x-x0)^i/``(i)!*eval(diff(e,x$i),x=x0),i=1..n):
q(sin(x),x,0,9);

                            ((e,x,x0,n)->add((x-x0)^i/``(i)!*eval(diff(e,x$i),x=x0),i=1..n))(sin(x),x,0,9)

expand(%);

                       1  3    1   5    1    7     1     9
                   x - - x  + --- x  - ---- x  + ------ x 
                       6      120      5040      362880   

@andrewfortune Applying the ``() procedure to something makes a function call out of it, which prettyprints with round brackets. Thus, ``(17) gets printed as (17), which is useful. And `expand` undoes this, which is also useful.

So, ``(17)! gets printed just as (17)!

The operation subsindets(A,B,C) changes the expression A by substituting C(z) for all subexpressions z in A which are of type B.

For example,

expr:=(sin(2*x)+7)*exp(3*t);

                       expr := (sin(2 x) + 7) exp(3 t)

subsindets(expr,integer,z->z^2);

                          (sin(4 x) + 49) exp(9 t)

Here we have substituted each integer in `expr` by its square.

In simpler terms, what I did to my `T` to get my `Q` was to substitute for everything of a type matching z! with ``(z)!, where z could be anything.

You can `lprint` both `T` and `Q`, to see the difference.

You can also create your own Taylor series operator in Maple. And you can adjust it to suspend the factorial execution, as well.

restart:

taylor(sin(x),x=0,11); # The stock Library routine for this

                  1  3    1   5    1    7     1     9    / 11\
              x - - x  + --- x  - ---- x  + ------ x  + O\x  /
                  6      120      5040      362880            

convert(%,polynom);

                       1  3    1   5    1    7     1     9
                   x - - x  + --- x  - ---- x  + ------ x 
                       6      120      5040      362880   

t:=(e,x,x0,n)->add((x-x0)^i/i!*eval(diff(e,x$i),x=x0),i=1..n):
t(sin(x),x,0,9);

                       1  3    1   5    1    7     1     9
                   x - - x  + --- x  - ---- x  + ------ x 
                       6      120      5040      362880   

q:=(e,x,x0,n)->add((x-x0)^i/``(i)!*eval(diff(e,x$i),x=x0),i=1..n):
q(sin(x),x,0,9);

                            ((e,x,x0,n)->add((x-x0)^i/``(i)!*eval(diff(e,x$i),x=x0),i=1..n))(sin(x),x,0,9)

expand(%);

                       1  3    1   5    1    7     1     9
                   x - - x  + --- x  - ---- x  + ------ x 
                       6      120      5040      362880   

It turns out that CodeGeneration[C] does handle piecewise, but only if the optimize option is supplied. (I'll submit a bug report, that it should be handled by default.)

restart:

with(CodeGeneration):
with(LanguageDefinition):

myp:=proc(x::numeric) local result::numeric;
     result:=piecewise(x>3,3*x,x>2,2*x,x>1,1*x,0);
end proc;

         myp := proc(x::numeric)
         local result::numeric;
           result := piecewise(3 < x, 3*x, 2 < x, 2*x, 1 < x, x, 0)
         end proc;

Translate(myp, language="C", optimize);

double myp (double x)
{
  double result;
  double s1;
  if (0.3e1 < x)
    s1 = 0.3e1 * x;
  else if (0.2e1 < x)
    s1 = 0.2e1 * x;
  else if (0.1e1 < x)
    s1 = x;
  else
    s1 = 0.0e0;
  result = s1;
  return(result);
}

As you can see, piecewise is handled above by translation to a separate if(){..} block, with assignment to an introduced temporary variable. That temporary is subsequently used wherever the piecewise call existed in the Maple procedure. And the temporary is declared. Nice and automatic. So that might suffice for your use of piecewise.

You also asked how you could both introduce and declare such temporary variables in your own extensions (if I understand you rightly). Continuing on in the same Maple session from above, here are some ideas along those lines. An unassigned global name is generated. The myp procedure is put into inert form, to which the new local variable is added. And then that altered inert form is turned back into an actual procedure. As an illustration, I used a modified version of your original extension to handle piecewise. This all produces something close to acceptable. The only snag is that the assignment statement,

result = temporary_variable;

is out of place! It lies before the piecewise translation block. I don't yet see how to repair that in the method.

LanguageDefinition:-Define("NewC", extend="C",
    AddFunction("piecewise", anything::numeric,
        proc()
            global T;
            local i, t;
            t:=convert(T,string);
            Printer:-Print(t,";\n");
            Printer:-Print("  if (",_passed[1],
                           ")\n    { ",t," = ",_passed[2],"; }\n");
            for i from 3 to _npassed-2 by 2 do
                Printer:-Print("  else if (",_passed[i],")\n    { ",
                               t," = ",_passed[i+1],"; }\n");
            end do;
            Printer:-Print("  else { ",t," = ",_passed[_npassed],"; }");
        end proc,
    numeric=double)
):

T:=`tools/genglobal`('s'):

newmyp := FromInert(subsindets(ToInert(eval(myp)),'specfunc(anything,_Inert_LOCALSEQ)',
           z->_Inert_LOCALSEQ(op(z),
                              _Inert_DCOLON(_Inert_NAME(convert(T,string)),
                                            _Inert_NAME("numeric",
                                               _Inert_ATTRIBUTE(_Inert_NAME("protected",
                                               _Inert_ATTRIBUTE(_Inert_NAME("protected")
          ))))))));

Translate(newmyp, language="NewC");
         newmyp := proc(x::numeric)
         local result::numeric, s::numeric;
           result := piecewise(3 < x, 3*x, 2 < x, 2*x, 1 < x, x, 0)
         end proc;

double newmyp (double x)
{
  double result;
  double s;
  result = s;
  if (0.3e1 < x)
    { s = 0.3e1 * x; }
  else if (0.2e1 < x)
    { s = 0.2e1 * x; }
  else if (0.1e1 < x)
    { s = x; }
  else { s = 0; };
  return(result);

If you rerun the last three statements above (from the assignment to T, through to the Translate call) then you should see a new temp variable used, such as s0. And then s1 if repeated yet again. And so on.

Perhaps this will give you some more ideas to work with.

acer

It turns out that CodeGeneration[C] does handle piecewise, but only if the optimize option is supplied. (I'll submit a bug report, that it should be handled by default.)

restart:

with(CodeGeneration):
with(LanguageDefinition):

myp:=proc(x::numeric) local result::numeric;
     result:=piecewise(x>3,3*x,x>2,2*x,x>1,1*x,0);
end proc;

         myp := proc(x::numeric)
         local result::numeric;
           result := piecewise(3 < x, 3*x, 2 < x, 2*x, 1 < x, x, 0)
         end proc;

Translate(myp, language="C", optimize);

double myp (double x)
{
  double result;
  double s1;
  if (0.3e1 < x)
    s1 = 0.3e1 * x;
  else if (0.2e1 < x)
    s1 = 0.2e1 * x;
  else if (0.1e1 < x)
    s1 = x;
  else
    s1 = 0.0e0;
  result = s1;
  return(result);
}

As you can see, piecewise is handled above by translation to a separate if(){..} block, with assignment to an introduced temporary variable. That temporary is subsequently used wherever the piecewise call existed in the Maple procedure. And the temporary is declared. Nice and automatic. So that might suffice for your use of piecewise.

You also asked how you could both introduce and declare such temporary variables in your own extensions (if I understand you rightly). Continuing on in the same Maple session from above, here are some ideas along those lines. An unassigned global name is generated. The myp procedure is put into inert form, to which the new local variable is added. And then that altered inert form is turned back into an actual procedure. As an illustration, I used a modified version of your original extension to handle piecewise. This all produces something close to acceptable. The only snag is that the assignment statement,

result = temporary_variable;

is out of place! It lies before the piecewise translation block. I don't yet see how to repair that in the method.

LanguageDefinition:-Define("NewC", extend="C",
    AddFunction("piecewise", anything::numeric,
        proc()
            global T;
            local i, t;
            t:=convert(T,string);
            Printer:-Print(t,";\n");
            Printer:-Print("  if (",_passed[1],
                           ")\n    { ",t," = ",_passed[2],"; }\n");
            for i from 3 to _npassed-2 by 2 do
                Printer:-Print("  else if (",_passed[i],")\n    { ",
                               t," = ",_passed[i+1],"; }\n");
            end do;
            Printer:-Print("  else { ",t," = ",_passed[_npassed],"; }");
        end proc,
    numeric=double)
):

T:=`tools/genglobal`('s'):

newmyp := FromInert(subsindets(ToInert(eval(myp)),'specfunc(anything,_Inert_LOCALSEQ)',
           z->_Inert_LOCALSEQ(op(z),
                              _Inert_DCOLON(_Inert_NAME(convert(T,string)),
                                            _Inert_NAME("numeric",
                                               _Inert_ATTRIBUTE(_Inert_NAME("protected",
                                               _Inert_ATTRIBUTE(_Inert_NAME("protected")
          ))))))));

Translate(newmyp, language="NewC");
         newmyp := proc(x::numeric)
         local result::numeric, s::numeric;
           result := piecewise(3 < x, 3*x, 2 < x, 2*x, 1 < x, x, 0)
         end proc;

double newmyp (double x)
{
  double result;
  double s;
  result = s;
  if (0.3e1 < x)
    { s = 0.3e1 * x; }
  else if (0.2e1 < x)
    { s = 0.2e1 * x; }
  else if (0.1e1 < x)
    { s = x; }
  else { s = 0; };
  return(result);

If you rerun the last three statements above (from the assignment to T, through to the Translate call) then you should see a new temp variable used, such as s0. And then s1 if repeated yet again. And so on.

Perhaps this will give you some more ideas to work with.

acer

@asghar 

palin:=proc(T::list)
local i, n;
   n := nops(T);
   for i from 1 to n/2 do
      if T[i] <> T[n-i+1] then
         return false;
      end if;
   end do;
   return true;
end proc:

@asghar 

palin:=proc(T::list)
local i, n;
   n := nops(T);
   for i from 1 to n/2 do
      if T[i] <> T[n-i+1] then
         return false;
      end if;
   end do;
   return true;
end proc:

Thanks for the interesting read.

I wonder whether the quality of the embedded images could be improved, so that they are a bit sharper. If you'd like to post any Maple code that you might have used to generate them then it might be possible to alter the method. (...it looks like fun, but it'd be easier to not have to start from scratch on it.)

acer

@serena88 The procedure is returning the last "result" that it computes, from its last statement.

You can have a procedure return a sequence of results. Like so,

restart:
makeEOM:=proc(elenum)
local i, node, nodes, L, E0, E0M,E2,E2M;
   nodes:=elenum*2+1:
   L:=evalf((Pi*2)/(elenum*2)):
   E0:=Matrix([[L/3,2*L/3,L/3],[2*L/3,11*L/15,2*L/3],[L/11,2*L/3,L/110]]):
   E2:=Matrix([[L/13,2*L/13,L/13],[2*L/3,11*L/5,2*L/3],[L/11,2*L/13,L/11]]):   
   E0M:=Matrix(nodes);
   E2M:=Matrix(nodes);
   for i from 1 to elenum do
      node:=(2*(i-1))+1;
      E0M[node..node+2,node..node+2]:=E0M[node..node+2,node..node+2]+E0;
      E2M[node..node+2,node..node+2]:=E2M[node..node+2,node..node+2]+E2;
   end do:
   E0M, E2M;
end proc:

makeEOM(2); # returns a sequence of the two result Matrices

You can also use Maple's ability to do multiple assignments simultaneously (ie., concurrently),

e0m[2],e2m[2] := makeEOM(2);

And, once any pair are saved in the tables e0m and e2m, you could access them seperately,

e2m[2];
e0m[2];

@serena88 The procedure is returning the last "result" that it computes, from its last statement.

You can have a procedure return a sequence of results. Like so,

restart:
makeEOM:=proc(elenum)
local i, node, nodes, L, E0, E0M,E2,E2M;
   nodes:=elenum*2+1:
   L:=evalf((Pi*2)/(elenum*2)):
   E0:=Matrix([[L/3,2*L/3,L/3],[2*L/3,11*L/15,2*L/3],[L/11,2*L/3,L/110]]):
   E2:=Matrix([[L/13,2*L/13,L/13],[2*L/3,11*L/5,2*L/3],[L/11,2*L/13,L/11]]):   
   E0M:=Matrix(nodes);
   E2M:=Matrix(nodes);
   for i from 1 to elenum do
      node:=(2*(i-1))+1;
      E0M[node..node+2,node..node+2]:=E0M[node..node+2,node..node+2]+E0;
      E2M[node..node+2,node..node+2]:=E2M[node..node+2,node..node+2]+E2;
   end do:
   E0M, E2M;
end proc:

makeEOM(2); # returns a sequence of the two result Matrices

You can also use Maple's ability to do multiple assignments simultaneously (ie., concurrently),

e0m[2],e2m[2] := makeEOM(2);

And, once any pair are saved in the tables e0m and e2m, you could access them seperately,

e2m[2];
e0m[2];

Note that .ind file extensions are old and have no longer been advocated (for many major releases, now). Unfortunately some relevent help-files have still mentioned then in quite recent releases.

Basically, many years ago usual to have a pair of files that went together, with filename extensions .lib and .ind

But the modern way to use Maple Library archives is to have just the single file, with filename extension .mla

acer

It sounds like you are on the right track.

If your module's sources are long, valuable to you, or hard to reproduce, then I suggest keeping them as plaintext.  

For example, the module definition could be a text file like this,

mymodule := module() option package;
   export a,b,c;
   local e,f,g,ModuleLoad;
   a := proc()...
   e := proc()...
   ... and so on ...
end module:

# optionally build .mla
# and optionally savelib mymodule

Your master build worksheet could then be something trivially simple like the single line of code,

   read "build_mymodule.mpl";

or you could have a short command to do that, defined in your initialization file.

An important advantage of storing your valuable source code in plaintext files if that you can use a revision control system to store meaningful source-diffs, as you develop.

You could also split up the text source, for easier management and editing of involved projects. An easy enhancement of the above is to us Maple's $include directive to read the source of each module local/export. The module defn could then become more like,

mymodule := module() option package;
   export a,b,c;
   local e,f,g,ModuleLoad;
   $include path_to_text_source_of_a
   $include path_to_text_source_of_e
   ... and so on ...
end module:

You could also wrap the .mla creation and `savelib` call (with a condition, or a $ifdef) so that you could load your current version into a running session without neccesarily saving it. Really, there are all kinds of fancy variations, and scripting possibilities.

Another important consideration for keeping valuable source code as plaintext is that it could always be recovered without access to Maple, and file corruption chances are next to nil.

acer

It sounds like you are on the right track.

If your module's sources are long, valuable to you, or hard to reproduce, then I suggest keeping them as plaintext.  

For example, the module definition could be a text file like this,

mymodule := module() option package;
   export a,b,c;
   local e,f,g,ModuleLoad;
   a := proc()...
   e := proc()...
   ... and so on ...
end module:

# optionally build .mla
# and optionally savelib mymodule

Your master build worksheet could then be something trivially simple like the single line of code,

   read "build_mymodule.mpl";

or you could have a short command to do that, defined in your initialization file.

An important advantage of storing your valuable source code in plaintext files if that you can use a revision control system to store meaningful source-diffs, as you develop.

You could also split up the text source, for easier management and editing of involved projects. An easy enhancement of the above is to us Maple's $include directive to read the source of each module local/export. The module defn could then become more like,

mymodule := module() option package;
   export a,b,c;
   local e,f,g,ModuleLoad;
   $include path_to_text_source_of_a
   $include path_to_text_source_of_e
   ... and so on ...
end module:

You could also wrap the .mla creation and `savelib` call (with a condition, or a $ifdef) so that you could load your current version into a running session without neccesarily saving it. Really, there are all kinds of fancy variations, and scripting possibilities.

Another important consideration for keeping valuable source code as plaintext is that it could always be recovered without access to Maple, and file corruption chances are next to nil.

acer

A (less flashy) alternative is,

a:=12+10*x^4+7*x^3-89*x^2+65*x:

r:=[fsolve(a)];

     -3.624808208, -0.1524813627, 1.095553748, 1.981735823

seq(eval(a,x=t),t=r);

                    -7       -9      -8      -7
                5 10  , -7 10  , 3 10  , 1 10  

A (less flashy) alternative is,

a:=12+10*x^4+7*x^3-89*x^2+65*x:

r:=[fsolve(a)];

     -3.624808208, -0.1524813627, 1.095553748, 1.981735823

seq(eval(a,x=t),t=r);

                    -7       -9      -8      -7
                5 10  , -7 10  , 3 10  , 1 10  
First 413 414 415 416 417 418 419 Last Page 415 of 597