Stephen Forrest

Mr. Stephen Forrest

476 Reputation

14 Badges

22 years, 200 days
Software Architect

Social Networks and Content at

Maple Application Center

MaplePrimes Activity

These are answers submitted by Stephen Forrest

There is a space after 20230505 in your URL, perhaps just a copy-paste artifact. When I delete that and execute the URL:-Get call, I get a ByteArray object corresponding to a JPEG encoding of the image, as expected.  Perhaps that's all that's wrong here?

To further confirm the result is a JPEG, the following also works for me and implicitly uses URL:-Get:


Thanks for your report. In answer to your question, there were some significant modifications to the Logic package in Maple 2016, which they are described in the feature page What's New in Maple 2016: Logic and in the in-product help page updates,Maple2016,Logic.

The main change was the inclusion of highly efficient external routines for testing boolean satisfiability, and the Logic:-Tautology command was modified to make use of that: a boolean formula phi is a tautology if and only if there is no satisfying assignment to not(phi).

Regrettably this change apparently also introduced this behaviour, which is a bug. Thanks for drawing our attention to it and we'll try to get it addressed in an upcoming Maple patch release.

This is documented, though admittedly not so clearly (mea culpa there). Some information can be found on the help page ?CodeGeneration,LanguageDefinition,Printer,LanguageAttribute.

In short, you are correct that there is a name validity test applied to the original names from Maple. If that test fails, i.e. if the original Maple names will not be valid identifiers in the target language (in this case Matlab), they are automatically replaced.

The validity test is controlled by a "language attribute" called Name_IsValid, a short description of which appears in a table in the above link. In the following I'll explain how you can view and change that setting.

Viewing the Validity Test

To view the Name_IsValid attribute for CodeGeneration[Matlab]:

> showstat( CodeGeneration:-LanguageDefinition:-Get("Matlab"):-Printer:-GetLanguageAttribute("Name_IsValid") );

attribtab["Name_IsValid"] := proc(x)
1    length(x) <= 31 and StringTools:-RegMatch("^[A-Za-z][A-Za-z0-9_]*$",x)
end proc

The condition here takes the input variable name (as a string), checks that it is 31 characters or less, that it starts with a letter, and that all subsequent characters are letters, digits, or underscores.  If that condition is false, that variable will be replaced.

Changing the Validity Test

Now, on to the next part: how to change it. To use a different condition, first let's start with an example where name replacements are made now:

> p := proc(`X.1`, `X.2`) `X.1` * `X.2` end proc);

p := proc(`X.1`, `X.2`) `X.1` * `X.2` end proc)

> CodeGeneration:-Matlab(p);

Warning, the following variable name replacements were made: X.1 -> cg, X.2 -> cg1
function preturn = p(cg, cg1)
  preturn = cg * cg1;

We can then define new language, an extension of Matlab, which we'll call MyMatlab. This will be like Matlab in every way but for which every identifier is valid. This can be accomplished in one line with:

> CodeGeneration:-LanguageDefinition:-Define( "MyMatlab", extend="Matlab", SetLanguageAttribute("Name_IsValid"=true) );

That's it; the new language is defined. The "Name_IsValid"=true part simply says "always return true from every validity check". To see MyMatlab in action on our example you can just do:

> CodeGeneration:-Translate( p, language="MyMatlab" );
  function preturn = p(X.1, X.2)
preturn = X.1 * X.2;

If you want to use this frequently, you can of course then define:

> MyMatlab := () -> CodeGeneration:-Translate(args, language="MyMatlab" );

You can then use MyMatlab in much the same way as you would use CodeGeneration:-Matlab:

> MyMatlab(p);
  function preturn = p(X.1, X.2)
preturn = X.1 * X.2;

Note though the Name_IsValid setting is what it is for a reason: if you change it, the identifiers you produce may not be valid for Matlab. In this case, they specifically are not.

When I run your example, the variable data is assigned to a string which is the HTML source for the page in question; that is the expected behaviour for this command.

> status, data, headers := HTTP:-Get(""):
> data[1..90];
    "<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "">"

If you want to extract the table data from that, you will have to parse the HTML.

For this specific case you might be able to achieve that with some regular expression code, however in general it would be cleaner to use another format. It so happens that Yahoo Finance also has APIs for producing stock quote results in more easily parseable formats like JSON. For an example of that API see this stackoverflow thread.

I should mention that Maple 2015 has a number of tools to make this kind of activity easier, including an improved engine for HTTP operations which also supports SSL, built-in facilities for parsing JSON, and immediate access to current and historical stock quotes.

It's not too difficult to write a JSON parser usable by Maple 17; if you're interested in that avenue, let me know.

As Rouben Rostamian notes, the code for finding approximate solutions for systems of differential equations (a.k.a. 'dsolve/numeric') needs you to specify an initial condition for a first-order equation such as this.

For example:

> f1 := {cos(x*exp(2*y(x))-y(x))*(diff(y(x), x))=exp(y(x))*sin(2*x), y(0) = 0};

> result := dsolve(f1, numeric);

proc(x_rkf45) ... end proc

> result(.50);

[x = .50, y(x) = .281853320681254]

An STL file represents a collection of triangles including surface orientation, so I'm not sure why you'd want it as a set of points.  Nevertheless there are a couple simple ways to do this conversion.

Let's start by importing an STL. Take the following image I found on Thingiverse: Maple Leaf Cookie Cutter.

We can click on the Download this Thing button and copy the URL corresponding to the STL file, in this case

Then import it into Maple with the following command:

p := plottools:-importplot(""):

To see this readered using polygons:



Next, for this case to convert the polygons to points we can simply perform the following transformation using the eval command.  Keep in mind all this is doing is converting each triangle into a set of three points, so there will be redundancies in the resulting structure as points are shared between adjacent triangles.

q := eval(p, POLYGONS=(u->POINTS(u))):




You can use the Matlab:-FromMFile command for this task.

> Matlab:-FromMFile("/home/sforrest/Desktop/MyMatlab.m");

Note that because Maple does not have a complete implementation of the entire MATLAB function library, the Matlab:-FromMFile command cannot be guaranteed to produce code which is functionally identical to the MATLAB input.

If your MATLAB code is in a string, you can use Matlab:-FromMatlab.  For example:

> Matlab:-FromMatlab("[1 2 ; 3 4]");


If you are always looking inside a list, you can just use ListTools:-Search for this:

ListTools:-Search( "banana", ["apple", "banana", "orange", "pear"] );


If you're set on writing your own procedure, you can use the member command with a third argument p:

indexOf := proc(x, L) local p;
     if member(x,L,'p') then p else FAIL end if;
end proc:

Here's an example:

fruits := ["apple", "banana", "orange", "pear"];

indexOf( "banana", fruits );


indexOf( "pear", fruits );


indexOf( "grapefruit", fruits );


Since your Array is two-dimensional, you should be able to convert it to a Matrix and use the ExportMatrix and ImportMatrix commands.  The following is from Maple 18:

Exporting to CSV (comma-separated values)

> A := Array(1..5, 1..6, (i,j)->i*j );

Matrix([[1, 2, 3, 4, 5, 6], [2, 4, 6, 8, 10, 12], [3, 6, 9, 12, 15, 18], [4, 8, 12, 16, 20, 24], [5, 10, 15, 20, 25, 30]])

> ExportMatrix("myfile.csv", Matrix(A), target=csv);


Importing from CSV

> ImportMatrix("myfile.csv");

Matrix([[1, 2, 3, 4, 5, 6], [2, 4, 6, 8, 10, 12], [3, 6, 9, 12, 15, 18], [4, 8, 12, 16, 20, 24], [5, 10, 15, 20, 25, 30]])


The easiest method is to store your computed results in a Maple archive file.

To do this, first from within, create a Maple archive and save only those variables you care about.  For example, suppose we want to save VarA and VarB but don't care whether VarC is saved.

VarA := [apple, banana, cherry];
VarB := [elderberry, fig, guava];
VarC := [jackfruit, kiwi, lemon];
LibraryTools:-Save(VarA, VarB, "MyNewArchive.mla");

Note we do not save VarC in the above since, as we said, we didn't care about it.

Next, from within, add the line

libname := libname, "MyNewArchive.mla";

You will now be able to access VarA and VarB inside Part2 without any further work.

(Another way to do this is with the command DocumentTools:-RunWorksheet, but the archive approach is probably the better one for your situation.)

You probably don't want to get all combinations of this system of polynomials.  Running your input up to the point where you invoke nops(polylistresult) for the last time shows that nops(polylistresult)=1536.

At this point, instead of calling combinat[permute](polylistresult,3) let's examine just how big the resulting structure would be if it were computed:



That is, the resulting list would have more than three billion elements. I expect you are only interested in a subset of that output satisfying some criterion. Can you elaborate on what you hope to do with the list of permutations?

Stephen Forrest
Product Manager for Maple

Creating a Maple hash table is very simple:

T := table();

To insert a key/value pair into it, just use square-bracket indexing and assignment. You say you want the key to be a function, and the value a list of things. Let's go with that: for our key we'll pick sin(x) and our value [apple,banana,cherry].

T[sin(x)] := [apple, banana, cherry]:

To retrieve the value just use square-bracket indexing:


To test if a particular key is in the table, use assigned:

if not assigned(T[cos(x)]) then
    T[cos(x)] := [jackfruit, kumquat, lingonberry];
end if;

To retrieve a list of the key-value pairs as equations, use indices:

indices(T, pairs);

sin(x) = [apple,banana,cherry], cos(x) = [jackfruit,kumquat,lingonberry]

For additional documentation on hash tables in Maple see the online help for table.

@wingjammer Here's another implementation of an import routine, one not requiring a loop. For simplicity I assume the same filename as tomleslie:

data := FileTools:-Text:-ReadFile("testMat.txt");
ParseLine := proc(line) uses StringTools;
    if line="" then NULL
    else map(parse,[RegSplit(" *",RegSubs("^ *"="",RegSubs(" *$"="",SubstituteAll(line,"|",""))))])
    end if;
end proc:

While either implementation works fine for this case, if you still use Macaulay2 you might be better served by putting your data in some storage format there, rather than a presentation format. Usually those are easier to parse reliably.  I can't speak to what Macaualay has by way of matrix storage formats but this page looks useful.

As acer has suggested, the answer is the URL package in Maple 18, which supports HTTP, HTTPS, and FTP.  You could fetch a Google Translate URL in the following way:

s := "The quick brown fox jumps over the lazy dog":

result := URL:-Get( StringTools:-FormatMessage("", s) );

Please note however that the translated text does not appear in the HTTP response from Google.  It appears that they show that to you by means of some Javascript embedded in the page.

If you want to perform translations programmatically using Google Translate, they have an API for that described here:


First, the ExcelTools:-Import command exists exactly to import data from an Excel workbook into a Maple Matrix, so you don't need to copy and paste.

Next, let's assume you have this a Matrix, e.g.
M := <<1,2,3,4,5,6,7>|<1,7,8,9,10,14,20>>;


You can access column 1 as M[..,1], column 2 with M[..,2], etc:


Similarly you can access, e.g. row 2 with M[2,..]:

If for some reason you prefer working with lists, you can convert it easily:
convert(M, listlist);
[[1, 1], [2, 7], [3, 8], [4, 9], [5, 10], [6, 14], [7, 20]]Hope that helps.

1 2 3 Page 1 of 3