Carl Love

## 25796 Reputation

10 years, 349 days
Himself
Wayland, Massachusetts, United States
My name was formerly Carl Devore.

## Several possible interpretations...

There are several possible interpretations of your problem. You said "a bunch of (x,y) coordinates". The first distinction that must be made is whether "a bunch" is 4 or more than 4. Possibly a second distinction must be made between one degree-3 polynomial or multiple degree-3 polynomials. All of these situations can be handled by 1 or 2 short Maple commands.

The interpretations:

1. You have exactly 4 points. This is the situation hinted at by Rouben's Answer. There is a unique polynomial of degree at most three that passes exactly through those points. The polynomial's coefficients can be determined by the process outlined by Rouben, or you can simply use the Maple command CurveFitting:-PolynomialInterpolation.

2. You have more than 4 points, but you know that you want a single degree-3 polynomial that goes through them all. This can't necessarily be done, but you can easily check whether it can. If it can be done, any subset of 4 of the points will give the same result (allowing some reasonable bounds for round-off error). Pick any 4, apply case 1, and see if the rest of the points fit.

3. You have more than 4 points, and you want the degree-3 polynomial that "best fits" all of them. The polynomial will not necessarily go exactly through any of the points; indeed, it's likely to not go through any exactly. This is called linear regression; the Maple command is Statistics:-LinearFit.

4. You have more than 4 points, and you want a smooth piecewise curve that goes exactly through them such that each "piece" is a polynomial of degree at most 3. This is called cubic spline interpolation; the Maple command is CurveFitting:-Spline.

## entries command...

Like this:

plots:-display([entries(IP)])

Edit: As pointed out by @mmcdara below, the above should be

plots:-display([entries(IP, nolist)])

## Yes, it's a bug...

Yes, the death of a kernel process due to a simple command with bad syntax is certainly a serious/critical bug. Since your printf command is syntactically nonsense, you should get a simple error message informing you of that.

## Folding procedures taking an arbitrary n...

I am writing this Answer to address your overall, titular Question, which is essentially about generalizing f@@n to situations where f takes many arguments and those arguments are changing for each application of f. Such generalizations are called folding f. You may read about it on help page ?fold; however, in this particular case I'm not going to use the commands foldr or foldl documented on that page but rather a new option to seq that does essentially the same thing more efficiently.

I am not writing this Answer because I think that folding is the best way to implement the particular situation that you present---the Answers by Kitonum and especially Acer have better methods for that situation. Nonetheless, your main Question is essentially about folding.

```L:= "[(0, 1), (1, 2), (1, 10), (2, 3), (3, 4), (4, 5), (4, 9), (5, 6), (6, 7),"
" (7, 8), (8, 9), (10, 11), (11, 12), (11, 16), (12, 13), (13, 14),"
" (14, 15), (15, 16)]"
:
#L1 and L2 could be lists, but simple strings are enough in this case:
L1:= "()[]": L2:= "{}{}":
X:= seq['fold'= (StringTools:-SubstituteAll, L)]('L1[i], L2[i]', i= 1..length(L1));
X := "{{0, 1}, {1, 2}, {1, 10}, {2, 3}, {3, 4}, {4, 5}, {4, 9}, {5, 6}, {6, 7}, {7, 8}, {8, 9}, {10, 11}, {11, 12}, {11, 16}, {12, 13}, {13, 14}, {14, 15}, {15, 16}}"

```

This is more efficient than foldr or foldl because seq (ironically) does not create any sequence when used like this; it just feeds arguments to the accumulator procedure SubstituteAll. In contrast, using foldr or foldl requires first constructing the entire sequence of arguments before calling the command.

## Constructor for the multiplicative group...

Here's a constructor for the multiplicative group modulo n, regardless of whether n is prime:

```#Constructor for the multiplicative group modulo n
MultGroup:= (n::And(posint, Not(1)))->
local G:= select(k-> igcd(n,k) = 1, [\$n]), o:= nops(G), J:= table(G =~ [\$o]);
(
GroupTheory:-CayleyTableGroup(
Matrix(o\$2, (i,j)-> J[modp(G[i]*G[j], n)], shape= symmetric),
labels= G, check= false
),
subs(_o= o, (k::integer[1.._o])-> G[k])
)
:
(g,G):= MultGroup(12);
g, G := < a Cayley table group with 4 elements >, k-> G[k]

GroupTheory:-DrawCayleyTable(g, labels= G);``` ## Simple matrix arithmetic...

All you need is this:

```ABC:= <
-3,  1,  2;  # your A as a matrix row
-2, -1,  1;  # ...  B ...
0,  3, -3   # ...  C ...
>:
alpha:= <2 | -1 | 1>:  # your weights as a row vector

```

The spacing and line breaks in the matrix input are only for enhanced readability. You could just as well enter it as

ABC:= <-3, 1, 2; -2, -1, 1; 0, 3, -3>:

## X^n...

Then all you need to type is

X^n

• Where can I see  in the lprint output that the first argument is of type uneval?

Since sqrt(x) is inherently unevaluated, you can't explicitly see that in this case. If you replace x by 4, then you'll see the difference.

• Is sqrt(x) the first argument?

Yes. For any function f(a1, a2, ..., an)a1 is the first argument.

• What does mi do?

It displays a variable in italic. All the Typesetting commands beginning with m are from the MathML language, and you can find them documented on numerous public websites.

## DataFrame...

Like this:

M:= DataFrame(<a,b,c; b,c,a; c,a,b>, rows= [a,b,c], columns= [a,b,c]);

M[b,c];

In the default prettyprinted display of a DataFrame, the displayed first row is the column indices and the displayed first column is the row indices. These mustn't be confused with the entries of the matrix itself.

## Maple's catenation operators...

The operation that you want to perform is called catenation. Maple has essentialy three catenation operators: The first two that I'll discuss are a binary infix operator || (two vertical bars) and a functional prefix operator cat. Those two are mostly interchangeable, but there are some quirky differences regarding which operands are evaluated and which are just taken verbatim. I'll get to the 3rd catenation operator(s) later.

Definitions of some "types" that are relevant to your main question:

"indexed" vs. "suffixed": First, some vocabulary about some formal terms in Maple's "type" system that are relevant to this. I'm doing this because although know perfectly well what you mean by "indexed", your usage of that word is not consistent with its formal definition in Maple. Thus, there's a (small) risk of causing confusion by using that word as you have. A better word would be suffixed, and fortunately that word means exactly the same thing in common English as its formal definition in Maple (see help page ?type,suffixed).

"symbols" as "variables"; "pure" symbols: What you're calling "variables" are formally known as objects of type symbol. There's not much risk of confusion if you say "variable" because that word has no formal Maple-wide definition (it often has command-specific definitions, such as a variable with respect to which a derivative is computed). However, note that named constants such as Pi are also considered symbols, although they don't "vary". As you're very likely aware, Maple's symbols can be used quite effectively either with or without assigned values. The ability to manipulate "pure" (i.e., unassigned) symbols is what makes Maple a Symbolic Computation System. In many computer languages, the tokens that represent "variables" are called "identifiers" (which also has no formal definition in Maple).

"names", "indexed names": If you take a symbol such as your Rand it has no assigned value (very important!), and you follow it by a pair of square brackets containing a comma-separated sequence of zero or more items (of any type whatsoever), then you've created what Maple calls an indexed name (i.e., it has type indexed and type name). This can be followed by more sequences of indices in square brackets and it'll still be an indexed name. A plain (unindexed) symbol is also considered a name (see help page ?name). All names could be considered "variables", since they can be assigned values; thus the word name is much more common in Maple discussions than symbol. Names that aren't constant are Maple's primary representation of the abstract mathematical concept of "variable". But for our main topic, catenation, we can only use symbols. A vast number of Maple objects other than names can be indexed with square brackets, which is why it's important to know that your symbol is unassigned before you try to make an indexed name from it. Not heeding this advice is a leading cause of newbie errors reported here on MaplePrimes. (See help pages ?type,indexed, ?type,name, and ?type,symbol.)

Examples: R, R1, _R, R_1, and R__1 are symbols. R[]RR[1,x], and R[x] are indexednames, and Not(symbol).

All names formed by any of the forms of catenation are global! That's true even if the pieces that are put together are local! But inappropriate use of indexed names is a far more common source of errors than is the globalness of catenations.

By way of contrast, an indexed name is local as long as its beginning symbol is local, and global if its beginning symbol is global.

Catenation:

The II binary infix operator: Referring to the specific example from your question, if your n is either explicitly a positive integer or is assigned a specific positive integer, then what you asked for can be done as simply as this:

R||(1..n)

The suffixes need not be positive integers, nor in order. These all work:

R||(5, 7, 3);  R||(start, finish);  R||(a,b,c);
R||(1,2,3)||(a,b,c); #This makes 9 symbols.
S:= {seq(2*k, k= 1..5)};  R||(S[]);

If has an assigned value, it's ignored.

See help page ?||.

cat: You can also do

cat(R, 1..n);  cat~(R, [a,b,c])[];  cat~(R, S)[];
cat~(R, [1,2,3], [a,b,c])[]; #This makes 3 symbols.
cat(R, 1..3, a..c); #This makes 9 symbols.

Warning: For cat, if the first argument R has an assigned value, it's NOT ignored.

The help page ?|| "discourages" you from using ||, advocating cat instead. I strongly disagree with that advice. Both commands have numerous legitimate uses. In the cases where either can be used, I use ||.

Both || and cat work with both symbols and strings. Whether the resulting object is a symbol or string depends on the type of the first argument or operand.

nprintf, sprintf: These are the third way that I mentioned earlier. Sophisticated catenations using format codes can be made with these commands. The syntax is a generalization of sprintf from the C language or FORMAT from Fortran. The only difference between them is that nprintf creates symbols and sprintf creates strings.

Subscripting:

You can use catenation to create symbols which will prettyprint (i.e., display in Maple's 2D GUI output display (the centered and mostly italicized blue output you see in your worksheets)) with subscripts. This is done by including __ (two underscores) in the symbol. Examples:

R__1;  R__||(1..3);  t__start;

(The 1st and 3rd examples are ordinary symbols, not catenations).

This is usually the best way to avoid those common newbie errors caused by the incorrect use of indexed names that I mentioned earlier. Much documentation refers to these as "atomic" variables. I disapprove of that term for the sole reason that atomic has a long-standing formal definition as a Maple type and that definition conflicts with the usage for subscripting because all names, whether indexed or plain symbol are type atomic.

## save anames(...), ......

It can be done with the anames command (i.e., assigned names) like this:

save ({anames}(user) minus {anames}(procedure))[], "some_file_name";

## Empty set in Maple 2022.2...

In Maple 2022.2, your indets command returns the empty set, which I guess is what you mean by "proper form".

## nops([op](1, eval(...))) for -> procedur...

That's difficult (sometimes impossible) to do in the the most-general cases, but easier in the cases that I think you're interested. The error message comes from line 52 of `D/procedure`, so you can read around there for a general answer. It looks like you'll need to read at least lines 25-65 to understand the general case.

The simpler case: operator procedures: The parameter sequence of a procedure f can be extracted via op(1, eval(f)). If f is also an operator (which'll always be true if it's constructed with ->), the parameters can't be "too complicated". All of the following are disallowed:

• the end-of-parameters marker,
• keyword parameters,
• parameters with default values assigned directly within the parameter sequence.

So, those easier cases can be handled by

Nparams:= (f::And(operator, procedure))-> nops([op](1, eval(f))):
q:= (u,v)-> u^2+v^2:
Nparams(q);

## op(4, ...): The array of neighborhoods...

The information about a graph G's edges is stored in an Array as op(4,G). Although this structure doesn't seem to have a formal documented name, I find it to be the most convenient and most efficient way to access the edge infomation from a graph. Suppose that there are n vertices. Then op(4,G) is an Array indexed 1..n such that A[k] is the set of the indices of the neighbors of the kth vertex. In the code below, I construct this Array as a means to construct your graph. However, if the graph was constructed some other way, this Array could still be accessed as op(4,G)

 > restart:
 > GT:= GraphTheory:
 > Vs:= [x,y,z,w]:
 > n:= [\$nops(Vs)]:

 > Popvs:= [-2, 1, 6, 3]:
 > Nbs:= Array([{2}, {1,3,4}, {2,4}, {2,3}]):
 > X:= GT:-Graph(Vs, Nbs); > GT:-SetVertexPositions(X, [[0,0], [1,0], [1.5,1], [2,0]]):
 > newX:= GT:-RelabelVertices(X, [seq](cat(Vs[i], "=", add(Popvs[[i, Nbs[i][]]])), i= n)); > GT:-DrawGraph(newX); > 