Joe Riel

9660 Reputation

23 Badges

20 years, 9 days

MaplePrimes Activity


These are replies submitted by Joe Riel

One could just use lprint, though I wouldn't say it was better. Better to just return the sequence, at least that way it can be further processed.
I'm not sure what you mean. Per your spec, you only want one integer returned, so commas don't make sense. Note that print only causes a display, it doesn't return anything, so further processing (with other procedures) is not possible. If you want the procedure to operate on several sets, and return a sequence of values, then do something like
smallest_integer := proc() ... end proc:
seq(smallest_integer(s), s=[{a,b,1}, {d,e,2}, {3,4}]);
if smallest_integer returned the smallest integer from each set, then that would return the expression sequence
 1, 2, 3
I'm not sure what you mean. Per your spec, you only want one integer returned, so commas don't make sense. Note that print only causes a display, it doesn't return anything, so further processing (with other procedures) is not possible. If you want the procedure to operate on several sets, and return a sequence of values, then do something like
smallest_integer := proc() ... end proc:
seq(smallest_integer(s), s=[{a,b,1}, {d,e,2}, {3,4}]);
if smallest_integer returned the smallest integer from each set, then that would return the expression sequence
 1, 2, 3
Yes, I realized that shortly after posting. Thanks for clarifying. I was interested in what the poster asked for (generating a procedure from an expression), not what he meant (evaluating an expression at a point). As you say, eval is the way to evaluate an expression at a point, usually better than subs and much better than unapply followed by application. The point of my response was mainly pedalogical, to show how to restrict the values returned by indets to those of interest.
Yes, I realized that shortly after posting. Thanks for clarifying. I was interested in what the poster asked for (generating a procedure from an expression), not what he meant (evaluating an expression at a point). As you say, eval is the way to evaluate an expression at a point, usually better than subs and much better than unapply followed by application. The point of my response was mainly pedalogical, to show how to restrict the values returned by indets to those of interest.
As has been mentioned, it is a programming convenience, but a useful one. There is also rcurry, which "curries" from the right. The name curry is not related to Indian cooking, rather it comes from the name of the logician Haskell Curry. Any other historical figures whose both first and last names are used in math/programming (Haskell is a functional language).
As has been mentioned, it is a programming convenience, but a useful one. There is also rcurry, which "curries" from the right. The name curry is not related to Indian cooking, rather it comes from the name of the logician Haskell Curry. Any other historical figures whose both first and last names are used in math/programming (Haskell is a functional language).
Here's a small module that uses that technique to count stuff.
Counter := module()
export count, tally, reset;
local zap;
    zap   := proc(v) procname(v) := 1; 0; end proc:
    reset := proc() forget(zap); end proc;
    count := proc(v) zap(v) := zap(v)+1; end proc:
    tally := proc(v) zap(v) := zap(v); end proc;
end module:
But they are not the exact same string. The 1D case is the string "1 + 2", the 2D case is "1 + 2" (the + was converted by the GUI input to `+'). To Maple's engine those are entirely different strings. The real question is, how does one enter the string "1 + 2" in 2D mode? One way is to use Maple's automatic catenation of adjacent strings separated by white space. Type
bar := "1 &plus" "; 2";
That will work in either 1D or 2D mode. Use lprint(bar) to verify that the input string is what you want.
For real TTY junkies, try Preview(img, output=text);
Your technique can be "improved" for the special case in which the set elements consist of integers in a known range. The toy graphs have this quality. I don't expect that your real application, or most uses, do. The motivation was to eliminate the call to zap, a non-builtin function, in the inner loop. The technique is to use an rtable with indices in the known range of integers and initialized to the index values (Z[1] = 1, Z[2] = 2, etc.). Elements are zapped by assigning their entries to NULL. The new code is procedure BFS4. To make the comparison as fair as possible, I've included BFS22, which uses the double seq optimization that you mentioned.
BFS1 := proc(G, v)
local S, X, i, j, zap;
    zap := proc(v) procname(v) := NULL; v end proc;
    forget(zap);
    S := table();
    X := map(zap, {v});
    for i while nops(X) > 0 do
        S[i] := X;
        X := {seq(op(map(zap, G[j])), j=X)};
    end do;
    [seq(S[j], j=1..i-1)];
end proc:

BFS22 := proc(G, v)
local S, X, i, j, k, zap;
    zap := proc(v) procname(v) := NULL; v end proc;
    forget(zap);
    S := table();
    X := [zap(v)];
    for i while X <> [] do
        S[i] := X;
        X := [seq(seq(zap(k), k=G[j]), j=X)];
    end do;
    [seq(S[j], j=1..i-1)];
end proc:

BFS4 := proc(G, v, n)
local S, X, i, j, k, Z;
    Z := rtable(1..n, i->i);
    S := table();
    X := {v};
    Z[v] := NULL;
    for i while X <> {} do
        S[i] := X;
        X := {seq(seq(Z[k], k=G[j]), j=X)};
        for k in X do
            Z[k] := NULL;
        end do;
    end do;
    [seq(S[j], j=1..i-1)];
end proc:
Here is the comparison using graphs created by SeqGraph
                     +---- Timing (sec) -----+---- Memory (MiB) --------+
n=10^3, m=10         |  Maple    |   Total   |   Used     |    Alloc    | GC times
---------------------+-----------+-----------+------------+-------------+---------
BFS1                 |     0.03  |     0.03  |     0.59   |      0.12   |    0
BFS22                |     0.02  |     0.02  |     0.41   |      0.31   |    0
BFS4                 |     0.02  |     0.01  |     0.26   |      0.19   |    0
---------------------+-----------+-----------+------------+-------------+---------
n=10^4, m=10                                                                      
---------------------+-----------+-----------+------------+-------------+---------
BFS1                 |     0.26  |     0.26  |     5.26   |      2.81   |    0
BFS22                |     0.22  |     0.23  |     3.20   |      1.94   |    0
BFS4                 |     0.16  |     0.16  |     2.32   |      1.06   |    0
---------------------+-----------+-----------+------------+-------------+---------
n=10^5, m=10                                                                      
---------------------+-----------+-----------+------------+-------------+---------
BFS1                 |     3.61  |     5.44  |    48.72   |     21.87   |    1
BFS22                |     2.84  |     3.04  |    28.50   |     18.12   |    0
BFS4                 |     1.97  |     2.08  |    23.63   |     11.69   |    0
That makes sense. Thanks for sharing this technique, it is quite ingenious. A neat addition to the toolbox.
This time I tried testing with a nonrandom graph, using
SeqGraph := proc(n::posint, m::posint)
local i,G,k;
    G := table();
    for i to n do
        G[i] := {seq(modp(k-1,n)+1, k=i..i+m)}
    end do;
    eval(G);
end proc:
The results were significantly different:
                     +---- Timing (sec) -----+---- Memory (MiB) --------+
n=10^2, m=10         |  Maple    |   Total   |   Used     |    Alloc    | GC times
---------------------+-----------+-----------+------------+-------------+---------
BFS1                 |     0.00  |     0.01  |     0.14   |      0.06   |    0
BFS2                 |     0.01  |     0.01  |     0.15   |      0.12   |    0
BFS3                 |     0.01  |     0.00  |     0.02   |      0.00   |    0
---------------------+-----------+-----------+------------+-------------+---------
n=10^3, m=10                                                                      
---------------------+-----------+-----------+------------+-------------+---------
BFS1                 |     0.03  |     0.03  |     0.59   |      0.19   |    0
BFS2                 |     0.02  |     0.03  |     0.63   |      0.56   |    0
BFS3                 |     0.01  |     0.01  |     0.33   |      0.31   |    0
---------------------+-----------+-----------+------------+-------------+---------
n=10^4, m=10                                                                      
---------------------+-----------+-----------+------------+-------------+---------
BFS1                 |     0.26  |     0.26  |     5.26   |      2.81   |    0
BFS2                 |     0.25  |     0.26  |     5.40   |      3.87   |    0
BFS3                 |     0.39  |     0.43  |    20.29   |     25.75   |    0
---------------------+-----------+-----------+------------+-------------+---------
n=10^5, m=10                                                                      
---------------------+-----------+-----------+------------+-------------+---------
BFS1                 |     3.64  |     3.74  |    48.71   |     22.06   |    1
BFS2                 |     3.58  |     3.69  |    48.90   |     27.68   |    1
BFS3                 |    48.73  |    85.43  |  1919.24   |    338.19   |   50
The set based approach is substantially worse for this case.
The zap function is a clever idea, however, using it in BFS appears to be slower than using a set based approach. How large are the graphs that you are dealing with? I've tested with graphs up to 100000 nodes. Here is the set based procedure:
BFS3 := proc(G, v)
local S, U, X, i, j;
    S := table();
    X := {v};
    U := {};
    for i while X <> {} do
        S[i] := X;
        U := U union X;
        X := `union`(seq(G[j], j=X)) minus U;
    end do;
    [seq(S[j], j=1..i-1)];
end proc:
Here is a comparison of the times and memory usage. BFS1 is your procedure, BFS2 is essentially the same, but with lists instead of sets. n is the number of nodes in the graph, m is the number of children at each node. Graph is generated randomly.
                     +---- Timing (sec) -----+---- Memory (MiB) --------+
n=1000, m=10         |  Maple    |   Total   |   Used     |    Alloc    | GC times
---------------------+-----------+-----------+------------+-------------+---------
BFS1                 |     0.03  |     0.02  |     0.53   |      0.00   |    0
BFS2                 |     0.02  |     0.02  |     0.57   |      0.50   |    0
BFS3                 |     0.01  |     0.01  |     0.32   |      0.31   |    0
---------------------+-----------+-----------+------------+-------------+---------
n=1000, m=100                                                                     
---------------------+-----------+-----------+------------+-------------+---------
BFS1                 |     0.10  |     0.10  |     3.14   |      0.00   |    0
BFS2                 |     0.10  |     0.10  |     3.16   |      2.87   |    0
BFS3                 |     0.02  |     0.02  |     1.36   |      1.37   |    0
---------------------+-----------+-----------+------------+-------------+---------
n=10000, m=10                                                                     
---------------------+-----------+-----------+------------+-------------+---------
BFS1                 |     0.28  |     0.29  |     4.83   |      1.00   |    0
BFS2                 |     0.27  |     0.28  |     4.79   |      3.50   |    0
BFS3                 |     0.07  |     0.08  |     4.36   |      3.62   |    0
---------------------+-----------+-----------+------------+-------------+---------
n=10000, m=100                                                                    
---------------------+-----------+-----------+------------+-------------+---------
BFS1                 |     1.63  |     1.77  |    32.07   |     20.50   |    0
BFS2                 |     1.63  |     1.71  |    32.04   |     27.49   |    0
BFS3                 |     0.29  |     0.46  |    25.98   |     26.37   |    0
---------------------+-----------+-----------+------------+-------------+---------
Probably. In that vein,
A := proc(x) lprint(x); type(x,'numeric'); end proc:
ormap(A,a^2);                                       
a
                                     false
a^2 is a product (analogous to 2*a being a sum), but A is only called once even though it returns false (in an ormap). To strengthen your conjecture
ormap(A, a^b);
a
b
                                     false
This time A is called twice, as it should be. a^b is of type `^`
First 163 164 165 166 167 168 169 Last Page 165 of 195