Carl Love

Carl Love

28095 Reputation

25 Badges

13 years, 100 days
Himself
Wayland, Massachusetts, United States
My name was formerly Carl Devore.

MaplePrimes Activity


These are answers submitted by Carl Love

My first inclination was to use a try ... catch statement as suggested by Robert Lopez, but then I saw an easier way for your situation. The break statement exits a do loop. For your code, setting h[i+1] to 0 was equivalent to exiting the loop. Notice how the if statement first checks the type of h[i+1]. This makes it safe to compare it with 0.

restart;
p1[0]:=
     .989347189582843*x^2 - 0.139423979061219e-1*x -
     1.82559474469870e8*x^15 + 1.30761381361453e8*x^16 -
     6.88520063191821e7*x^17 + 2.51079317463498e7*x^18 -
     5.66094206949155e6*x^19 + 5.94129446612678e5*x^20 -
     6812.74182685426*x^5 + 59230.0931084044*x^6  -
     3.83520584559500e5*x^7 + 1.90126822307036e6*x^8  -
     7.34991883857609e6*x^9 + 2.24203561757434e7*x^10 -
     5.43284775909785e7*x^11 + 1.04806113793011e8*x^12 -
     1.60600324339222e8*x^13 + 1.94090536353833e8*x^14 +
     559.557918804679*x^4 - 30.6576714427729*x^3  -
     3.93727537464007e-15
:

h[1]:= -1;
for i to 149 do
     p1[i]:= p1[0]-i^2-i:
     h[i+1]:= fsolve(p1[i]-0.312e-1, x, -.2 .. 0);
     if h[i+1]::numeric implies h[i+1] >= 0 then  break  end if;
     print(i, h[i])
end do;

Since you defined h as a procedure (because of the arrow) rather than as an expression, you wouldn't use eval to evaluate it. Just use h(10).

There's a bug in your h. You need to change cos^4*(x) to cos(x)^4.

If you want an actual decimal evauluation, use h(10.); h(10) essentially gives just a substitution without any significant computation in this case.

Most of the plot commands will try to use hardware float arithmetic to evaluate your expression, but they will fail because of the extreme exponents. To counteract this, use

UseHardwareFloats:= false:

Now assign your expression to F (or whatever name you like), and plot like this:

plots:-complexplot(F, del= -1e-13..1e-13);

and

plot([Re,Im](F), del= -1e-13..1e-13);

There are many other options for visualizing a complex function.

Rouben: Don't worry: This isn't a homework problem. Brian is a long-time (many years) poster of optimization puzzle-type problems.

Brian/general readers: There's a trick for converting objective functions with absolute values---but which are otherwise linear---into linear objective functions by adding variables. Unfortunately I don't remember the trick. It should be implemented automatically in Optimization:-LPSolve, but it's not. If it were, I'd solve this as an Integer Linear Program (ILP). Package DirectSearch solves INLPs, but package Optimization doesn't. It turns out that the integer solution can be obtained by the non-integer method of Optimization:-NLPSolve.

 

Problem setup.

restart:

Data:= <name, x, y, pop;
        A, 3, 7, 5;  B, 6, 5, 2;  C, 5, 3, 2;
        D, 1, 2, 1;  E, 7, 1, 3              >;

Data := Matrix(6, 4, {(1, 1) = name, (1, 2) = x, (1, 3) = y, (1, 4) = pop, (2, 1) = A, (2, 2) = 3, (2, 3) = 7, (2, 4) = 5, (3, 1) = B, (3, 2) = 6, (3, 3) = 5, (3, 4) = 2, (4, 1) = C, (4, 2) = 5, (4, 3) = 3, (4, 4) = 2, (5, 1) = D, (5, 2) = 1, (5, 3) = 2, (5, 4) = 1, (6, 1) = E, (6, 2) = 7, (6, 3) = 1, (6, 4) = 3})

n:= op([1,1], Data) - 1;

5

City:= Vector(
     n,
     k-> Record(convert(Data[1,..]=~ Data[k+1,..], list)[])
);

City := Vector(5, {(1) = Record(name = A, x = 3, y = 7, pop = 5), (2) = Record(name = B, x = 6, y = 5, pop = 2), (3) = Record(name = C, x = 5, y = 3, pop = 2), (4) = Record(name = D, x = 1, y = 2, pop = 1), (5) = Record(name = E, x = 7, y = 1, pop = 3)})

Dist:= (P1,P2)-> LinearAlgebra:-Norm(P1-P2, 1): #1 is taxi metric.

P:= <x,y>:

Obj:= add(Dist(<City[k]:-x, City[k]:-y>, P)*City[k]:-pop, k= 1..n);   

5*abs(x-3)+5*abs(y-7)+2*abs(x-6)+2*abs(y-5)+2*abs(x-5)+2*abs(y-3)+abs(x-1)+abs(y-2)+3*abs(x-7)+3*abs(y-1)

 

 

Solution method #1:

infolevel[Optimization]:= 2:

Optimization:-NLPSolve(Obj, method= nonlinearsimplex, evaluationlimit= 2^13);

NLPSolve: calling NLP solver

SolveUnconstrainedNM: using method=nonlinearsimplex
SolveUnconstrainedNM: number of problem variables 2
SolveUnconstrainedNM: trying evalhf mode
E04CCA: number of function evaluations 251

[51.0000000000183604, [x = HFloat(4.999999999989731), y = HFloat(4.999999999991912)]]

 

 

Solution method #2:

#Brute-force integer method requires fewer evaluations!

Min:= infinity:
for X in $(min..max)(Data[2..,2]) do
     for Y in $(min..max)(Data[2..,3]) do
          dist:= eval(Obj, [x= X, y= Y]);
          if dist < Min then               
               (Min,Xmin,Ymin):= (dist,X,Y)
          end if
     end do
end do:

Min,Xmin,Ymin;

51, 5, 5

 

 

Solution method #3:

DirectSearch:-GlobalSearch(Obj, assume= integer);

Matrix(1, 3, {(1, 1) = 51., (1, 2) = [x = 5, y = 5], (1, 3) = 98})

Hmmm. The number of objective function evaluations, 98, is exactly twice the number of lattice points used in the brute-force technique. That's weird and worthy of further investigation.

 

 

Solution method #4?

This simple method is implied by the text in your post. Does it always work? 

 

Xmed:= Statistics:-Median(Data[2..,2], weights= Data[2..,4]);

HFloat(5.0)

Ymed:= Statistics:-Median(Data[2..,3], weights= Data[2..,4]);

HFloat(5.0)

 

 

Download Brian_taxi_metric.mw

 

 A multi-argument function call such as arctan(y,x) could appear in a denominator.

That's a frequently requested feature, but it's not available now.

Here are some alternatives:

  1. Increase the size of the plot.
  2. Decrease the font size of the tickmarks (option axesfont).
  3. Remove the leading zeroes from the tickmarks.
  4. Remove some tickmarks.

Let me know if you need help with any of these.

 

Since the exercises were already due, I thought that there'd be no harm in posting solutions now. I urge you to experiment with various changes to this code. My level of explanation below assumes that you have some experience programming in some other language, although I don't know if that's true. Maybe someone else will add more explanation. Or, feel free to ask specific questions. I also assume that you'll read the help pages for all the commands that I use.

Write a Maple proc L that takes as input two lists and returns as output a set containing the terms they have in common (not necessarily in the same position). For example, L([1, 3, x, 5],[2, x, 5, 2, 1, 8]) should return [1, x, 5].

There's a contradiction in the problem statement. He says that the output should be a set, but he shows it being a list. I'll just assume that it should be a set.

L:= (A::list, B::list)-> {A[]} intersect {B[]};

or

L:= proc(A::list, B::list)  {A[]} intersect {B[]}  end proc;

Note: If A is a set or list, A[] returns the sequence of elements; so {A[]} converts a list to a set.

This procedure can be easily generalized to take an arbitrary number of sets/lists as arguments:

L:= (L::seq({set,list}))-> `intersect`(seq({_l[]}, _l= L));

 

Write a Maple program that implements the Euclidean algorithm to compute the gcd(x, y) for any natural numbers x, y (except x = y = 0).

I saw no reason to treat (0,0) as a separate case. I just have it return 0, which is what Maple's gcd and igcd both do.

GCD:= proc(X::integer, Y::integer)
local r, x, y;
     (x,y):= (max,min)(abs~([X,Y])[]);
     while y <> 0 do
          r:= irem(x,y);
          (x,y):= (y,r)
     end do;
     x
end
proc;

If you really insist on not allowing (0,0) as input, change it to

GCD:= proc(X::integer, Y::integer)
local r, x, y;
     (x,y):= (max,min)(abs~([X,Y])[]);
     if x = 0 then  error "Invalid input: Both arguments can't be 0"  end if;  
     while y <> 0 do
          r:= irem(x,y);
          (x,y):= (y,r)
     end do;
     x
end proc;

or, better yet, replace the error statement with infinity or undefined.

Notes:

  1. abs~([X,Y]) is short for [abs(X), abs(Y)].
  2. (max,min)(x,y) is short for max(x,y), min(x,y).
  3. (x,y):= (y,r) is short for x:= y; y:= r.
  4. In lieu of a return statement, the last expression evaluated in a procedure will be its return value. In this case, that's the x before the end proc.

For a two-line version (as promised), make an inner procedure which acts recursively after the outer procedure has sorted the absolute values of the arguments:

GCD:= (X::integer, Y::integer)->
    ((x,y)-> `if`(y=0, x, thisproc(y, irem(x,y))))((max,min)(abs~([X,Y])[]));

 

Write a Maple program to plot the Pythagorean spiral. The program should take a single positive integer n as an argument and plot the spiral until the side of length n is reached.

Since the sides have lengths that are square roots of integers, I'm surprised that he didn't say "until the side of length sqrt(n) is reached." Anyway, that doesn't add any complexity other than that we need to loop up to n^2 rather than n.

Hopefully you've read the Wikipedia page so you know that the nth radial side is sqrt(n) long and the nth central angle is arctan(1/sqrt(n)).

My "long" version is two procedures. The first loads a two-column matrix with the polar coordinates of the points; the second plots them.

PShf:= proc(n::posint, Pts::Matrix)
local k, r, theta:= 0;
     Pts[1,1]:= 1;
     for k from 2 to n do
          r:= evalf(sqrt(k-1));
          theta:= theta + evalf(arctan(1/r));
          Pts[k,1]:= r;  Pts[k,2]:= theta
     end do
end proc:

PythagoreanSpiral:= proc(n::posint)
local k, Pts:= Matrix((n^2,2), datatype= float[8]), O:= <0|0>;
     evalhf(PShf(n^2, Pts));
     plot([Pts, seq(<Pts[k,..], O>, k= 1..n^2)], coords= polar, scaling= constrained)
end proc:

Notes:

  1. The angle brackets < > are Matrix/Vector constructors; so <0|0> is a row vector of two zeroes (in this case it represents the origin on the plot).
  2. A dimension of a Matrix/Vector/Array specifed by simply .. indicates that the whole of the dimension is to be extracted; so Pts[k,..] extracts the kth point as a row vector.
  3. <Pts[k,..], O> stacks the two row vectors into a 2x2 Matrix.
  4. plot interprets a two-column Matrix as a sequence of points to be plotted and connected.
  5. datatype= float[8] declares that the Matrix will only contain eight-byte double precision values. These are usually the most efficient numbers to work with.
  6. scaling= constrained means that the unit measure on the x- and y-axes will be visually the same (see ?plot,options).
  7. The plot itself is the return value of the procedure.

My three-line version:

PythagoreanSpiral:= (n::posint)->
     (Pts-> plot([Pts[], map2(op, 1, Pts)], coords= polar, scaling= constrained))
          ([seq([[sqrt(_k), evalhf(add(arctan(1/sqrt(_j)), _j= 1.._k-1))], [0,0]], _k= 1..n^2)]);

The evalhf just makes them faster. You can remove the evalhf in either case and they'll still run. If you're going to be plotting any significantly detailed fractals, then you'll need to learn evalhf, which is a tricky command to use correctly.

 

The command fnormal doesn't automatically map over Matrices. Change your command

fnormal(C12f, Digits, 1e-6);

to

fnormal~(C12f, Digits, 1e-6);

(There seems to be no rhyme nor reason to which commands automatically map themselves over which container objects. The command fnormal automatically maps overs lists and sets, but not tables or rtables.)

There is a command essentially for this purpose: plottools:-transform. Here's an example of its use. I use  Kitonum's last example---his plane mapping applied to a unit square---and I show the first three iterations.

#Unit square parametrized on 0..4:
Sq:= t-> piecewise(t < 1, [t,0], t < 2, [0,t-1], t < 3, [t-2,1], [1,t-3]):
#Split it into coordinate functions (required by `plot`):
Sq||(x,y):= seq(subs(_k= k, t-> Sq(t)[_k]), k= 1..2):
#plottools:-transform requires that F return a list (in square brackets):
F:= (x,y)-> [x^2/2 - 3/2*y^3, -x^3/2 + y^2/3]:
T:= plottools:-transform(F):
P:= plot([Sqx, Sqy, 0..4], thickness= 3):
plots:-display(
     Matrix(
         (2,2),
         [seq(plots:-display((T@@k)(P), title= cat("k = ", k)), k= 0..3)]
     ), scaling= constrained
);

Sorry, MaplePrimes can't display array plots from the Standard GUI. You'll need to copy-and-paste the code to see it.

How's it possible that you've been on MaplePrimes for nearly three years and have posted 366 Questions and yet you don't know the answer to this very simple and fundamental question?

p:= x^2*y + x*y + x:
[op(p)];

Please read the help ?op---it's one of the most commonly used low-level commands.

The following could be made faster by pregenerating arrays of random numbers (like you did in your code), but this is a good exposition of the Maple animation technique.

2D animation:

U:= RandomTools:-Generate(float(method= uniform, range= 0..1), makeproc):
frames:= 2^5:
points:= 2^9:
plots:-display(
     ['plot(x-> abs(x)*U(), -5..5, adaptive= false, numpoints= points)' $ frames],
     insequence, thickness= 0
);

3D animation:

frames:= 2^4:
points:= 2^7:
plots:-display(
     ['plot3d((x,y)-> abs(x)*U()+abs(y)^2*U(), -5..5, -5..5, grid= [points$2])' $ frames],
     insequence, shading= zhue, thickness= 0, style= wireframe, transparency= 0.5,
     axes= frame
);

I think that the 3D one may be too bulky to animate here in the post, but you will see it animated in a worksheet. You should use the toolbar controls to slow the Frames Per Second (FPS) to 1 to give the rendering a chance to keep up.

Here is the complete and simplified code. This procedure will print the complete contents of a module---all locals and all exports---and apply itself recursively to all submodules. I was able to simplify from the earlier code by eliminating the need for unwith and parse.

ModulePrint:= proc(M::`module`)
uses ST= StringTools;
local
     N,
     SIV:= interface(verboseproc= 2),
     SKO:= kernelopts(opaquemodules= false),
     EVs:= eval~(op~([1,3], eval(M)))
;
     for N in ST:-Split(sprintf(" %q", op~([1,3], eval(M))[]), ",") =~ EVs do
          printf("%s", lhs(N));
          print(rhs(N));
          if rhs(N)::'`module`' then  thisproc(rhs(N))  end if;
     end do;
     kernelopts(opaquemodules= SKO);
     interface(verboseproc= SIV);
     return
end proc:

combinat:-permute([0$3,1$3], 3);

     [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]

I'm guessing that the above list is what you really want. If you actually want the output as you presented it, then add (as Kitonum did)

(cat@op)~(%)[];

     000, 001, 010, 011, 100, 101, 110, 111

Here's a procedure for it. It's a bit quick-and-dirty because I'm in a hurry right now. Ideally, it'd do exports as well as locals, but the specific module that you mentioned doesn't have any exports. Also, ideally, it'd apply itself recursively to submodules.

The printout of the Maplet code is unfortunately not indented. This would be difficult to achieve, but I'll think about it.

restart:

ModulePrint:= proc(M::`module`)
uses ST= StringTools;
local
     Ns:= ST:-Split(sprintf("%q", op(3, eval(M))), ","),
     N
;
     interface(verboseproc= 2);
     kernelopts(opaquemodules= false);
     for N in Ns do
          lprint(N);
          parse(sprintf("print(eval(%s))", N), 'statement')
     end do
end proc:

ModulePrint(Student:-Calculus1:-DiffTutor);

Edit: There is a bug in the above procedure. Please use the corrected code in the third Reply below.

If your evaluations of the parameters are rational numbers, then an exact solution can be obtained instantaneously, as in

Vars:= {A||(1..8)}:
Rand:= rand(1..9):
Params:= indets(sys1, name) minus Vars:
Vals:= zip(`/`, '['Rand()'$nops(Params)]'$2):
sys2:= eval(sys1, Params=~ Vals):
<solve(sys2, Vars)[]>;

Even exact rational solutions with thousands of digits can be obtained instantaneously. Maple/GMP is very fast with rational arithmetic (state of the art, perhaps?).

First 247 248 249 250 251 252 253 Last Page 249 of 395