acer

32333 Reputation

29 Badges

19 years, 321 days
Ontario, Canada

Social Networks and Content at Maplesoft.com

MaplePrimes Activity


These are replies submitted by acer

Thanks, Alex. I must have accidentally used my earlier defn when I wrote that last int() call. I ought to have forseen my mistake.

Anyway, this looks like what sometimes gets called "premature evaluation", where the applied function argument is unintentionally evaluated up front. A usual way of dealing with it is to delay the evaluation. That can often be done using operator form, or using uneval quotes, or by redefining the proc to return unevaluated on non-numeric input. Those workarounds can allow numeric routines like plot(), evalf(Int(...)), fsolve(), Minimize() to work with f(x).

But symbolic int() doesn appear to be able to do anything meaningful with them. It doesn't "know" how to handle them, in the way that it "knows" how to handle piecewise structures. It doesn't generate an error, but it also doesn't compute the result.

> f:=proc(x) if x>=0 and x<1 then 1 else 0 fi; end proc:

> int(f(x),x=0..2);
Error, (in f) cannot determine if this expression is
true or false: 0 <= x and x < 1

> int('f'(x),x=0..2);
                                    2
                                   /
                                  |
                                  |   f(x) dx
                                  |
                                 /
                                   0
 
> int(f,0..2); # As Alex mentioned
Error, (in f) cannot determine if this expression is true
or false: 0 <= x and x < 1

> f:=proc(x)
> if type(x,numeric) then
>  if x>=0 and x<1 then 1 else 0 fi;
> else 'procname'(args);
> end if;
> end proc:

> int(f(x),x=0..2);
                                    2
                                   /
                                  |
                                  |   f(x) dx
                                  |
                                 /
                                   0
 
> int(f,0..2);
                                    2
                                   /
                                  |
                                  |   f(x) dx
                                  |
                                 /
                                   0

Yet int() does know how to deal with (many) piecewise structures, as illustrated above.

It may be of interest to compare with the differential operator D, which has more knowledge (tricks) for delving into procs.

> f:=proc(x) if x>=0 and x<1 then 1 else 0 fi; end proc:

> D(f);
           proc(x) if 0 <= x and x < 1 then 0 else 0 end if end proc

Of course, D is intended for use on operators, while int() is intended for use on expressions. Note that the help-page for int() describes its calling sequences as each working on an expression rather than on an appliable function. There is mention of the following form for uppercase Int(), which looks a little like an expression-operator form mismatch,

   Int(expression, a..b)

I can imagine why that gets a help-page mention, because one might subsequently want to apply evalf to that Int() call.

It appears that for lowercase int() the operator form is really just faked, by evaluating at a dummy name. That functionality for int(f,a..b) allows things like this to work

> f := t -> sin(t):

> int(f,a..b);
                                cos(a) - cos(b)

But as far as I can see, that really only works well when int(f(x),x=a..b) would also work. So its upside is mostly (only?) that of minor convenience. But the downside is that it gives the surface impression that int() works with operators in general (which it doesn't -- see the original posted example).

acer

Thanks, Alex. I must have accidentally used my earlier defn when I wrote that last int() call. I ought to have forseen my mistake.

Anyway, this looks like what sometimes gets called "premature evaluation", where the applied function argument is unintentionally evaluated up front. A usual way of dealing with it is to delay the evaluation. That can often be done using operator form, or using uneval quotes, or by redefining the proc to return unevaluated on non-numeric input. Those workarounds can allow numeric routines like plot(), evalf(Int(...)), fsolve(), Minimize() to work with f(x).

But symbolic int() doesn appear to be able to do anything meaningful with them. It doesn't "know" how to handle them, in the way that it "knows" how to handle piecewise structures. It doesn't generate an error, but it also doesn't compute the result.

> f:=proc(x) if x>=0 and x<1 then 1 else 0 fi; end proc:

> int(f(x),x=0..2);
Error, (in f) cannot determine if this expression is
true or false: 0 <= x and x < 1

> int('f'(x),x=0..2);
                                    2
                                   /
                                  |
                                  |   f(x) dx
                                  |
                                 /
                                   0
 
> int(f,0..2); # As Alex mentioned
Error, (in f) cannot determine if this expression is true
or false: 0 <= x and x < 1

> f:=proc(x)
> if type(x,numeric) then
>  if x>=0 and x<1 then 1 else 0 fi;
> else 'procname'(args);
> end if;
> end proc:

> int(f(x),x=0..2);
                                    2
                                   /
                                  |
                                  |   f(x) dx
                                  |
                                 /
                                   0
 
> int(f,0..2);
                                    2
                                   /
                                  |
                                  |   f(x) dx
                                  |
                                 /
                                   0

Yet int() does know how to deal with (many) piecewise structures, as illustrated above.

It may be of interest to compare with the differential operator D, which has more knowledge (tricks) for delving into procs.

> f:=proc(x) if x>=0 and x<1 then 1 else 0 fi; end proc:

> D(f);
           proc(x) if 0 <= x and x < 1 then 0 else 0 end if end proc

Of course, D is intended for use on operators, while int() is intended for use on expressions. Note that the help-page for int() describes its calling sequences as each working on an expression rather than on an appliable function. There is mention of the following form for uppercase Int(), which looks a little like an expression-operator form mismatch,

   Int(expression, a..b)

I can imagine why that gets a help-page mention, because one might subsequently want to apply evalf to that Int() call.

It appears that for lowercase int() the operator form is really just faked, by evaluating at a dummy name. That functionality for int(f,a..b) allows things like this to work

> f := t -> sin(t):

> int(f,a..b);
                                cos(a) - cos(b)

But as far as I can see, that really only works well when int(f(x),x=a..b) would also work. So its upside is mostly (only?) that of minor convenience. But the downside is that it gives the surface impression that int() works with operators in general (which it doesn't -- see the original posted example).

acer

If `e` is rebound to the name of an export of a module, then it can be used with the `networks` package, I believe.

One should be able to issue any of these fragments, prior to the networks calls, and then use e as a name for a vertex, etc.

 

loce:=module() option package; export e; end:with(loce,':-e'):

bind((module() option package; export e; end):-e):

loce:=module() export e; end:bind(loce:-e):

Of course, the original, global name can still be accessed as :-e.

In a similar way, it seems possible to rebind D and then use it naturally with the geometry package. The global differential operator :-D is then still available.

acer

If `e` is rebound to the name of an export of a module, then it can be used with the `networks` package, I believe.

One should be able to issue any of these fragments, prior to the networks calls, and then use e as a name for a vertex, etc.

 

loce:=module() option package; export e; end:with(loce,':-e'):

bind((module() option package; export e; end):-e):

loce:=module() export e; end:bind(loce:-e):

Of course, the original, global name can still be accessed as :-e.

In a similar way, it seems possible to rebind D and then use it naturally with the geometry package. The global differential operator :-D is then still available.

acer

Oh, sure, a re-implementation of solve might well try that (or close variants to the formulaic pattern, as well). Your point is good, and is hopefully not lost.

But I was more wondering whether anyone's found an incantation to pump it out in Maple 12, using the usual suspects such as solve, expand, convert, simplify, collect, assuming, etc.

acer

Oh, sure, a re-implementation of solve might well try that (or close variants to the formulaic pattern, as well). Your point is good, and is hopefully not lost.

But I was more wondering whether anyone's found an incantation to pump it out in Maple 12, using the usual suspects such as solve, expand, convert, simplify, collect, assuming, etc.

acer

I may be missing something obvious, but how can one get solve to provide the obvious solution y=a^2 (if real a>0, say) to,

> eval(ln(y)/ln(a) = ln(y-1)/ln(b),b=sqrt(a^2-1));

                              ln(y)   2 ln(y - 1)
                              ----- = -----------
                              ln(a)       2
                                      ln(a  - 1)

acer

I may be missing something obvious, but how can one get solve to provide the obvious solution y=a^2 (if real a>0, say) to,

> eval(ln(y)/ln(a) = ln(y-1)/ln(b),b=sqrt(a^2-1));

                              ln(y)   2 ln(y - 1)
                              ----- = -----------
                              ln(a)       2
                                      ln(a  - 1)

acer

> f:=sin(x):
> Dn := (n,L) -> (2/L)* int(f*sin(n*Pi*x/L), x=0..L):
> Dn(n,Pi) assuming n::posint;
                                       0

> _EnvAllSolutions:=true: # hoping for a piecewise
> Dn(n,Pi) assuming n::posint;
                            /{  Pi                  \
                            |{ ----          n = 1  |
                          2 |{  2                   |
                            |{                      |
                            \{  0          otherwise/
                          ---------------------------
                                      Pi

> sum( Dn(n,Pi)*sin(n*x)*cos(n*t), n=1..infinity );
                       1/2 sin(x + t) - 1/2 sin(-x + t)

> simplify(convert(expand(convert(%,expln)),trig));
                                 sin(x) cos(t)

acer

> f:=sin(x):
> Dn := (n,L) -> (2/L)* int(f*sin(n*Pi*x/L), x=0..L):
> Dn(n,Pi) assuming n::posint;
                                       0

> _EnvAllSolutions:=true: # hoping for a piecewise
> Dn(n,Pi) assuming n::posint;
                            /{  Pi                  \
                            |{ ----          n = 1  |
                          2 |{  2                   |
                            |{                      |
                            \{  0          otherwise/
                          ---------------------------
                                      Pi

> sum( Dn(n,Pi)*sin(n*x)*cos(n*t), n=1..infinity );
                       1/2 sin(x + t) - 1/2 sin(-x + t)

> simplify(convert(expand(convert(%,expln)),trig));
                                 sin(x) cos(t)

acer

It might be possible to enhance the routine CurveFitting:-ArrayInterpolation so that it returns either the computed piecewise splines or (taking a page out of dsolve/numeric's repertoire) a new routine which can use those splines. Such a returned  routine might accept a single point, say, and compute (only) its interpolated value. Or it might accept an Array of requested data points, and a container Array for the results which gets filled in-place.

In such a way, the splines could be computed just once, and then the new returned routine could efficiently compute interpolated values for any new given point or new Array of points, on demand. That's in contrast to the current situation where all points (to be interpolated) must be supplied up front.

Calling ArrayInterpolation (as it exists currently) repeatedly on single points would (it seems) entail recomputation of the actual splines each time (and allocation of the Arrays which contain them, as garbage to be repeatedly collected).

Consider thse lines of code, from ArrayInterpolation,

        elif method = 'spline' or method = 'cubic' then
            extfun := ExternalCalling:-DefineExternal(
                convert(cat(prefix, "InterpSpline"), 'name'), extlib);
            extfun(dim, splinedeg, dimsizes, numpieces, listnodes, yvalues,
                xisize, xi, outdata2, xmin, xmax, extrapflag, extrapval,
                useuniform, splinetype, nodemode, splinecoeffs,
                splinematrix, splinevector, splinepivots, splinedx,
                splineslopes, splinemids)

Stepping through that in the Maple debugger, the Array argument xi consists of the input points, and in-place Array argument outdata2 contains their computed interpolated values. The challenge would be to construct an returnable, efficient "evaluator" procedure that made use of the apparent spline data returned above in splinecoeffs, etc.

acer

It might be possible to enhance the routine CurveFitting:-ArrayInterpolation so that it returns either the computed piecewise splines or (taking a page out of dsolve/numeric's repertoire) a new routine which can use those splines. Such a returned  routine might accept a single point, say, and compute (only) its interpolated value. Or it might accept an Array of requested data points, and a container Array for the results which gets filled in-place.

In such a way, the splines could be computed just once, and then the new returned routine could efficiently compute interpolated values for any new given point or new Array of points, on demand. That's in contrast to the current situation where all points (to be interpolated) must be supplied up front.

Calling ArrayInterpolation (as it exists currently) repeatedly on single points would (it seems) entail recomputation of the actual splines each time (and allocation of the Arrays which contain them, as garbage to be repeatedly collected).

Consider thse lines of code, from ArrayInterpolation,

        elif method = 'spline' or method = 'cubic' then
            extfun := ExternalCalling:-DefineExternal(
                convert(cat(prefix, "InterpSpline"), 'name'), extlib);
            extfun(dim, splinedeg, dimsizes, numpieces, listnodes, yvalues,
                xisize, xi, outdata2, xmin, xmax, extrapflag, extrapval,
                useuniform, splinetype, nodemode, splinecoeffs,
                splinematrix, splinevector, splinepivots, splinedx,
                splineslopes, splinemids)

Stepping through that in the Maple debugger, the Array argument xi consists of the input points, and in-place Array argument outdata2 contains their computed interpolated values. The challenge would be to construct an returnable, efficient "evaluator" procedure that made use of the apparent spline data returned above in splinecoeffs, etc.

acer

Alec, you are fast.

acer

Alec, you are fast.

acer

It's quite bad that the ?evalm help-page uses Matrix instead of matrix in Maple 12. Fortunately only the Examples appear affected, and the explanatory text has correctly been left alone.

It makes no sense, since `+`, `.`, ^(-1), etc work directly for Matrices. The Example showing S+2*T demonstrates the mistake, since S+2*T will get computed elementwise even without being wrapped in an evalm call.

And evalm applied to a Matrix is unnecessary (Matrices don't have last_name_eval), and doing so inefficiently produces an unnecessary copy and increases the amount of garbage to be collected.

Also, since Matrices and Vectors don't have last_name_eval, the evalm environment isn't any means to do symbolic addition or subtraction on just the names of those objects. Again, the Example on that help-page for S+2*T makes that point, since for S and T as Matrices then S+2*T can't be entered unwrapped without the elementwise computation occuring. (See here, for a rough and ready attempt at such.)

This may have been a misguided and overzealous part of a sweep to deprecate linalg and matrix. It would have been much better to simply have noted the "deprecated" aspect as a brief note at the start of the ?evalm help-page.

acer

First 498 499 500 501 502 503 504 Last Page 500 of 591