Joe Riel

9590 Reputation

23 Badges

19 years, 134 days

MaplePrimes Activity


These are answers submitted by Joe Riel

There is more here than meets the eye.  Here's a modification that suggests what is happening:
 

(**) f := proc(n)
(**) option remember;
(**)     if n < 2 then 1;
(**)     else
(**)         f(n - 1) + f(n - 2);
(**)     end if;
(**) end proc:
(**) F := Compiler:-Compile(f):
Warning, the function names {f} are not recognized in the target language
(**) unassign('f');
(**) F(10);
Error, (in F) number expected for float[8] parameter, got f(9)

Note my use of unassign.  The compiler warning is a hint.  If the unassign is removed, then F(10) returns the correct answer, but only because it is evaluating f in Maple.  To allow recursion to work you can replace the calls to f with thisproc:

(**) f := proc(n)
(**)     if n < 2 then 1;
(**)     else
(**)         thisproc(n - 1) + thisproc(n - 2);
(**)     end if;
(**) end proc:
(**) F := Compiler:-Compile(f):
(**) F(10);
                               89



 

I'm not sure what you are actually looking to achieve.  I believe the custom component shown in the video was created using Modelica Code Editor, which allows more functionality then the Custom Component app, however, you can use a boolean parameter (which is what the solution parameter appears to be) in the Custom Component app to select a branch of a piecewise.  For example

eq := [ diff(x(t),t) = %piecewise(b, sin(t), cost(t)) ]; 

In the app, set the b parameter to type Boolean. It will then appear as a checkbox in the parameter panel of the generated component.

You defined the force on the mass as -9.81*m, where m is a parameter.  However, you didn't assign the mass (SM1) the parameter m, so the force doesn't correspond to gravitional acceleration.  Also, the the mass-with-stop-and-friction component has additional mass not accounted for in the force model.  

If you use the multibody mass component, it will, by default, have the downward acceleration of Earth's gravitional force applied to it.  Then you won't need the external force component. I've uploaded a modified version.  It doesn't include stops.

fall_elevator_on_spring2.msim

If you first execute stoperror(traperror), the debugger will open at the occurrence of the assertion that causes the issue.  The library code contains
 

                  dz1 := numer(normal(diff(z1,x)));
                  ASSERT( degree(dz1,sol) = 1 );
                  dz1 := normal( -coeff(dz1,sol,0) / coeff(dz1,sol) );

but at that point z1 is _X000001+exp(x^2)*exp(-x^2), so dz1 is 0 and the assertion fails.  With assertlevel=2, the ASSERT command raises the error, otherwise the subsequent statement raises a division by zero error.

For this I generally use one of the following techniques
 

(**) eqs := [1=a,2=b]:
(**) map(rhs=lhs,eqs);
                             [a = 1, b = 2]

(**) (rhs=lhs)~(eqs);
                             [a = 1, b = 2]

 

A straightforrward method is to eliminate t_y from the objective, and check stationary points:

obj := rho*ln((-beta*tau + rho)/(1 + t__x)) + sigma*ln(sigma/(1 + t__y)) + beta*tau + B - rho - sigma - beta*tau*ln((-beta*tau + rho)/(1 + t__x));
cons := -t__x*(-beta*tau + rho)/(1 + t__x) + t__y*sigma/(1 + t__y) = R:

sol_ty := solve(cons, {t__y});
obj2 := subs(sol_ty, obj);
sol_tx := solve(diff(obj2,t__x), {t__x});
simplify(subs(sol_tx, obj2));

You can also use Lagrange multipliers,
 

Student:-MultivariateCalculus:-LagrangeMultipliers(obj, [(lhs-rhs)(cons)], [t__x, t__y], 'output = detailed');
[t__x = -(R-2*sigma)/(-beta*tau+R+rho-sigma), 
 t__y = -(-2*beta*tau+R+2*rho)/(-beta*tau+R+rho-sigma), 
 lambda[1] = -(beta*tau-rho-sigma)/(-beta*tau+R+rho-sigma), 
 rho*ln((-beta*tau+rho)/(1+t__x))+sigma*ln(sigma/(1+t__y))+beta*tau+B-rho-sigma-beta*tau*ln((-beta*tau+rho)/(1+t__x)) = rho*ln((-beta*tau+rho)/(1-(R-2*sigma)/(-beta*tau+R+rho-sigma)))+sigma*ln(sigma/(1-(-2*beta*tau+R+2*rho)/(-beta*tau+R+rho-sigma)))+beta*tau+B-rho-sigma-beta*tau*ln((-beta*tau+rho)/(1-(R-2*sigma)/(-beta*tau+R+rho-sigma)))
]

 

Doing directly what you want isn't feasible in that the file is not syntactically valid Maple input.  A workaround is to use strings to assign the differential equations of interest, then parse them into the correponding Maple expression.

Maple doesn't directly provide a parser for its 2D input. Here's a hackish approach.  No implications that this is robust. 
 

ParsePrimes := proc(str :: string, indep :: symbol := 'x')
local b, p, pos, primes, s, var, vars;
uses ST = StringTools;
    b := ST:-StringBuffer();
    vars := MutableSet();
    s := str;
    while ST:-RegMatch("([A-Za-z_]+)('+)"
                       , s
                       , 'all', 'var', 'primes'
                      ) do
        pos := SearchText(all, s);
        b:-append(s[1..pos-1]);
        b:-appendf("diff(%s(x),[x$%d])", var, length(primes));
        s := s[pos+length(all)..-1];
        vars ,= parse(var);
    end do;
    b:-append(s);
    s := b:-value();

    p := parse(s);

    # Ensure non-primed dependent variables are converted to functions
    # of the independent variable

    if numelems(vars) > 0 then
        p := subsindets(p, 'identical'(seq(vars)), y -> y(indep));
    end if;

    p;

end proc:

# assign a short function name 
`_` := ParsePrimes:

z := _("3*y''+2*y'+y");

                 z := 3*diff(y(x),x $ 2)+2*diff(y(x),x)+y(x)

 

Here's another confirmation, using Syrup:
 

resistance := proc( n :: posint := 2 )
local G, ckt, edge, i, sbuf, sol;
uses GT = GraphTheory;
    sbuf := StringTools:-StringBuffer();
    sbuf:-append("* Soccer Ball *\n");
    G := GT:-SpecialGraphs:-SoccerBallGraph();
    for i,edge in GT:-Edges(G) do
        sbuf:-appendf("R%d %d %d 1\n", i, op(edge));
    end do;
    sbuf:-append("V0 1 0 0\n");       # ground vertex 1
    sbuf:-appendf("I0 0 %d 1\n", n);  # connect 1 A to vertex n
    sbuf:-append(".end\n");
    ckt := sbuf:-value();
    sol := Syrup:-Solve(ckt, 'dc');
    eval('v'[n], sol);
end proc:

(resistance)(2);
                                    16273/25080
(resistance)(31);
                                     17/11

 

The frame_c port of the box component (by default shown on the bottom) is vectorized.  Each connection to it can connect to a different additional frame.  To select the desired additional frame, make a connection, then select the "wire" and select the desired frame from the drop-down menu that will appear in the upper right pane (the connector inspector).  When connecting a "scalar" port to a vectorized port you will get a pop-up warning indicating the two have different dimensions; that's a cue to use the connector inspector.

I've attached the modified msim.
Box.msim

As others have posted, there are shorter ways to do this, but they don't necessarily generalize; some times you need to use nested loops.  You can do that with
 

x := [1,2,3,4]:    # x is a list, not a Vector
k := Matrix(4,4):  # Assign k a 4x4 Matrix; by default it is initialized with all zeros.
for i to 4 do      # By default, Maple for loops start at 1
    for j from 1 to 4 do  # Here's notation for explicitly starting from 1
       k[i,j] := x[i] + x[j];
    end do;
end do:

 

Before calling A:-main(), issue the maple command

stoperror(traperror["numeric exception"]);

When you then execute A:-main(0, the debugger will stop at the location of the error (1/n) in foo.

The string in the traperror index should match the start of the error message; here you could reduce it to "numeric".  You can also use

stoperror(traperror);

which will cause the debugger to stop at every trapped error.  Usually you don't want that, since some Maple procedures use try/catch to handle special cases and you end up stopping at too many locations before arriving at the place of interest.

I don't believe there is a way to do precisely what you want.  There are, however, a few alternatives that may or may not be acceptable.  The simplest might be to just create a local module, say funcs, which has exports of the local functions you want to use throughout the main module.  Then you could access them with funcs:-foo. For example
 

parent := module()
local
    funcs := module()
    export
        foo := proc() ... end proc;
        bar := proc() ... end proc;
   end func;
...
local
      foo := proc()
           funcs:-foo(...)
      end proc;
end module:

Another possibility, if you are planning on making parent a package, is to make foo an export of it, but don't allow it to be given a short name if the parent is with'ed, i.e. a user calls with(parent).  That doesn't prevent it from being called externally, or from appearing in the output of exports(parent), but it does make it slightly less accessible.  To do this, make _pexports an export of parent and assign it a procedure that returns a list of the exports you want to be withed.  For example,
 

parent := module()
option package;
export foo, bar, _pexports;
    _pexports := () -> [ ':-bar' ];   # only bar will show up in the output of with(parent)
end module:

with(parent);
                          [bar]

Later A third alternative is to make foo a local, but call it with thismodule:-foo.  That, however, can only be used if thismodule refers to parent, that is, it won't work inside a procedure in a submodule of parent. 

Here's a somewhat crude solution using the Syrup package (available on the MapleCloud):

Solve := proc(m::posint, n::posint, p::posint)
local R, ckt, i, j, k, sbuf, sol;

    sbuf := StringTools:-StringBuffer();
    sbuf:-append("* Grid Circuit\n");

    # insert resistances forming grid
    for i from 0 to m do
        for j from 0 to n do
            for k from 0 to p do
                if 0 < i then sbuf:-appendf("Rx%d%d%d n%d%d%d n%d%d%d 1\n", i,j,k, i-1,j,k, i,j,k) end if;
                if 0 < j then sbuf:-appendf("Ry%d%d%d n%d%d%d n%d%d%d 1\n", i,j,k, i,j-1,k, i,j,k) end if;
                if 0 < k then sbuf:-appendf("Rz%d%d%d n%d%d%d n%d%d%d 1\n", i,j,k, i,j,k-1, i,j,k) end if;
            end do;
        end do;
    end do;

    # ground node n000 and connect 1A source to n[m,n,p]
    sbuf:-append("V0 n000 0 0\n");
    sbuf:-appendf("I1 0 n%d%d%d 1\n", m,n,p);
    sbuf:-append(".end\n");

    ckt := sbuf:-value();

    sol := Syrup:-Solve(ckt, 'dc');
    
    # extract the voltage at node n[m,n,p],
    # which corresponds to the desired resistance.

    R := subs(sol, 'v'[nprintf("n%d%d%d",m,n,p)]);
    return R;
    
end proc:

(Solve)(3,4,5);
 

The rational returned is 4913373981117039232145573771/4056979859824989677919819480, which is 1.21109...

They can be connected, however, the input is vectorized, which requires an additional step to select which slot of the vector to connect to.  I generally start from the output gate and draw the connection to the input gate, hovering over its input section (left side) until I see the green highlight, then click. That should make a connection, typically (maybe always) to the first slot. Then select the signal (click on the line) and you should see, in the upper right pane a display like A2.y <--> N1.x[1].  That means the output (A2.y) is connected to the first slot of the N1.x.  Use the drop-down menu that appears in that pane to change this to, say N1.x[2]. 

Here is the updated model.

logical_circuit2.msim

DEtools is rather old and is not a Maple module, but rather a table-based package.  As such, I'm surprised DEtools:-kovavicsols even works, though maybe there is now a mechanism to handle that (use of the member operator, :-, with a table-based package). Try

eval(DEtools[kovacicsols]);
    proc() `DEtools/kovacicsols`(_passed) end proc

Based on that, I'd modify your code to use either DEtools['kovacicsols'] or `DEtools/kovacicsols`, which is the procedure that is eventually called.

4 5 6 7 8 9 10 Last Page 6 of 114