On Thu, Jan 28, 2021 at 06:58:55PM -0500, Tobias Neumann wrote:
> Thank you, that indeed explains the issue. My confusion
> arose because the equation (obviously) has to take the symbol as FE.
>
> My next issue is when trying to construct a list of series expansions (see
> my snippet later):
> (I added the [1,1,1] at the end to not introduce more errors from trying to
> use 'approximate')
> (Ultimately I want to obtain a Matrix or Lists of Lists of series
> expansions)
>
> testseries := map((elem:FE): uts +-> retract(taylor(elem, eqn)$e_pak)$any1,
> ff) :: List(uts)
>
> This fails with:
> >> Apparent user error:
> Cannot coerce (CONS (CLOSEDFN (LAMBDA ((elem ) ($$ )) (PROG (eqn $ uts
> any1) (SETQ eqn (QREFELT $$ 3)) (SETQ $ (QREFELT $$ 2)) (SETQ uts (QREFELT
> $$ 1)) (SETQ any1 (QREFELT $$ 0)) (RETURN (PROGN (SPADCALL (SPADCALL elem
> eqn (QREFELT $ 15)) (compiledLookupCheck (QUOTE retract) (LIST (devaluate
> uts) (LIST (QUOTE Any))) any1))))))) (VECTOR any1 uts $ eqn))
> of mode (Mapping uts FE)
> to mode ##2
>
> If I leave out the anonymous function type signature,
> testseries := map(elem +-> retract(taylor(elem, eqn)$e_pak)$any1, ff)
> :: List(uts)
> the error changes to:
> >> Apparent user error:
> Cannot coerce elem
> of mode uts
> to mode ##2
>
> Is this another user error or a problem with the compiler?
I do not know it is all, but there is basic user error above:
before you call a function package/domain containing the
function must be imported. Spad compiler automatically
is doing some imports, but this is quite limited.
Unlike interpreter which aggressively searches database
of defined functions Spad compiler will not see 'map'
that you want to use. To clarify a bit: Spad uses
overloading so from point of view of Spad compilers
there are a lot of different 'map' functions defined
in many places. You need to either import package
defining this function or use '$' qualification.
Error may look weird, but simply Spad tells you that
your arguments do not fit 'map' that Spad tried to use.
This is because there is a lot of 'map' functions and
without import (or '$' qualification) Spad has only
wrong ones.
Extra things:
- ATM '$' qualification is doing import, so next use
of the same function works without qualification,
but at some moment this will be fixed
- each parameter tuple gives you different type and
requires separate import
in the future
AFAICS you want 'map' from ListFunctions2 (with appropriate
parameters). There are a lot of packages called like
XxxxFunctions2 and they contain functions acting between
two types (like 'map' that you want).
> Another unrelated question: Assuming I pass a series expansion wrapped as
> type 'Any' to some function,
> am I able to reconstruct the underlying series type just from that?
> Schematically, having
> myseries of type Any, can I do something like unwrapped :=
> retract(myseries)$AnyFunctions1(dom(myseries)),
> (where dom returns the domain and not an SExpression),
> or can I pass the underlying domain as another parameter to a function?
> Along the lines of:
>
> doSomethingWithSeries : (Any, Type)-> Expression(Integer)
> doSomethingWithSeries (ser, type) ==
> unwrapped := retract(ser)$AnyFunctions1(type)
> approximate(unwrapped,5)
1) You can pass types as parameters. Note that types also
have types, and if you have something that is just 'type'
there is not much that you can do with it. In
particular call to 'approximate' would fail.
Rather, normally instead of Type you would have category
like Group, then you should be able to call group operations
I can not tell you code above will work with proper category
definition, but it can not work without category definition
(or other type info). To call approximate appropriate
category is 'UnivariateTaylorSeriesCategory', but specifying
it means that you need to specify cefficient type
(variable name and center remain unspecified).
2) Usually types are passed of parameters to domain
constructors. Namely, for example 'Expression' is
effectively a function from types to types. You
can pass type constructed at runtime to 'Expression'
and get new type. Spad compilers handles domain
constructors is special way, in particular uses
elaborate caching scheme to avoid repeating computations
on types. If you create new types on whim and
intensively use them you may be surprized by poor
performance. Computers are now fast enough that
you will feel nothing for small computations, but
when you care about speed computations that limits
runtime use of types may be much faster. If you
are doing something inherently expensive, then
runtime use of type may be insignificant in
comparison, but avoid runtime types in inner loops.
3) There is no official way to get type from Any.
Internaly there is Lisp function 'evalType' that
given Sexpression returns Type.
4) I would discourage Spad code based on Any. Any
is used in limited number of situations, basically
when type depends on something known to code but
dependence is too complicated to express in Spad.
Once type is known use normal package parameters to
pass type info. So instead of
AnyPak : with
doSomethingWithSeries: (Any, Type)-> Expression(Integer)
....
have
Pak(T : Type) : with
doSomethingWithSeries: T -> Expression(Integer)
doing 'retract' at call site. If you need to pass Any,
than
Pak(T : Type) : with
doSomethingWithSeries: Any -> Expression(Integer)
...
doSomethingWithSeries(a) ==
a_val := retract(a)$AnyFunctions1(T)
...
is better.
5) Current style in FriCAS algebra is to pass around a lot
of parameters to domain constructors. And use helper
packages like ListFunctions2 so that needed types are
are determined by parameters. This is sometimes
inconvenient and certainly different coding styles are
worth investigation. But current code and design
is adapted to coding style and all this together
works reasonably well. Different coding style
would probably require large changes to algebra
code to make new style really viable.
> I have tried something similar using interpreted FriCAS:
>
> EI ==> Expression(Integer)
>
> dostuff3(x0, sym, lst) ==
> local uts, any1, x
> uts := UnivariatePuiseuxSeries(EI,sym, x0)
> any1 := AnyFunctions1(uts)
> map((elem:EI): uts +-> retract(puiseux(elem, equation(sym ::
> EI,x0)))$any1, lst)
>
> x := 'x :: Symbol
> expr := x^2 + x :: EI
> lst := [expr,expr,expr]
> dostuff3(3::EI, x, lst)
>
> which results in
>
> Local variable or parameter used in type
> We will attempt to interpret the code.
> Cannot compile a $-expression involving a local variable.
> FriCAS will attempt to step through and interpret the code.
>
> any1 is not a valid type.
There are bugs with handling local types in interprter (this may
be one of them). I would suggest sticking to global ones if
possible (at least you should get better error messages). Note
that you can re-assign global types and FriCAS interpreter will
recompile your functions to take into account changed types. Also,
interprter code using global types is easy to convert to
Spad code which uses domain parameters. Local types
behave better in Spad code but there is potential inefficiency
(probaly smaller than cost of recompilation...).
--
Waldek Hebisch
--
You received this message because you are subscribed to the Google Groups
"FriCAS - computer algebra system" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/fricas-devel/20210129021330.GB2309%40math.uni.wroc.pl.