Carl Love

Carl Love

25319 Reputation

25 Badges

10 years, 235 days
Himself
Natick, Massachusetts, United States
My name was formerly Carl Devore.

MaplePrimes Activity


These are answers submitted by Carl Love

It's much easier to let the overload command do all the type-checking work rather than trying to do it in ModuleApply. Here is your module with my corrections. What I added is in green; what I removed is in orange.
 

restart
:

MyModule:= module()
uses TT= TypeTools;
global _T1, _T2L, _T2V, _T3L, _T3V, _MyType;
local
     MyTypes:= {_T1, _T2L, _T2V, _T3L, _T3V},
     AllMyTypes:= MyTypes union {_MyType},

     ModuleLoad:= proc()
     local
          g, #iterator over module globals
          e
     ;
          #op([2,6], ...) of a module is its globals.
          for g in op([2,6], thismodule) do
               e:= eval(g);
               if g <> e and e in AllMyTypes then
                    error "The name %1 must be globally available.", g
               end if
          end do;
          TT:-AddType(_T1, algebraic);
          TT:-AddType(_T2V, 'Vector(2, algebraic)');
          TT:-AddType(_T2L, [algebraic $ 2]);
          TT:-AddType(_T3V, 'Vector(3, algebraic)');
          TT:-AddType(_T3L, [algebraic $ 3]);
          TT:-AddType(_MyType, MyTypes)
     end proc,

     ModuleUnload:= proc()
     local T;
          for T in AllMyTypes do TT:-RemoveType(T) end do
     end proc,

     MyDispatch:= overload([
          proc(A::_T1, B::_T1, C::_T1)
          option overload;
          local r:= "A, B, C are T1."; #unnecessary; just an example.
               #statements to process this type
          end proc,

          proc(A::_T2L, B::_T2L, C::_T2L)
          option overload;
          local r:= "A, B, C are T2L.";
               #
          end proc,

          proc(A::_T2V, B::_T2V, C::_T2V)
          option overload;
          local r:= "A, B, C are T2V.";
               #
          end proc,

          proc(A::_T3L, B::_T3L, C::_T3L)
          option overload;
          local r:= "A, B, C are T3L.";
               #         
          end proc,
          #
          #The overloaded procedures MUST have option overload.


          #
          #I added this
          #
          proc(A::_T2L, B::_T3L, $)
          option overload;
          local r:= "A, B, are mixed.";
               #
          end proc,

          proc(A::_T3V, B::_T3V, C::_T3V)
          option overload;
          local r:= "A, B, C are T3V.";
               #
          end proc
     ]),
#
# I have added the Or(....(A::_T2L,B::_T3L)
#
     ModuleApply:= proc(
          (*
          A::'Or'(And(
               _MyType,
               satisfies(A-> andmap(T-> A::T implies B::T and C::T, MyTypes) )
          ),(A::_T2L,B::_T3L)),
          B::_MyType, C::_MyType
          *)
     )
          MyDispatch(args)
     end proc
;
     ModuleLoad()    
end module:
 

#Example usage:
#

x:=[9,4];
y:=[5,7];
z:=[1,9];                                 
MyModule(x,y,z);

[9, 4]

[5, 7]

[1, 9]

"A, B, C are T2L."

x:=[9,4];
y:=[5,6,7];
z:=p;                                 
MyModule(x,y);

[9, 4]

[5, 6, 7]

p

"A, B, are mixed."

MyModule([1,2],2,3);

Error, (in MyModule) invalid input: no implementation of MyDispatch matches the arguments in call, 'MyDispatch([1, 2], 2, 3)'

 

Download Module_Test_Types.mw

The algorithm shown by @dharr is fairly well known; I remember reading it in a magazine (perhaps Games) as a child. The following property of that algorithm is much less well known. It doesn't help much when applying the algorithm by hand, but it allows for a big simplification in a computer implementation. It's this: The steps where one needs to go down instead of up and right due to a previously used position or going off the upper right corner happen iff the previously used value is a multiple of the order.

Also, for the verification procedure, I added a check that the elements are all different, which is usually considered part of the definition of a true magic square.
 

restart
:

#Both procedures require 1D input!
#
MagicSq:= proc(n::And(posint, odd))
local M:= Matrix(n$2, datatype= integer[4]), i:= 0, j:= (n+1)/2, k:= 0;
    to n do
        i+= 2; j--;
        to n do M((i:= `if`(i=1, n, i-1)), (j:= `if`(j=n, 1, j+1))):= ++k od
    od;
    M
end proc
:                                

TypeTools:-AddType(
    'MagicSq',
    M-> M::'Matrix'('square') and (
            ()-> local n:= op([1,1], M), j, r:= j= 1..n, S:= add(M[j,-j], r);
            S = add(M[j,j], r)                         #equal diagnonal sums 
            and n^2 = nops({entries}(M, 'nolist'))         #distinct entries
            and andseq(S=add(M[j]) and S=add(M[..,j]), r) #row & column sums
        )()
):

interface(rtablesize= 15):

M:= MagicSq(15);

Matrix(15, 15, {(1, 1) = 122, (1, 2) = 139, (1, 3) = 156, (1, 4) = 173, (1, 5) = 190, (1, 6) = 207, (1, 7) = 224, (1, 8) = 1, (1, 9) = 18, (1, 10) = 35, (1, 11) = 52, (1, 12) = 69, (1, 13) = 86, (1, 14) = 103, (1, 15) = 120, (2, 1) = 138, (2, 2) = 155, (2, 3) = 172, (2, 4) = 189, (2, 5) = 206, (2, 6) = 223, (2, 7) = 15, (2, 8) = 17, (2, 9) = 34, (2, 10) = 51, (2, 11) = 68, (2, 12) = 85, (2, 13) = 102, (2, 14) = 119, (2, 15) = 121, (3, 1) = 154, (3, 2) = 171, (3, 3) = 188, (3, 4) = 205, (3, 5) = 222, (3, 6) = 14, (3, 7) = 16, (3, 8) = 33, (3, 9) = 50, (3, 10) = 67, (3, 11) = 84, (3, 12) = 101, (3, 13) = 118, (3, 14) = 135, (3, 15) = 137, (4, 1) = 170, (4, 2) = 187, (4, 3) = 204, (4, 4) = 221, (4, 5) = 13, (4, 6) = 30, (4, 7) = 32, (4, 8) = 49, (4, 9) = 66, (4, 10) = 83, (4, 11) = 100, (4, 12) = 117, (4, 13) = 134, (4, 14) = 136, (4, 15) = 153, (5, 1) = 186, (5, 2) = 203, (5, 3) = 220, (5, 4) = 12, (5, 5) = 29, (5, 6) = 31, (5, 7) = 48, (5, 8) = 65, (5, 9) = 82, (5, 10) = 99, (5, 11) = 116, (5, 12) = 133, (5, 13) = 150, (5, 14) = 152, (5, 15) = 169, (6, 1) = 202, (6, 2) = 219, (6, 3) = 11, (6, 4) = 28, (6, 5) = 45, (6, 6) = 47, (6, 7) = 64, (6, 8) = 81, (6, 9) = 98, (6, 10) = 115, (6, 11) = 132, (6, 12) = 149, (6, 13) = 151, (6, 14) = 168, (6, 15) = 185, (7, 1) = 218, (7, 2) = 10, (7, 3) = 27, (7, 4) = 44, (7, 5) = 46, (7, 6) = 63, (7, 7) = 80, (7, 8) = 97, (7, 9) = 114, (7, 10) = 131, (7, 11) = 148, (7, 12) = 165, (7, 13) = 167, (7, 14) = 184, (7, 15) = 201, (8, 1) = 9, (8, 2) = 26, (8, 3) = 43, (8, 4) = 60, (8, 5) = 62, (8, 6) = 79, (8, 7) = 96, (8, 8) = 113, (8, 9) = 130, (8, 10) = 147, (8, 11) = 164, (8, 12) = 166, (8, 13) = 183, (8, 14) = 200, (8, 15) = 217, (9, 1) = 25, (9, 2) = 42, (9, 3) = 59, (9, 4) = 61, (9, 5) = 78, (9, 6) = 95, (9, 7) = 112, (9, 8) = 129, (9, 9) = 146, (9, 10) = 163, (9, 11) = 180, (9, 12) = 182, (9, 13) = 199, (9, 14) = 216, (9, 15) = 8, (10, 1) = 41, (10, 2) = 58, (10, 3) = 75, (10, 4) = 77, (10, 5) = 94, (10, 6) = 111, (10, 7) = 128, (10, 8) = 145, (10, 9) = 162, (10, 10) = 179, (10, 11) = 181, (10, 12) = 198, (10, 13) = 215, (10, 14) = 7, (10, 15) = 24, (11, 1) = 57, (11, 2) = 74, (11, 3) = 76, (11, 4) = 93, (11, 5) = 110, (11, 6) = 127, (11, 7) = 144, (11, 8) = 161, (11, 9) = 178, (11, 10) = 195, (11, 11) = 197, (11, 12) = 214, (11, 13) = 6, (11, 14) = 23, (11, 15) = 40, (12, 1) = 73, (12, 2) = 90, (12, 3) = 92, (12, 4) = 109, (12, 5) = 126, (12, 6) = 143, (12, 7) = 160, (12, 8) = 177, (12, 9) = 194, (12, 10) = 196, (12, 11) = 213, (12, 12) = 5, (12, 13) = 22, (12, 14) = 39, (12, 15) = 56, (13, 1) = 89, (13, 2) = 91, (13, 3) = 108, (13, 4) = 125, (13, 5) = 142, (13, 6) = 159, (13, 7) = 176, (13, 8) = 193, (13, 9) = 210, (13, 10) = 212, (13, 11) = 4, (13, 12) = 21, (13, 13) = 38, (13, 14) = 55, (13, 15) = 72, (14, 1) = 105, (14, 2) = 107, (14, 3) = 124, (14, 4) = 141, (14, 5) = 158, (14, 6) = 175, (14, 7) = 192, (14, 8) = 209, (14, 9) = 211, (14, 10) = 3, (14, 11) = 20, (14, 12) = 37, (14, 13) = 54, (14, 14) = 71, (14, 15) = 88, (15, 1) = 106, (15, 2) = 123, (15, 3) = 140, (15, 4) = 157, (15, 5) = 174, (15, 6) = 191, (15, 7) = 208, (15, 8) = 225, (15, 9) = 2, (15, 10) = 19, (15, 11) = 36, (15, 12) = 53, (15, 13) = 70, (15, 14) = 87, (15, 15) = 104})

type(M, MagicSq);

true

(*~~~
Create and verify a large square---over a million entries---to check code efficiency:
                                                                                   ~~~*)
printf(
    "\n\nResource usage for magic-square construction:\n"
        ".............................................\n"
):
M:= CodeTools:-Usage(MagicSq(1001)):

printf(
    "\n\nResource usage for magic-square verification:\n"
        ".............................................\n"
);
CodeTools:-Usage(type(M, MagicSq));



Resource usage for magic-square construction:
.............................................
memory used=119.57MiB, alloc change=48.82MiB, cpu time=1.67s, real time=1.43s, gc time=468.75ms


Resource usage for magic-square verification:
.............................................
memory used=28.56MiB, alloc change=15.30MiB, cpu time=406.00ms, real time=401.00ms, gc time=0ns

true

 

NULL

Download MagicSquare.mw

 

Like this:

ex:=
    G1*P3 + G1*P5 + G1*P6 + G2*P3 + G2*P6 + G3*P2 + G3*P5 + G4*P2 + G4*P3 + G4*P5 
    + G4*P6 + G5*P2 + G5*P3
    + G5*P5 + G5*P6 + G6*P3 + G6*P6 + G7*P2 + G7*P5 + G8*P2 + G8*P3 + G8*P5 + G8*P6
:
V:= indets(ex)[]:
codegen[optimize](unapply(ex, [V]), tryhard)(V);

    (G3 + G4 + G5 + G7 + G8)*P2 + (G1 + G3 + G4 + G5 + G7 + G8)*P5 + (P3 + P6)*(G1 + G2 + G4 + G5 + G6 + G8)

By the way, collect will also accept a list of variables: 

collect(ex, [P3,P6,P2,P5]);

It can be done with a one-line procedure:

Rose:= (n::integer)-> plots:-polarplot(sin(n*t), filled, color= `if`(n::odd, pink, aqua));

Test:

Rose(2);  Rose(3);

Given a planar graph G, the command

PD:= GraphTheory:-PlaneDual(G)

returns the graph PD whose vertices are the regions (a.k.a. "faces") of and such that {u,v} is an edge of PD iff the corresponding faces of share an edge. Unfortunately, this command doesn't give the face-to-vertex correspondence; however, it may be enough for your purposes.

The list of lists FL of vertices of G that define its faces can be obtained by 

GraphTheory:-IsPlanar(G, 'FL')

Vertices of degree 0, 1, or 2 in G can be a nuisance. I know this from long experience; I don't know whether they have any bad effect on these particular commands. Those vertices usually add nothing of interest mathematically to the study of planar graphs (or graphs embeddable on other surfaces), but they make many algorithms more complicated. I recommend that they be removed from G. Those of degree 0 or 1 can be removed outright. For a degree-2 vertex v, remove it and connect the two other vertices of its neighborhood if they aren't already connected. Continue recursively removing vertices of degree < 3 until there are no more.

@zenterix If I take your example worksheet, and add the line 

export getSeed, setSeed;

then it works, regardless of whether I use 1D or 2D. There are no hidden characters in this case. If your experience is different, then post a case with an error, not one without.

Here's a minimal implementation in 1D:

module NumberGenerator()
option object;
local defaultSeed:= 100, ModuleApply:= ()-> Object(thismodule);
export 
    setSeed:= proc(newSeed) local r:= defaultSeed; defaultSeed:= newSeed; r end proc,
    getSeed:= ()-> defaultSeed
;
end module
: 

I modified your setSeed to return the previous seed because I'm nearly certain that at some future point you'll wish that it was defined that way.

Background motivation: From the theory of limits of univariate functions (i.e., functions of a single real variable), recall the idea of directional or one-sided limits (i.e., limits from the left or from the right). Recall that if the left and right limits both exist but have different values, we'd say that the limit as a whole doesn't exist. We extend that idea to the multivariate case. There are now an infinite number of directions rather than just the two (left and right). If there are any two that give different limits, then we say that the multivariate limit doesn't exist (because it is path dependent, hence the title of this Answer).

Reduction of counterexample construction to the univariate case: Define the given function as f(x,y). For the sake of generality, I'll say that the limit point is (a,b) rather than (0,0). I'll define a path as a function y = g(x) such that limit(g(x), x= a) = b. (The notion of path in multivariate calculus is more general than that, but my definition is sufficient for the purpose of this problem.) If we can find two paths given by functions y = g1(x) and y = g2(x) such that limit(f(x, g1(x)), x= a) <> limit(f(x, g2(x)), x= a), then we'll have proved that the limit is path dependent and hence "doesn't exist" as a multivariate limit.

For the given problem, finding functions g1 and g2 that work is very easy, and there are many possible choices.

In Maple:

f:= (x,y)-> sin(x^2 - y^2)/(x^2 + y^2):
g1:= x-> 
...:  
g2:= x-> 
...
:
#Check 1:
limit(g1(x), x= 0) = 0;
limit(g2(x), x= 0) = 0;

#Final check:
limit(f(x, g1(x)), x= 0) <> limit(f(x, g2(x)), x= 0);

I leave it up to you to guess and define suitable functions for g1 and g2.

Like this:

restart:
f:= t-> cos(3*t) + 2*sin(2*t-3):
T:= Vector(100, i-> 0.1*i):
data:= <T | f~(T)>;

You can combine an Interpolation object with a regular function in a numeric integrand as in this example:

P:= plot(sin(x), x= 0..Pi):
XY:= op([1,1], P):
f:= Interpolation:-SplineInterpolation(XY):
int(x-> f(x)/(1+x), 0..Pi, numeric);

If such an integral returns unevaluated, reduce the precision with the epsilon option:

int(x-> f(x)/(1+x), 0..Pi, epsilon= 5e-7, numeric);
 

There are a few other problems in your code, unrelated to the issue corrected by acer. The most prominent of these problems is this: Once a procedure executes a return statement, it stops executing. Thus, in places where you have two or more return statements in succession, only the first can possibly be executed. You can get around this by returning multiple values in a single return statement, for example 

return p, q, r

Here are corrections to your procedure:

conjcl:= proc(k::integer, p::prime, n::posint)
local q:= p^n-1, L:= Array(1..0), K:= 0, t;
    for t do K:= K+k mod q; L(t):= K; if K=0 then break fi od;
    [seq](L) 
end proc
:

conjcl(3,2,3);

                     [3, 6, 2, 5, 1, 4, 0]

Note that for your example values q = p^n - 1 = 7 is itself prime. That's a very rare occurence; there are only 51 known pairs (p,n) for which it happens. It's easy to prove that it can only happen for p = 2 and prime. The upshot is that the returned list has all the integers 0..6 for any not a multiple of 7, and thus the conjugacy class is the entire multiplicative group of the field. In general, that will only happen when k and q are relatively prime, i.e., when their greatest common divisor (GCD) is 1.

Here are the errors with your original procedure:

  1. t needs to start at 1, not 0.
  2. It's the multiples of k, not the powers of p, that matter; indeed p could never be a generator (a.k.a. primitive element) of the field GF(p^n).
  3. Maple's mod doesn't distribute over <>.

This procedure is much simpler using syntax that is only available in 1D input:

conjcl:= (k::integer, p::prime, n::posint)->
local q:= p^n-1, K;
    [for K from k by k do K mod= q until K=0]
:

The need for an index variable in add and related looping statements can very often be avoided by using elementwise operations. I've typed the below in 1D, but they work in 2D also:

Omega:= (a::list)-> (-1)^add(a -~ 1);
Omega__rev:= (a::list)-> (-1)^add(a -~ [$nops(a)]);

There are many possible variations of the above, many of which avoid the internal creation of a temporary list. Here are two such possibilities for each:

Omega:= (a::list)-> (-1)^(add - nops)(a);
Omega:= curry(`^`, -1)@(add - nops);

Omega__rev:= (a::list)-> (-1)^(add - (n-> n*(n+1)/2)@nops)(a):
Omega__rev:= curry(`^`, -1)@(add - (n-> n*(n+1)/2)@nops):

I use curry and rcurry so often that I have the following predefined:

`&<`:= curry:  `&>`:= rcurry:

Using those, the above can be:

Omega:= `^`&<(-1) @ (add - nops):
Omega__rev:= `^`&<(-1) @ (add - binomial&>2 @ (nops+1)):

 

I think that you're misinterpreting the prettyprinted output of a permutation group object as a string. If you apply lprint to the output, you'll see that it's actually the PermutationGroup constructor. However, if you truly have a string such as you say, it can be converted to the group with this procedure:

StringToGroup:= proc(S::string)
uses ST= StringTools, GT= GroupTheory;
    (GT:-PermutationGroup@eval)(
        subsindets[flat](
            (`[]`~@{seq})(
                parse(ST:-SubstituteAll(ST:-SubstituteAll(S, ")(", ")*("), "(", "_("))
            ),
            `*`, op
        ),
        _= `[]`
    )
end proc
:
StringToGroup("<(1, 2), (1, 2, 3)(4, 5)>");
                <(1, 2), (1, 2, 3)(4, 5)>        

lprint(%);
GroupTheory:-PermutationGroup({Perm([[1, 2]]), Perm([[1, 2, 3], [4, 5]])},
degree = 5)

 

It should be 

cutoff:= eval(t, tempLrest[2])

The reason is that classical methods (almost by definition of classical) don't have dynamic error control such as variable step length. So, they are ignoring the errors that rkf45 is trying to prevent.

I don't know much about these ODEs with random input (are they stochastic DEs such as used in finance?), but perhaps ignoring the error controls is in fact useful.

First 8 9 10 11 12 13 14 Last Page 10 of 369