Wow! What a question. Browsing through the history of the mailing
archive, you'll find that I also don't like "Expression" very much.
The answer for whether "EXPR INT" represents a general expression is
true and false in some sense.
True, because it is the way to take general input of a user (which is
usually an expression -- actually even only a string of characters) and
transforming that into some typed FriCAS object. Since there some
guessing is involved and it doesn't succeed all the time, there must be
some fallback. EXPR INT is such a fallback. It is somehow a necessary
evil for the interpreter. When it however comes to library programming,
I am very much for avoiding EXPR altogether.
The answer is false, because, the implementation of EXPR INT is not what
perhaps other CAS do or how one would imagine an ordinary expression
tree. FriCAS tries to figure out what the smallest units of the
expressions are. Such "smallest units" are known by the term "kernel"
(see Kernel as the corresponding domain). And then FriCAS tries to
represent the expresssion as a rational function with coefficients being
from INT (the argument of EXPR) and "variables" being these kernels.
If you look more carefully through the implementation of EXPR, then you
find that there is not even just one internal representation.
>grep '^ *Rep' expr.spad.pamphlet
Rep := Fraction MP
Rep := MP
Rep := FreeAbelianGroup K
Rep := K
Rep := RF
I hope that helps a bit.
Ralf
I agree that this is both a very relevant and fairly deep question
about Axiom. Understanding the Expression domain is very important
for a real understand of how Axiom works and helps a lot to understand
why it is so different than most other CAS. I recall a few papers and
notes the early days of Axiom about the design of Expression. I will
try to find them in my archive when I get back home.
I especially like Ralf's 2nd answer "false" - If you intend to try to
use Axiom like you would use any of the other computer algebra systems
then there really is no way to avoid Expression. In a sense it is one
the deepest (highest?) domains in the Axiom type hierachy, i.e. a
result of a rather large number of nested dependent definitions that
correspond (more or less) to the way mathematics itself is presented
from it's foundations.
On the other hand there is a tree-like domain in Axiom simply called
InputForm which does the job of just symbolically representing an
expression. In Axiom this domain is in fact used very little. It is
just an intermediate parsed but otherwise unevaluated form of an
expression. It has no other associated type information. One of the
core processes in Axiom is the semantic evaluation of the types that
are to be associated with the various parts of the InputForm and
ultimately the InputForm is completely replaced with a new type
corresponding to it's final value. This process usually does not
involve any of the "rewriting" operations that one might find in
Mathematica for example. If you really wanted this sort of thing, in
my opinion an extension of InputForm would be a good choice for
implementing it. But this would be very much against the design
philosophy of Axiom. (There is also the Pattern domain which makes it
possible to do such rewriting at a higher level in Axiom.)
Regards,
Bill Page.
> --
> You received this message because you are subscribed to the Google Groups
> "FriCAS - computer algebra system" group.
> To post to this group, send email to fricas...@googlegroups.com.
> To unsubscribe from this group, send email to
> fricas-devel...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/fricas-devel?hl=en.
>
>
Basic result is theorem of Richardson which says that what we would
like to have is impossible (problem of deciding if an expression
is zero is undecidable). Generalities are niecely described
in Davenport, Siret, Tournier book (look for canonical form):
http://staff.bath.ac.uk/masjhd/masternew.pdf
Core problem is that there is no general algorithm to decide
if two expression represent the same value (in particular if
an expression is 0). This means that we have to allow
different representations and computations may give wrong
answer (if there is division by unrecognized 0). Instead
of giving well-defined unique answer there are "simplifications"
which make best effort to get "simplest" form, but no warranty
of success.
Details of representaion used and empleyed "simplifications" vary
from system to system. FriCAS expression is a parametric domain.
If nothing interesting is known about the parameter, then FriCAS
represents expression essentially as trees and does almost no
simplifications. If parameter is an integral domain then FriCAS
represents expressions as rational functions of "kernels" -- the
idea is that expressions form a field and kernels give generators
of that field over base ring. More precisely, some kernels are
transendental and give transcenence basis, some are algebraic.
Operations form Expression are careful to simplify the result
using known algebraic relations. If all realtions are known
to FriCAS than results are sound (no risk of division by 0).
If you do not go into details it is very similar to what other
systems do, but details differ. AFAIK officialy Mathematica
uses pure tree representation for expressions but almost
surely converts to something like rational functions of kernels
for computations. Macsyma/Maxima give user a choice between
tree representation and rational function representation, but
sometimes automatically switches representations.
> Is there a technique to avoid this general type? Or why it
> should not be avoided?
If you have relatively general expressions and Expression
is doing (or can be made to do) what you need then use
Expression. If you have something very specialised or
quite different needs that use something different.
I wrote "can be made to do" above because for example
AlgebraicNumber is represented by Expression(Integer)
but disallows transcendentals and adds extra simplification.
There are no special reasons to avoid Expression.
Basically, if for your problem you have better algorithm then
algorithms implemented in Expression then you should create
new domain and use your better algorithm. If there is
more specialised domain doing what you need you probably
should use this domain. Otherwise, if you need what
expression is doing than use it.
--
Waldek Hebisch
heb...@math.uni.wroc.pl
I would like to continue the discussion in this thread a little even
if it goes somewhat beyond the scope of the original question.
On Thu, Mar 17, 2011 at 5:39 PM, you wrote:
>
> Basic result is theorem of Richardson which says that what we would
> like to have is impossible (problem of deciding if an expression
> is zero is undecidable). Generalities are niecely described
> in Davenport, Siret, Tournier book (look for canonical form):
>
> http://staff.bath.ac.uk/masjhd/masternew.pdf
>
What you are describing is the situation when equality is "canonical",
i.e. when equality on the domain is the same as the equality on its
underlying representation. Is this the case for Expression? In
principle a domain can use a non-canonical representation and then
define equality in a computationally intensive manner or even
incomplete (possibly non-terminating) manner. But FriCAS does not
currently permit equality to be anything other than Boolean valued.
>
> Details of representaion used and empleyed "simplifications" vary
> from system to system. FriCAS expression is a parametric domain.
> If nothing interesting is known about the parameter, then FriCAS
> represents expression essentially as trees and does almost no
> simplifications.
Could you give an example of defining Expression over a domain where
"nothing interesting is known"? I tried several things but so far I
have been unable to produce an example of a value in such a domain.
> ...
> If you do not go into details it is very similar to what other
> systems do, but details differ. AFAIK officialy Mathematica
> uses pure tree representation for expressions but almost
> surely converts to something like rational functions of
> kernels for computations.
I know Maple fairly well and I would say that this does not accurately
describe what Maple does. Besides very simple "automatic"
simplifications, Maple does very little re-writing of the original
input expression. All the real work is done by operations applied
later to the expression tree such as "simplify", "expand" etc.
I FriCAS (and other incarnations of Axiom) it seems to me that usually
'simply' does very little. Effects like '
How could one distinguish between a "pure tree representation" versus
"rational functions of kernels" in Mathematica. Aren't these both
"expression trees"? How is this different from simply rewriting
expression trees?
> Macsyma/Maxima give user a choice between
> tree representation and rational function representation,
> but sometimes automatically switches representations.
>
Like Maple in Maxima there are operations such as "full_simplify"
which attempt to reduce expressions to some canonical "simple" form.
It seems to me that most automatic simplifications are avoided.
I think Reduce is a good example of a CAS where there is a serious
attempt to automatically reduce expressions to canonical form but even
here there are many times when this must be avoided for specific types
of calculations.
Regards,
Bill Page
best regards,
Franz
See below. If you look closely at the exports in expr.spad, then you see
that one cannot really do much with such a domain.
Ralf
(1) -> E := EXPR STRING
(1) Expression(String)
Type: Type
(2) -> e1: E := x1
(2) x1
Type:
Expression(String)
(3) -> e2: E := x2
(3) x2
Type:
Expression(String)
(4) -> paren e1
(4) (x1)
Type:
Expression(String)
(5) -> e1+e2
There are 11 exposed and 7 unexposed library operations named +
having 2 argument(s) but none was determined to be applicable.
Use HyperDoc Browse, or issue
)display op +
to learn more about the available operations. Perhaps
package-calling the operation or using coercions on the arguments
will allow you to apply the operation.
Cannot find a definition or applicable library operation named +
with argument type(s)
Expression(String)
Expression(String)
Perhaps you should use "@" to indicate the required return type,
or "$" to specify which version of the function you need.
I'm not sure whether that helps, but maybe you have to say something like
foo := operator 'foo
and look into ES for more about manipulation.
You can certainly build you own expression tree domain for your
manipulations.
Ralf
Franz
You cannot have Symbol, because you cannot sensibly hide information in
there. The only thing would be to build a new domain that encapsulates
your data but behaves to the outside world like Symbol (i.e. same
category as Symbol has). I fear, however, that Symbol is explicitly
needed and not such a boxed domain that I've described.
I'll have to look at it in more detail. But maybe you give a more
explicit example of what exactly you want to do. Just do so as if you
could box up your things and extract afterwards. I'd like to see a
concrete scenario.
Ralf
You can hide in an operator whatever you want. Look at RECOP.
Martin
In fact a polynomial ring would be enough at the moment,
but I didn't even figure out how to do that yet.
Franz
Still not completely clear. As far as I understand f and g basically
serve as tags for elements of your free monoid. What kind of structure
is the above (formal) sum of products? Let's just write elements of you
free monoid with y if it appears inside g, then the above would be
something like
x_1 x_2 x_1 y_3 y_4 + x_1 y_3 + ...
Right? So this could be considered as a monoid ring element of
ZM where Z denotes integers, and M is the (disjoint) union of your given
FreeMonoid X with itself (in the second copy the elements are denoted by
y instead of x).
You want all terms where (roughly speaking) x appears in exactly power
3, right?
> In fact a polynomial ring would be enough at the moment,
> but I didn't even figure out how to do that yet.
Oh, it would take a bit more time for me to figure out the details, but
I am sure you are able to find yourself how to construct a monoid ring
in FriCAS, the rest basically comes for free. AND there is *no* need for
Expression!!!
But maybe you haven't told me the full story and your f,g expressions
are much more complicated.
Ralf
> Oh, it would take a bit more time for me to figure out the details,
> but I am sure you are able to find yourself how to construct a
> monoid ring in FriCAS, the rest basically comes for free. AND there
> is *no* need for Expression!!!
As I said, for the moment that would do and I will figure out something.
But still I was wondering whether it would be possible to
incorporate some kind of 'rich' symbols in Expression Integer.
Franz
'=' for expressions is equality of representations. This not
always agrees with mathematical equality.
> In
> principle a domain can use a non-canonical representation and then
> define equality in a computationally intensive manner or even
> incomplete (possibly non-terminating) manner. But FriCAS does not
> currently permit equality to be anything other than Boolean valued.
'=' may produce whatever type we need. The real problem is that
result of equality tests is used to make decisions in code and
having say 'if' the 'then' part either will be executed or not,
which forces boolean result. So FriCAS premits equality of
arbitrary type, but useful equality is boolean (no matter if
in FriCAS or in other system). In principle equality can
raise exceptions ("can not decide") but that does not change
too much.
>
> >
> > Details of representaion used and empleyed "simplifications" vary
> > from system to system. =A0FriCAS expression is a parametric domain.
> > If nothing interesting is known about the parameter, then FriCAS
> > represents expression essentially as trees and does almost no
> > simplifications.
>
> Could you give an example of defining Expression over a domain where
> "nothing interesting is known"? I tried several things but so far I
> have been unable to produce an example of a value in such a domain.
>
For experiments I am using the following domain:
)abbrev domain IBT IntegerAsComparable
IntegerAsComparable : Join(BasicType, Comparable,
ConvertibleTo Pattern Integer, PatternMatchable(Integer)) with
0 : () -> %
1 : () -> %
_- : % -> %
coerce : Integer -> %
coerce : % -> Integer
== Integer add
coerce(n : Integer) : % == n pretend %
coerce(x : %) : Integer == x pretend Integer
after you compile it you can do:
ET:=Expression(IntegerAsComparable)
(6) -> 1::ET
(6) 1
Type: Expression(IntegerAsComparable)
(7) -> sin := operator 'sin
(7) sin
Type: BasicOperator
(8) -> sin(1::ET)
(8) sin(1)
Type: Expression(IntegerAsComparable)
(9) -> _+ := operator '_+
(9) +
Type: BasicOperator
(10) -> sin(_+(1::ET, 2::ET))
(10) sin(+(1,2))
Type: Expression(IntegerAsComparable)
Basically, declare whatever operators you need and build a tree
from them. You can also analyse the tree and rewrite it.
Currently tree rewriting is rather unpleasent because pattern
matching does not work on general expressions. But it is not
hard to extend pattern matcher (I am experimenting with such an
extension), the main problem is that currently pattern matcher
assumes that '*' is commutative which is not appropriate for
fully general expressions (pattern matcher also assumes that
'+' is commutative but I feel that this is acceptable: using
'+' for noncommutative operation would be quite confusing,
while noncommutative '*' happens quite frequently).
> > ...
> > If you do not go into details it is very similar to what other
> > systems do, but details differ. =A0AFAIK officialy Mathematica
> > uses pure tree representation for expressions but almost
> > surely converts to something like rational functions of
> > kernels for computations.
>
> I know Maple fairly well and I would say that this does not accurately
> describe what Maple does. Besides very simple "automatic"
> simplifications, Maple does very little re-writing of the original
> input expression. All the real work is done by operations applied
> later to the expression tree such as "simplify", "expand" etc.
>
That I consider detail.
> I FriCAS (and other incarnations of Axiom) it seems to me that usually
> 'simply' does very little. Effects like '
>
> How could one distinguish between a "pure tree representation" versus
> "rational functions of kernels" in Mathematica. Aren't these both
> "expression trees"? How is this different from simply rewriting
> expression trees?
If system internally changes representation and does not expose
any relatad operation than as long as it works correctly you
should not be able observe this from results. External
observer could make some deductions based on timing and bugs,
but in practice if you want to discuss this deeper you need
to find insider willing to share information.
> > =A0Macsyma/Maxima give user a choice between
> > tree representation and rational function representation,
> > but sometimes automatically switches representations.
> >
>
> Like Maple in Maxima there are operations such as "full_simplify"
> which attempt to reduce expressions to some canonical "simple" form.
> It seems to me that most automatic simplifications are avoided.
>
> I think Reduce is a good example of a CAS where there is a serious
> attempt to automatically reduce expressions to canonical form but even
> here there are many times when this must be avoided for specific types
> of calculations.
>
Personally I think that FriCAS is doing too much simplifications
automatically. For example most special functions can be
represented as instances of Meijer G function. We could
internally implement some algorithms only for Meijer G function
and convert to/from Meijer G form as needed. But if we
allow any automatic simplification which changes Meijer G
to simpler form, then algorithms based on Meijer G representation
may be broken.
This is a bit tricky because currently some parts of FriCAS
assume very eager simplification (for example 'numeric' would
be broken otherwise), while in other places we depend on
having very specific form (and simplifications that would
change such form are not allowed).
--
Waldek Hebisch
heb...@math.uni.wroc.pl
As Martin wrote use operators. Main difference between nullary
operator and symbol is that you can attach extra data to operators
but can not to symbols. ATM there is no way to attach extra
information directly to expressions. In principle we could
add a special kind of kernel for this purpose, but I am not
sure how much this is needed. Currently AFAIK Martin needs
extra data in RECOP and I needed parameter counts for
'meijerG' and 'hypergeometricF'. Martin uses data attached to
operators and ATM I restricted special functions to base
domains which contain integers, so I can store integers just
as subexpressions.
--
Waldek Hebisch
heb...@math.uni.wroc.pl
It's actually not that easy.
log actually can appear in several ways. Just think about what log
actually is. It's not a function, right? What is log(0)? But if you want
to take the function view, you can have
log: P -> R
log: X -> C
where P denotes the positive real numbers, C is the complex numbers, X
is complex numbers without non-positive real numbers.
If you look at this from a categorial point of view then the above
"function" are different because source and target are different. (I
have not even yet said how one would represent that in FriCAS. -- You
couldn't with ELEMFUN, because it says D->D for the same source and
target. You cannot for another reason. Real numbers are in no CAS. There
are only things like Float (arbitrarily precise floating point numbers
(finite precision, however)), but no computer can represent all real
numbers.
> Basically it seems ELEMFUN to be just all types where log functions
> was defined. Unfortunately firefox couldn't find anything with "elem"
> in http://www.axiom-developer.org/axiom-website/bookvol10.2full.svg
> How do I figure out what types are contained in
> ElementaryFunctionCategory?
That's hard if you don't use HyperDoc. Usually if you start fricas,
there should be a window poping up that has "HyperDoc" in its title.
Click on "Browse".
Enter "ELEMFUN" and click on "Constructors".
Click on "Domains".
You should now see a list of all domains that export
ElementaryFunctionCategory.
Maybe that's also possible with the command line, but I don't know.
> (well, its a constructor, not a category
> itself, but I hope you'll understand what I need).
Ehm, what do you mean by that. In my understanding the union of all
domains and categories is called "constructors". I usually use
"constructor" in the context of FriCAS without caring whether or not
there are any arguments. It "constructs" a "type" instead of an
"element". I hope, I don't confuse you now.
> As soon as log has
> indeed type of D -> D, how can I prescribe (manually) something
> meaningful to D? I mean something used in everyday/applied math ---
> algebra structures, various mappings, real numbers etc, but not
> expressions:
>
> (13) -> log f
>
> Function Selection for log
> Arguments: VARIABLE(f)
>
> [1] signature: EXPR(INT) -> EXPR(INT)
> implemented: slot $$ from EXPR(INT)
>
>
> (13) log(f)
> Type:
> Expression(Integer)
I know that must be confusing, but now this log here is an expression
(i.e. an element of the Expression(Integer) domain. Expression(Integer)
itself belongs to the category ElementaryFunctionCategory. So it exports
a signature "log: %->%" where the % here is basically the same as the D
above and for this concrete instance means "Expression(Integer)". In
fact, it just means THIS-DOMAIN, but your domain is Expression(Integer).
To make it a bit clearer. log can be used in FriCAS like an actual
function, but then it is always applied and you have no handle on the
function object itself, because then it is not an expression.
(4) -> CC:=Complex Float
(4) Complex(Float)
Type: Type
(5) -> cc:CC:=2.0
(5) 2.0
Type: Complex(Float)
(6) -> log cc
(6) 0.6931471805 5994530942
Type: Complex(Float)
However, what you still can do, is to assign log to a variable.
(7) -> foo: CC->CC := log
(7) theMap(COMPCAT-;log;2S;81,303)
Type: (Complex(Float) -> Complex(Float))
(8) -> foo 1.0
(8) 0.0
Type:
Complex(Float)
You can even do operations with that function.
(9) -> bar := foo*foo
(9) theMap(MAPPKG3;*;MMM;6!0,303)
Type: (Complex(Float) -> Complex(Float))
(10) -> bar cc
(10) - 0.3665129205 8166432701
Type:
Complex(Float)
(11) -> log log cc
(11) - 0.3665129205 8166432701
Type: Complex(Float)
I hope that all helps you to get more into FriCAS.
Best regards
Ralf
OK, again. If you type
log(x*y)
then the interpreter has to turn this string of characters into a
sensible FriCAS object. Just think about what this could be.
It must live in some FriCAS domain. But which one? So the interpreter
tries to guess. there are 4 symbols log, x, *, y. Nothing is known about
x and y, so they are first interpreted as variables.
(1) -> x
(1) x
Type: Variable(x)
(2) -> y
(2) y
Type: Variable(y)
* is special. It has some default interpretation in the interpreter. In
particular it's know that it's an infix operator of type (D, D) -> D for
some D. Now what is the D? Input D would be something like Variable,
because x and y are. But then the result type D would also be Variable.
FriCAS knows that x*y is not a variable, so it looks for a superdomain P
of Variable that allows for a function *: (P, P)->P. Polynomial(Integer)
is such a domain.
(3) -> x*y
(3) x y
Type: Polynomial(Integer)
Then there is log. I am not sure how much the interpreter knows about
log, but the general idea is as with *. log looks like an operator so
the interpreter has to look for a function log: X -> Y for some X (that
must be a superdomain of P) and some Y. It detects that Expression
Integer (I'll abbreviate that as E) fits for X and Y.
(4) -> log(x*y)
(4) log(x y)
Type: Expression(Integer)
At this time log(x*y) is a proper thing that is of type
Expression(Integer). Everything is fine for FriCAS.
But as you see now, FriCAS considers x and y now as elements of type E.
If you haven't said anything about the type of x and y before you write
the log(x*y) expression, then now it is too late.
So let's go back. Suppose you have said
(1) -> x: Complex(Float)
Type: Void
(2) -> y: Complex(Float)
Type: Void
Now, you should be aware that x, y are like ordinary programming
variables. They are no longer indeterminates as before. FriCAS just
knows that they have a representation that is the same as for every
element of type Complex(Float). It just happens that for some strange
reason FriCAS allows you to declare the type of x and y, but don't give
a value. (I actually believe that this (mis-)feature should be removed
from the Interpreter.
Then it is clear that
(3) -> x*y
x is declared as being in Complex(Float) but has not been given a
value.
fails. The result should be Complex(Float), but if there are no values
then what would you expect FriCAS to do?
I'm sure you will have more questions.
Ralf
log(x*y) = log(x) + log(y)
is valid in many cases even if logs involved are not real.
Currently FriCAS uses 3 different approaches to decide if it
should apply given simplification:
- sometines it performs deductions based on variables ranges
(this is possible for definite integrals and limits)
- sometimes FriCAS makes assumption based on types: for
Expression(Integer) FriCAS in few places assumes that values
are real (while Expression(Complex(Integer)) is regared as
complex). This really is not sound: sqrt(-1) is of type
Expression(Integer) and is not real.
- some functions assume that user/caller verified that
simplification is possible -- for example normalize is
in this group. This would be sound if all callers
verified assumptions, but currently this means that
assumptions "propagate" in a way that is hard to understand
for users.
Let me mention variation on point 3 above: simplification
may be invalid if you think about single-valued functions
but both input and output are multivalied functions such
that results after simplification are equivalent. For example:
integrate(log(f(x)*g(x), x)
is defined only up to a constant, so we get equivalent
result from:
integrate(log(f(x)), x) + integrate(log(g(x)), x)
This is really not satisfying and we would like to do better.
But the problem is hard (other systems have troubles too) and
types (at least as currently used in FriCAS) does not really
help here.
--
Waldek Hebisch
heb...@math.uni.wroc.pl
Just a warning. In SPAD this means
poissonBracket f g is the same as poissonBracket(f(g)).
> In this example q and p have type SYMBOL. Does it mean I need
> something like a constructor for SYMBOL that would take INT as an
> argument? Some kind of function INT -> SYMBOL.
(1) -> )display op subscript
There is one exposed function called subscript :
[1] (Symbol,List(OutputForm)) -> Symbol from Symbol
You can easily turn an integer into a proper second argument for that
function.
(1) -> subscript(x,[1::OutputForm])
(1) x
1
Type: Symbol
Ralf
(3) [p ,p ,p ]
1 2 3
Type: List(Symbol)
(4) -> PoissonBracket(f, g) == D(f, q 1) * D(g, p 1) - D(f, p 1) * D(g, q 1)
Type: Void
(5) -> Hamiltonian == (p 1)^2 + (q 1)^2
Type: Void
(6) -> PoissonBracket(p 1, Hamiltonian)
Compiling function q with type PositiveInteger -> Symbol
Compiling body of rule Hamiltonian to compute value of type
Polynomial(Integer)
Compiling function PoissonBracket with type (Symbol,Polynomial(
Integer)) -> Polynomial(Integer)
(6) - 2q
1
Type: Polynomial(Integer)
> q i == subscript(q, [1::OutputForm])
> since it is recursion (no wonder though). Is there a way to have a
> single notion "q" for several entities?
Well, now you just see two q, but they mean different things. The first
q is a function Integer -> Symbol. OK, more exactly, I should have defined
q(i:Integer):Symbol == subscript('q, [i::OutputForm])
Now we come to the subscript function. It's of type
(Symbol, List(OutputForm) -> Symbol
So if you write q as it's first argument, it must be of type Symbol,
otherwise it would be rejected as an argument of subscript. So the q of
type Integer->Symbol is clearly not of type Symbol, so it is ruled out
or rather the error message shows you that there is no function
subscript with the argument types that you have supplied.
But what is the q then in the argument of subscript? In my definition
above, I've made it more explicit. I've prepended it with ' which means
that the thing following it is considered a symbol, i.e. something that
has no meaning and is different from the q of type Integer->Symbol.
Does it make things more clear to you?
Ralf
PS: I still hate Expression(?) since with a little more thought one can
almost always do better (and in the end faster). You should just use it
for initial experiments until you understand the type system in more
detail. If you stop learning FriCAS at the level of Expression, you are
not using FriCAS to its full power and are rather on equal footing with
other typeless CAS.
Now what should be the type of this exp operation. Please avoid
Expression(...). It's a serious question. I accept a pure mathematical
answer, but be very specific with every detail.
After that my next question will be: How can that be made algorithmic in
general? You probably want an answer in finite time. Or would you accept
approximate values for this "exp"?
Ralf
Do you realize that the 'exp' in this formula is just a shorthand
notation for solution of appropriate differential equation?
If you want to do some symbolic manipulation on it than you
may define an operator and work in Expression(Integer).
However, you should use some different name than 'exp', say:
my_exp := oprator 'my_exp
my_exp(PoissonBracket(f, Hamiltonian))
Note: I have used here _value_ of PoissonBracket(f, Hamiltonian)
as argument to 'my_exp'. In FriCAS it is not possible to
perform symbolic manipulations on _functions_, one have to
use expressions. Note that if f is sufficiently general
then this expression will behave like a function.
OTOH there are only few simplifications possible for 'my_exp'
and you would have to code them (for example as rewrite rules),
so you may prefer using series instead of expressions.
BTW: If your functions are simple enough FriCAS may be able
to find closed form solution and effectively compute 'my_exp'.
However, most interstiong equations do not have closed form
solution and even if they have it is possible that FriCAS
will miss it. So I would not count on being able to
compute 'my_exp' explicitely. But if you have explicit f
and explicit Hamiltonian it makes sense to try.
> >After that my next question will be: How can that be made algorithmic in
> general? You probably want an answer in finite time. Or would you
> accept
> approximate values for this "exp"?
>
> Yes approximate will do, ultimately all these symbolic stuff is
> required to produce a numeric functions. So its not to be some real
> exponent, but rather a finite term series (at least ~32 terms in the
> series). Well, lets call it MyExp to avoid confusion.
>
Then you may wish to look at FriCAS power series machinery. There
is a function that given a (nonsingular) differential equation will
produce power series solution. Of course, in practice you get
only finitely many terms, but you may ask for more and the number
of terms is only limited by computer memory and time.
However to use solver for power series you need a single
parameter for expansion (time is good candidate). You can
keep other parameters symbolic.
--
Waldek Hebisch
heb...@math.uni.wroc.pl
Actually, MyFunc got miscomplied and crashed during evaluation.
You do not have problem with blocks. The problem is with
local functions: I would say that local functions using '=='
notation are not supported in the interpreter (they work
in the Spad compiler). Your example can be rewritten in
the following way:
MyFunc : Float -> Float
MyFunc x ==
a : Integer -> Float := i +-> x^i
reduce(+, map(a, [0,1,2,3,4]))
that is using '+->' notation to create anonymous function and
assigning this function to 'a'. Examples like this do not
need separate function and can be written as:
MyFunc x ==
reduce(+, map(i +-> x^i, [0,1,2,3,4]))
--
Waldek Hebisch
heb...@math.uni.wroc.pl
---rhxBEGIN m.spad
)abbrev package MYEXP MyExp
MyExp(F: Ring): with
myexp: F -> F
myexp: (F, PositiveInteger) -> F
== add
myexp(x: F, n: PositiveInteger): F ==
y: F := 1
z: F := 1
for i in 1..n repeat
z := z * x
y := y + z
y
myexp(x: F): F == myexp(x, 10)
---rhxEND m.spad
That's generic code and has to be compiled. Look at the types of the result.
Ralf
(3) -> )clear all
All user variables and function definitions have been cleared.
(1) -> )compile m.spad
(1) -> myexp(0.1)
(1) 1.1111111111
Type: Float
(2) -> myexp(0.1,4)
(2) 1.1111
Type: Float
(3) -> myexp(2,4)
(3) 31
Type: PositiveInteger
(4) -> myexp(2/3,4)
211
(4) ---
81
Type: Fraction(Integer)
Maybe you like to study
http://axiom-wiki.newsynthesis.org/FunWithFunctions
in deep detail, so that you get a bit more familiar with types.
I've not included the PoissonBracket, but maybe after having studied the
above site, you get a feeling of how you can do that yourself as a
little exercise.
Just open up a sandbox. I'll correct your attempts if you run into
troubles under the condition that you don't use Expression.
Ralf
)abbrev package MYEXP MyExp
MyExp(F: Ring): public == private where
public ==> with
myexp: F -> F
myexp: (F, PositiveInteger) -> F
private ==> add
myexp(x: F, n: PositiveInteger): F ==
lif : List F := [1,2::F]
reduce(_+,lif) --[1,2,3,4])
.. and then:
myexp(0,58)
(2) 3
Type: PositiveInteger
> --
> You received this message because you are subscribed to the Google Groups "FriCAS - computer algebra system" group.
> To post to this group, send email to fricas...@googlegroups.com.
> To unsubscribe from this group, send email to fricas-devel...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/fricas-devel?hl=en.
>
Mit freundlichen Grüßen
Johannes Grabmeier
Prof. Dr. Johannes Grabmeier
Köckstraße 1, D-94469 Deggendorf
Tel. +49-(0)-991-2979584, Tel. +49-(0)-171-5503789
Tel. +49-(0)-991-3615-100 (d), Fax: +49-(0)-1803-5518-17745
Yes, and it is good that it doesn't!
The reason, why this
>> myexp(x: F, n: PositiveInteger): F == reduce(+,[1,2,3,4])
doesn't work is the following.
Obviously you want F as the result type. So try
)display operations reduce
on the command line or rather use HyperDoc for a nicer form of output.
(For HD enter "reduce" in the browse field and click operations and then
Signatures.)
In order to figure out which functions you actually meant in your
reduce(+,[1,2,3,4]) expression, the compiler collects every possible
function with name "reduce" and tries to match types with the given
arguments.
Your use of reduce has 2 arguments. So you can rule out every reduce
function with just one or more than 2 arguments. So what remains is
reduce: ((S, S) -> S, X) -> S
For some yet unknown types S and X.
Since you want reduce to return something of type F, the compiler
already knows that it must look for a function
reduce: ((F, F) -> F, X) -> F
The first argument + must now be of type (F,F)->F. That's now simple,
because the domain F exports such a function.
If you click in hyperdoc on the respective reduce: ((S,S)->S,%)->S,
you'll see more explanation. In particular you find "Origin: Collection(S).
Now your second argument looks like a List. And a List is a Collection.
But it also means, it is Collection(S), and bringing all together, i.e.
S=F in your case, means, that in order to find a reduce function, the
second argument [1,2,3,4] must be of type List(F).
But [1,2,3,4] is (without any implicit conversion) not of type List(F),
it rather looks like being of type List(PositiveInteger).
So the compiler does not find anything appropriate and thus must
complain to the user.
As Johannes sugested, you have to provide *explicit* coercions using
"::F" or you simply do as I have done in my original code.
myexp(x: F, n: PositiveInteger): F ==
y: F := 1
z: F := 1
for i in 1..n repeat
z := z * x
y := y + z
y
I was careful to give y and z the type F from the beginning.
Ralf
Well, I am not 100% sure what happens here, but I guess the spad
compiler isn't able to bring your declaration a : PositiveInteger -> F
together with the following definition a i == x. And, actually, why
should it?
You have not given a type for i, so maybe you mean a function
a(i: String): F == x
Why should the compiler assume that in your definition a i == x the i
stands for a PositiveInteger?
You probably know that Spad allows you to define something like (*), see
below.
To make your code work, you would have to give the type of the argument.
But you can do without the signature declaration by giving explicit
types to the argument and the result type.
---rhxBEGIN myexp.spad
)abbrev package MYEXP MyExp
MyExp(F: Ring): with
myexp: (F, PositiveInteger) -> F
== add
myexp(x, n) ==
a(i: PositiveInteger): F == x
a n
---rhxEND myexp.spad
I seem to remember
http://groups.google.com/group/fricas-devel/msg/c6b9ac05fad9e74c?hl=en
that there was a problem with local function anyway.
According to Waldek, they should work in the compiler (and Waldek
probably knows best), but you might want think of it if you run into
troubles.
Ralf
(*)
=============================================================
)abbrev package MY My
My(F: Ring): with
a: String -> F
a: Integer -> F
== add
a(i: Integer):F == -i::F
a(i: String): F == 1
=============================================================
(1) -> F := Fraction Integer
(1) Fraction(Integer)
Type: Type
(2) -> H := My F
(2) My(Fraction(Integer))
Type: Type
(3) -> a 3
(3) - 3
Type: Integer
(4) -> a "x"
(4) 1
Type: PositiveInteger
BTW, don't get confused about the return types. The function a actually
returns something of type Fraction(Integer), but the interpreter tries
to turn this into a simpler type.
Yes, it's hard. But maybe you look at
http://www.aldor.org/wiki/index.php/User_Guides_for_Compiler_and_Libraries
Aldor developed from SPAD, but it's now a separate language and
unfortunately only semi-free and no longer developed. Obviously, Stephen
Watt is not interested in really putting it under a GPL compatible
license, otherwise he would have invested more energy to make that happen.
Still the Aldor User Guide is a good source to understand how SPAD
works. It's not completely one-to-one, but once you understand Aldor,
it's easy to map you knowledge to use SPAD.
> differences between .input and .spad syntax
That's basically easy. Think of .input files as the same syntax that you
use on the command line. The main difference with .spad is that the
compiler doesn't implicitly do some coercions. If in SPAD something is
of type SparseUnivariatPolynomial and doesn't involve a variable (i.e.
is a constant), it is still not of the type of the coefficient domain.
Nor would be a constant suddently be a polynomial. So the following
wouldn't work in the compiler
(1) -> (1$Integer = 1$Polynomial(Integer))@Boolean
(1) true
Type: Boolean
because there is no function
=: (Integer, Polynomial(Integer) -> Boolean
The interpreter, however, makes you mostly to forget about the types and
autocoerces the integer argument to Polynomial(Integer) and only then
applies the = function.
> It is the first time I have to ask people rather than reading a book
> or following a tutorial. I indeed appreciate your help.
No problem. Go on. We all know how steep the learning curve for FriCAS
is. And maybe some day we can convince you to help us improving that
learning curve. Writing down you experiences in how you got into FriCAS,
might probably help others in the future. (So maybe you start taking
notes for this already.) ;-)
Best regards
Ralf
The following works:
)abbrev package MYEXP MyExp
MyExp(F: Ring): with
myexp: (F, PositiveInteger) -> F
== add
Map2 ==> ListFunctions2(PositiveInteger, F)
myexp(x, n) ==
a(i : PositiveInteger) : F == x^i
myList : List(PositiveInteger) := [i::PositiveInteger for i in 1..10]
reduce(_+@((F, F) -> F), map(a, myList)$Map2)
Basic problem is that 'map', 'reduce' and '+' are very unspecific,
you need to say something more to force correct type. Above
I wrote that I want function '+' of given type. The second problem is
that there is quite a lot of functions 'map' and most of them
was invisible (not imported). In particular the 'List' domain
contains only homogeneous 'map' functions, that is 'map' from
List(PositiveInteger) to List(PositiveInteger). The
'map' from List(PositiveInteger) to List(F) is in ListFunctions2.
Alternatively, in the last line one can write:
reduce(_+, map(a, myList)$Map2)$List(F)
Once it is specified that 'reduce' is from List(F) compiler sees that
there is only one two-argument 'reduce' in List(F) and it requires
something of type '(F, F) -> F' so it can choose correct '+'.
>
> So far I've learned something about local functions. In local
> functions one cannot
> 1) use "myfunc : A -> B" syntax to prescribe types before the
> implementation of the myfunc. One should use C-like type notion.
> 2) use functions without arguments (== won't do, only :=)
>
> Anything else?
>
Message like:
$x:= +
$m:= $EmptyMode
means that FriCAS can not determine type for '+'. Typical
reason is missing declaration. Also frequently appropriate
definition is not imported (and hence invisible) or it
is too complex for FriCAS to find matching definition. In
such cases try to make things more explicit by saying where
to find functions (by using $) and maybe also expected type
(needed is there are multiple functions which differ only
in return type).
The same applies when FriCAS says that it wants type T1 but
the offending expression has type T2.
> I wonder how do people learn Spad at all. I've looked through volume
> 0, 2 (that one was a bit strange), axiom wiki, but nothing devoted to
> Spad itself. At least nothing concerning the differences
> between .input and .spad syntax or local functions technicalities.
> Maybe I've overlooked something.
>
Actually chapters 11, 12 and 13 in Axiom Book (you can see it via
HyperDoc) contain main part different than interpreter. Chapter 2,
6 and 10 contain material about interpreter but are intended to
apply also to Spad. Yes, that is rather sparse reference, but
AFAICS all Spad contructs are there.
Note that "interpreter" and Spad compiler are two different
compilers which intend to implement essentially the same
language. One intended difference is that "interpreter"
tries hard to "guess" types while compiler signals errors.
Most of differences are considered bugs and we try to elliminate
them if possible.
Differences between .input and .spad syntax or local functions
technicalities are rather specialised knowledge. And they
change, for example '+->' in Spad files is from March 2009
which given Axiom/FriCAS history is quite recent (before that
Spad compiler used quite different notation).
We certainly need more material on Spad programming. And
please, keep asking questions -- that way we know what
needs to be explained. Also, real questions is the
best source of examples.
--
Waldek Hebisch
heb...@math.uni.wroc.pl