Joe Riel

9660 Reputation

23 Badges

20 years, 3 days

MaplePrimes Activity


These are answers submitted by Joe Riel

Creating the points is tedious. Here is an approach to simplify that aspect, using Maple's embedded components:  EtchSketch.mw

Click on the startup code region (gear-like symbol on toolbar) to see the code. The code I hacked together allows you to draw each of the characters you need, then plot them.  The resulting plot is not technically a parametric plot, though you could use the resulting data to create parametric plots as Carl suggested.  

On the menubar, click Tools --> Options then select the Security tab. I'm guessing your AutoExecute Security Level is set to Disable.  If so, change it to Don't warn before execution (or one of the warn options).

Here's a nicer approach.  The minimal bounding box must share an edge with the convex hull. That means we only need to check each edge of the hull. A bonus is that Maple can compute the exact solution.

MinAreaEnclosingRectange := module()
export
    ModuleApply := proc(P :: list([numeric,numeric])
                        , { plot :: truefalse := false }
                       )
    local A,hull,X,Y,i,n,poly;
    uses plottools;
        hull := simplex['convexhull'](P);
        X := Array(map2(op,1,hull));
        Y := Array(map2(op,2,hull));
        n := upperbound(X,1);
        # compute minimal area
        A := min(seq(MinRect(copy(X),copy(Y),i,n), i=1..n));
        # unpack attributes of minimal area
        (A,poly) := attributes(A);
        if plot then
            print(plots:-display(polygon(poly),polygon(P)));
        end if;
        A, poly;
    end proc;

local
    MinRect := proc(X :: Array, Y :: Array, i :: posint, n :: posint)
    local A,c,j,pts,r,s,x,y,xi,xmin,xmax,yi,ymin,ymax;
        # shift i-th point to origin
        (xi,yi) := (X[i],Y[i]);
        X[..] := X - xi; # bracket on lhs does operation in-place
        Y[..] := Y - yi;
        # rotate X and Y so next point is on x-axis
        j := modp(i,n)+1;
        (x,y) := (X[j],Y[j]);
        r := sqrt(x^2 + y^2);
        (c,s) := (x/r,-y/r);
        (X[..],Y[..]) := (c*X-s*Y, s*X+c*Y);
        # coordinates of minimal bounding rectangle with sides parallel to x-y axes
        (xmin,xmax) := (min,max)(X);
        (ymin,ymax) := (min,max)(Y);
        A := (xmax-xmin)*(ymax-ymin);
        # translate coordinate to original
        pts := [[xmin,ymin],[xmax,ymin],[xmax,ymax],[xmin,ymax]];
        pts := map(proc(pt)
                   local x,y;
                       (x,y) := op(pt);
                       [c*x + s*y + xi, -s*x + c*y + yi];
                   end proc, pts);
        # return area, with attributes: area and points that define the box.
        # area is included so that an exact value is returned.
        setattribute(evalf(A), A, pts);
    end proc;
end module:

pts := [[0,2],[1,4],[2,3.5],[4,4],[5,1],[4,0.75],[3,0]]:
(MinAreaEnclosingRectange)(pts, 'plot');
252/13, [[-3/13, 28/13], [51/13, -8/13], [79/13, 34/13], [25/13, 70/13]]

A data table embedded component does not have a value property, which is what the Do command you are calling is attempting to assign to. Data tables work differently than other components; they are linked to a global Matrix. Modifying the entries of that Matrix changes the data table.  Try just removing the call to Do.

MinRectangle := module()
export
    ModuleApply := proc(pts :: list([numeric,numeric]))
    local Pts, i, n, x0, y0;
        n := nops(pts)-1;
        Pts := Array(1..n, 1..2, pts[2..], 'datatype'=float[8]);
        (x0,y0) := op(pts[1]);
        for i to n do
            Pts[i,1] := Pts[i,1]-x0;
            Pts[i,2] := Pts[i,2]-y0;
        end do;
        theta -> Area(Pts,theta);
    end proc;

export
    Area := proc(Pts, theta)
    local b,c,i,l,r,s,t,x,y;
        (t,b,l,r) := (0,0,0,0);
        (c,s) := (cos,sin)(theta);
        for i to upperbound(Pts,1) do
            x := c*Pts[i,1] - s*Pts[i,2];
            y := s*Pts[i,1] + c*Pts[i,2];
            if x < l then
                l := x;
            elif r < x then
                r := x;
            end if;
            if y < b then
                b := y;
            elif t < y then
                t := y;
            end if;
        end do;
        (r-l)*(t-b);
    end proc;

end module:

pts := [[0,2],[1,4],[2,3.5],[4,4],[5,1],[4,0.75],[3,0]]:
f := MinRectangle(pts);
plot(f, 0..Pi);
Optimization:-Minimize(f, 0..Pi);
                        [19.6000000073504, [1.24904577327331]]


This isn't quite right, Minimize gets stuck at a local minimum.  Manually picking the range gives

Optimization:-Minimize(f,0.5 .. 0.7);
                       [19.3846154031950, [0.588002605076272]]

From symmetry, one should only have to rotate from 0 to Pi/2 to find a minimum.

Some operations work differently on Arrays than they do on Matrices or Vector. Matrices and Vectors are considered mathematical entities, an Array is more a programmer's entity.  Consider 

A := Array(1..3, [1,2,3]):
A + 1;
              [2,3,4]

V := Vector([1,2,3]);
V + 1;
Error, a constant cannot be added to a Vector; use +~ ... 

That is an error because, mathematically, it doesn't make sense. Programmers don't necessarily care about that, so a scalar can be added to an Array by doing it element-wise.

The goal is not entirely clear to me.  The confusion comes from the given example; why is the first element always 2?  Is the purpose to find the list with the largest second element? Or the list with the maximum (signed) difference between the two elements? Or the list with the maximum absolute value between the two elements?

Regardless, a different approach, somewhat sophisticated, is to use Maple attributes with the max function.  This is more efficient than sorting.  Sorting is O(n*ln(n)), and since a non-builtin comparison procedure is used the scaling factor is significant (though, I'm guessing, probably acceptable unless you have a rather large input). The max function is O(n), with a better scaling factor. Here is an example that finds the element with the maximum signed difference.

B := RandomTools:-Generate(listlist(integer(range=1..5),10,2)):
attributes(max(seq(setattribute(Float(b[2]-b[1]),b), b=B)));
                                                             [1, 5]

Note that doing this in a do-loop is conceptually simpler and could be faster and use less memory since a duplicate expression sequence does not have to be constructed.

Why not just wrap the code in a procedure?  For example, if I'm looking at a Maple worksheet provided by a user on this forum, I'll frequently export the worksheet to a *.mpl file, add a proc() DEBUG(); ... end proc() around the whole thing, then read it into maple.  Actually, rather than DEBUG() I use mdc(debug), which launches the Emacs debugger (assuming you have it installed). 

You can also use the Bernoulli distribution for this

with(Statistics):
X := Bernoulli(0.495):
Mean(X);
                  0.495
Sample(X,10);
                 

Student[LinearAlgebra][RotationMatrix]

 

ThU's response is correct.  Here is a bit more detail. Click the Plots tab in the right-pane. Click the combo-box and select "add plot"; enter a plot name in the pop-up window (that identifies it if you later have to edit the settings).  After that you should see a text area region with "Empty" in it. Click it and some more stuff will appear. In the x-axis combo-box select the probe you want for the x-axis. In the y-axis combo-box select the probe for the y-axis (you can add multiple probes by clicking Add Variable). When complete, run the simulation and you should see a second plot.

One approach is the following. It uses a loop to generate one solution at a time, then uses the 'avoid' option of fsolve to prevent solving for the same root twice. 

y := exp(x)*cos(x)+1=0:

all := NULL:
do
   sol := fsolve(y,{x=0..10},'avoid'={all});
    if not sol :: set then
        break;
    else
        all := (all,sol);
    end if;
end do:

all;

Besides the syntax issues pointed out by nm, there is a more fundamental issue.  Division should be avoided because the denominator could go to zero.  A better approach is to compute the wedge product of two vectors corresponding to the two lines, if it is non-zero then they are not parallel. This is nice in that it also works in n-dimensions. The vector corresponding to a line is just the difference between two points on the line. In two dimensions, the wedge product of vectors [x1,y1] and [x2,y2] is x1*y2 - x2*y1. Note that this test fails if one or both of the vectors is 0.  That would happen if the two points that designated a line were not distinct.

The requirement that the area go to zero if a segment intersects  is curious.  Ignoring that for the nonce, a simple method is to compute the signed-area.  Assume P is a listlist of points, with P[1] = P[-1], then

SignedArea := proc(P)
 local i,n;
   if P[1] <> P[-1] then
        error "first and last points must be identical";
   end if;
   n := numelems(P);
   1/2*add(P[i][1]*P[i+1][2]-P[i+1][1]*P[i][2], i=1..n-1);
end proc:

I don't see much hope in doing this for a symbolic n, but it easy enough to do if n is given a value.

f := proc(x)
local n;
    # get the index of the calling procedure
    n := op(procname);
    if n :: posint then
        if n = 1 then
            x;
        else
            x + sin(f[n-1](x));
        end if;
    else
        'procname'(x);
    end if;
end proc:

f[3](x);
                              x + sin(x + sin(x))

diff(f[3](x),x);                       1 + cos(x + sin(x)) (1 + cos(x))

 

First 31 32 33 34 35 36 37 Last Page 33 of 114