> Is there an easy way to get a linear output (not 2d-output), i.e.,
> which looks exactly like the input?
(1) -> x+y^2
2
(1) y + x
Type: Polynomial(Integer)
(2) -> (x+y^2 )::INFORM
(2) (+ (** y 2) x)
Type: InputForm
(3) -> unparse((x+y^2 )::INFORM)
(3) "y^2+x"
Type: String
This is, in my opinion a hack, in case you want linear *output*. It
should be relatively easy though, to provide something similar to
TexFormat, that provides a coercion from outputform to "linearform".
Would actually be nice.
Martin
Martin,
Do you mean something like?
)set output linear on
Note also that
y^2+x
is not syntactically identical to the input
x+y^2
I wonder why FriCAS changes the order?
Regards,
Bill Page.
I don't yet know what unparse does, but do you think that
lin z == unparse(z::InputForm)::Symbol::OutputForm
should do the job also for other expressions than polynomials?
Seems to be working for matrices...
(5) -> m:=matrix [[1,2],[3,4]]
+1 2+
(5) | |
+3 4+
Type: Matrix(Integer)
(6) -> lin m
Compiling function lin with type Matrix(Integer) -> OutputForm
(6) matrix([[1,2],[3,4]])
Type: OutputForm
Thanks a lot!!!
Ralf
> I don't yet know what unparse does, but do you think that
>
> lin z == unparse(z::InputForm)::Symbol::OutputForm
>
> should do the job also for other expressions than polynomials?
well...
(5) -> sum(1/i, i=1..n)::INFORM
(5) (%defsum (/ 1 %G) %G i 1 n)
Type: InputForm
One idea we had is that InputForm preserves the semantics *exactly*, and
another function possibly pretends that we'd be using the interpreter,
and thus assumes the interpreter's environment.
At least I for one am strongly in favour of that idea, and even with
this in mind, (5) above is a bug.
(11) -> unparse(integrate(%e^(x^2), x)::INFORM)
(11) "integral(exp(x^2),x::Symbol)"
Type: String
is another example. Note that integral *is* a function, so the result
of INFORM is quite OK...
In summary, it really depends on what you want to do.
Martin
| Ralf Hemmecke <ra...@hemmecke.de> writes:
|
| > Is there an easy way to get a linear output (not 2d-output), i.e.,
| > which looks exactly like the input?
|
| (1) -> x+y^2
|
| 2
| (1) y + x
| Type: Polynomial(Integer)
| (2) -> (x+y^2 )::INFORM
In OpenAxiom, I get
(1) -> (x + y^2)::InputForm
(1) y^2 + x
Type: InputForm
-- Gaby
OK, but what is the purpose of %G in the above expression? Woulnd't be
(%defsum (/ 1 i) i 1 n)
enough information th reconstruct the sum expression?
Ralf
> On Wed, Jun 3, 2009 at 8:35 AM, Martin Rubey wrote:
>> This is, in my opinion a hack, in case you want linear *output*. It
>> should be relatively easy though, to provide something similar to
>> TexFormat, that provides a coercion from outputform to "linearform".
>> Would actually be nice.
>>
>
> Martin,
>
> Do you mean something like?
>
> )set output linear on
Well, it may be nice to have a switch in the interpreter as this
suggests, but that's not my primary concern. My primary concern is to
have well defined and document coercions from OutputForm to whatever,
i.e., LaTeX, possibly TeX, html, text, linear text, etc.
> Note also that
>
> y^2+x
>
> is not syntactically identical to the input
>
> x+y^2
>
> I wonder why FriCAS changes the order?
Because the semantics is the same. Currently, + is always commutative I
think, but compare:
(18) -> a:XPOLY INT := y*x
(18) y x 1
Type: XPolynomial(Integer)
(19) -> b:POLY INT := x*y
(19) x y
Type: Polynomial(Integer)
well, embarassingly enough, there is no INFORM for XPOLY :-(
Martin
> Note also that
>
> y^2+x
>
> is not syntactically identical to the input
>
> x+y^2
> I wonder why FriCAS changes the order?
Oh, this is clear... The input x+y^2 is first interpreted and then
evaluated to something of type POLY(INT). Then the *result* is
transformed to InputForm. Since in POLY(INT) + is commutative, the
result makes perfect sense.
I wouldn't have expected to get exactly my input back.
Ralf
>> (5) -> sum(1/i, i=1..n)::INFORM
>>
>> (5) (%defsum (/ 1 %G) %G i 1 n)
>> Type: InputForm
>>
>> One idea we had is that InputForm preserves the semantics *exactly*, and
>> another function possibly pretends that we'd be using the interpreter,
>> and thus assumes the interpreter's environment.
>
> OK, but what is the purpose of %G in the above expression? Woulnd't be
It's a dummy variable. coerce@INFORM just doesn't work for sum,
product and possibly others.
> (%defsum (/ 1 i) i 1 n)
>
> enough information th reconstruct the sum expression?
No, the right thing would be something like
(sum (/ 1 i) (($elt (SegmentBinding (Expression (Integer))) equation) i
(($elt (Segment (Expression (Integer))) SEGMENT) 1 n)))
From that, we should retrieve the necessary information.
Martin
Cool! Was that done by a simple patch? What is the revision number?
I really wonder why in FriCAS I get
(^ y 2)
as the result of (1) above. That clashes with the name "InputForm",
since I cannot input that into a FriCAS session.
Ralf
Yes, thanks. Now I understand. In the expression:
(x+y^2 )::INFORM
'(x+y^2 )' is first fully interpreted by Fricas as a polynomial and
only then does it coerce (convert?) the result back to InputForm. To
do what I expected I guess one could write:
(1) -> unparse(parse("x+y^2")$InputForm)
(1) "x+y^2"
Type: String
Then no semantics are involved but if invoke the interpreter explicitly
(2) -> unparse(interpret(parse("x+y^2")$InputForm)::INFORM)
(2) "y^2+x"
Type: String
then of course I get the result you showed.
> Currently, + is always commutative I think, but compare:
>
> (18) -> a:XPOLY INT := y*x
>
> (18) y x 1
> Type: XPolynomial(Integer)
> (19) -> b:POLY INT := x*y
>
> (19) x y
> Type: Polynomial(Integer)
>
> well, embarassingly enough, there is no INFORM for XPOLY :-(
>
Of course there should be such a coercion.
You are right that the result depends on the domain chosen by the interpreter.
Regards,
Bill Page.
Ralf
There are a some long threads about this on the open-axiom list and
even here on FriCAS in relation to the Sage interface for FriCAS.
I also like the way it is now down in OpenAxiom better than FriCAS and
original AXIOM.
Regards,
Bill Page.
I would argue that you are wrong. The above (5) looks like
x::INFORM
The question now is when should the interpreter stop evaluation.
I don't know much about the interpreter, but I guess first it builds an
expression tree (AST?) from that. So (internally that probably looks like
(coerce x INFORM)
(of course with the x replaced by the corresponding tree). Now if the
interpreter stops here, you get exactly that expression (probably of
type SExpression.
[1] But the interpreter goes on interpreting it by first evaluating x.
Once that evaluation is done you have no chance in general to get your
original input back.
[2] If the interpreter first evaluates "coerce" then it would be
possible to just transform the AST back into something that looks like
the original x, i.e. sum(1/i, i=1..n).
I guess, however, Axiom was designed to first evaluate the arguments, so
[1] applies. No?
Ralf
> I don't know much about the interpreter, but I guess first it builds an
> expression tree (AST?) from that. So (internally that probably looks like
>
> (coerce x INFORM)
>
> (of course with the x replaced by the corresponding tree). Now if the
> interpreter stops here, you get exactly that expression (probably of
> type SExpression.
>
> [1] But the interpreter goes on interpreting it by first evaluating x.
> Once that evaluation is done you have no chance in general to get your
> original input back.
Yes, and that's not the idea of INFORM either. Rather, entering the
result of x::INFORM into the interpreter (unparsed, of course), should
yield something that is semantically equivalent to x.
Martin
Once it starts the interpret never stops evaluation - unless it fails.
> I don't know much about the interpreter, but I guess first it builds an
> expression tree (AST?) from that. So (internally that probably looks like
>
> (coerce x INFORM)
>
> (of course with the x replaced by the corresponding tree). Now if the
> interpreter stops here, you get exactly that expression (probably of
> type SExpression.
The interpreter never stops there. But you can get the same effect if you write:
(1) -> parse("x::INFORM")$INFORM
(1) (:: x INFORM)
Type: InputForm
Technically the result is not an SExpression but internally InputForm
does use SExpression as the representation and there is a coerce to
SExpression if you really want it:
(2) -> %::SEX
(2) (:: x INFORM)
Type: SExpression
>
> [1] But the interpreter goes on interpreting it by first evaluating x.
> Once that evaluation is done you have no chance in general to get
> your original input back.
>
That is true in general except of course evaluating x yields something
of type Variable(x) which can be coerced back to an InputForm.
> [2] If the interpreter first evaluates "coerce" then it would be
> possible to just transform the AST back into something that looks
> like the original x, i.e. sum(1/i, i=1..n).
I do not completely understand what you wrote above but if the
evaluation yields something "symbolic" like an Expression (or
Polynomial or several other Axiom domains) :
(2) -> sum(1/i, i=1..n)
n
--+ 1
(2) > -
--+ i
i= 1
Type: Union(Expression(Integer),...)
then (usually) such symbolic expressions can be coerced back to
something "equivalent" to the original InputForm.
> I guess, however, Axiom was designed to first evaluate the arguments, so
> [1] applies. No?
>
I would say simply that Axiom always fully evaluates all inputs.
Regards,
Bill Page.
| > In OpenAxiom, I get
| >
| > (1) -> (x + y^2)::InputForm
| > (1) y^2 + x
| > Type: InputForm
|
| Cool! Was that done by a simple patch? What is the revision number?
it was done by a simple patch. I don't have the revision number; but I
do know that it generated protests when I did, so somehow one should get
the discussions archived.
[ I just came out of emergency so don't expect more from me today,
expect the "easy" part I can handle. ]
-- Gaby
Looks like r881 is the one you meant. Can you confirm?
Martin, is this in your interest? I somehow had the impression that you
have other ideas of what InputForm should be used for.
Ralf
----------------------------------------------------------------------
r2496 (orig r881): dos-reis | 2008-10-15 05:44:37 +0200
Changed paths:
M /openaxiom/1.2/src/ChangeLog
M /openaxiom/1.2/src/algebra/mkfunc.spad.pamphlet
M /openaxiom/1.2/src/interp/i-output.boot
M /openaxiom/trunk/src/ChangeLog
M /openaxiom/trunk/src/algebra/mkfunc.spad.pamphlet
M /openaxiom/trunk/src/interp/i-output.boot
* algebra/mkfunc.spad.pamphlet (coerce$InputForm): Display
InputForm as a one-dimensional stream of characters suitable
for input to the interpreter.
* interp/i-output.boot: Implement conversion of InputForm to
displayed OutputForm.
=============================================================
svn diff -r880:881
https://open-axiom.svn.sourceforge.net/svnroot/open-axiom/trunk > r881.patch
==== r881.patch =============================================
Index: src/ChangeLog
===================================================================
--- src/ChangeLog (revision 880)
+++ src/ChangeLog (revision 881)
@@ -1,5 +1,13 @@
2008-10-14 Gabriel Dos Reis <g...@cs.tamu.edu>
+ * algebra/mkfunc.spad.pamphlet (coerce$InputForm): Display
+ InputForm as a one-dimensional stream of characters suitable
+ for input to the interpreter.
+ * interp/i-output.boot: Implement conversion of InputForm to
+ displayed OutputForm.
+
+2008-10-14 Gabriel Dos Reis <g...@cs.tamu.edu>
+
* interp/i-spec2.boot (upQUOTE): Quoted forms belong to InputForm.
* interp/sys-constants.boot ($InputForm): New.
Index: src/algebra/mkfunc.spad.pamphlet
===================================================================
--- src/algebra/mkfunc.spad.pamphlet (revision 880)
+++ src/algebra/mkfunc.spad.pamphlet (revision 881)
@@ -1,21 +1,24 @@
\documentclass{article}
\usepackage{axiom}
+
+\title{src/algebra mkfunc.spad}
+\author{Manuel Bronstein}
+
\begin{document}
-\title{\$SPAD/src/algebra mkfunc.spad}
-\author{Manuel Bronstein}
\maketitle
\begin{abstract}
\end{abstract}
-\eject
\tableofcontents
\eject
+
\section{domain INFORM InputForm}
+
<<domain INFORM InputForm>>=
)abbrev domain INFORM InputForm
++ Parser forms
++ Author: Manuel Bronstein
++ Date Created: ???
-++ Date Last Updated: September 18, 2008
+++ Date Last Updated: October 14, 2008
++ Description:
++ Domain of parsed forms which can be passed to the interpreter.
++ This is also the interface between algebra code and facilities
@@ -191,6 +194,11 @@
s2 = 1 => s1
conv [convert("/"::Symbol), s1, s2]$List(%)
+ -- A displayed form of an InputForm should be suitable as
+ -- input to the interpreter parser.
+ coerce(x: %): OutputForm ==
+ inputForm2OutputForm(x)$Lisp
+
@
\section{package INFORM1 InputFormFunctions1}
<<package INFORM1 InputFormFunctions1>>=
Index: src/interp/i-output.boot
===================================================================
--- src/interp/i-output.boot (revision 880)
+++ src/interp/i-output.boot (revision 881)
@@ -2581,3 +2581,99 @@
form
if ^$collectOutput then PRETTYPRINT(u,$algebraOutputStream)
nil
+
+
+--% Rendering of InputForm
+
+$allClassicOps ==
+ ["~","#","-","**","^","*","/","rem","quo","+","-",
+ "@","::","$", "pretend"]
+
+isUnaryPrefix op ==
+ op in '(_~ _# _-)
+
+primaryForm2String x ==
+ x = nil => '""
+ STRINGP x => x
+ x = $EmptyMode => specialChar 'quad
+ IDENTP x => SYMBOL_-NAME x
+ atom x => WRITE_-TO_-STRING x
+ strconc('"(",inputForm2String x, '")")
+
+callForm2String x ==
+ atom x => primaryForm2String x
+ [op,:args] := x
+
+ op in $allClassicOps => primaryForm2String x
+
+ #args = 0 =>
+ op = "Zero" => '"0"
+ op = "One" => '"1"
+ constructor? op => primaryForm2String op
+ strconc(inputForm2String op, '"()")
+
+ "strconc"/[inputForm2String op, '"(",:args','")"] where
+ args' := [toString(a,i) for a in args for i in 0..]
+ toString(a,i) ==
+ i = 0 => inputForm2String a
+ strconc('",",inputForm2String a)
+
+typedForm2String(s,x,t) ==
+ s = "pretend" =>
+ strconc(primaryForm2String x, '" pretend ", callForm2String t)
+ strconc(primaryForm2String x, SYMBOL_-NAME s, callForm2String t)
+
+expForm2String x ==
+ x is [op,lhs,rhs] and op in '(** _^) =>
+ strconc(expForm2String lhs,'"^", primaryForm2String rhs)
+ callForm2String x
+
+unaryForm2String x ==
+ x is [op,arg] and isUnaryPrefix op =>
+ strconc(inputForm2String op, inputForm2String arg)
+ expForm2String x
+
+multForm2String x ==
+ x isnt ["*",lhs,rhs] => unaryForm2String x
+ strconc(multForm2String lhs,'"*", multForm2String rhs)
+
+divForm2String x ==
+ x isnt ["/",lhs,rhs] => multForm2String x
+ strconc(divForm2String lhs,'"/", expForm2String rhs)
+
+remForm2String x ==
+ x isnt ["rem",lhs,rhs] => divForm2String x
+ strconc(divForm2String lhs,'" rem ", multForm2String rhs)
+
+quoForm2String x ==
+ x isnt ["quo",lhs,rhs] => remForm2String x
+ strconc(quoForm2String lhs,'" quo ", remForm2String rhs)
+
+plusForm2String x ==
+ x isnt ["+",lhs,rhs] => quoForm2String x
+ strconc(plusForm2String lhs,'" + ", plusForm2String rhs)
+
+minusForm2String x ==
+ x isnt ["-",lhs,rhs] => plusForm2String x
+ strconc(minusForm2String lhs,'" - ", minusForm2String rhs)
+
+inputForm2String x ==
+ atom x => primaryForm2String x
+ [op,:args] := x
+ isUnaryPrefix op and #args = 1 => unaryForm2String x
+ #args = 2 =>
+ op in '(** _^) => expForm2String x
+ op = "*" => multForm2String x
+ op = "/" => divForm2String x
+ op = "rem" => remForm2String x
+ op = "quo" => quoForm2String x
+ op = "+" => plusForm2String x
+ op = "-" => minusForm2String x
+ op in '(_@ _:_: $ pretend) =>
+ typedForm2String(op, first args, second args)
+ callForm2String x
+ callForm2String x
+
+inputForm2OutputForm x ==
+ INTERN inputForm2String x
+
| Dear Gaby
|
| Looks like r881 is the one you meant. Can you confirm?
It may very well be this one. I think I had one more twist to make, but
I can't remember right now.
-- Gaby
%G is needed to properly track distinctions between free and
bound variables. Consider:
(12) -> D(sum(1/(i+a), i=1..n), i)
(12) 0
Type: Expression(Integer)
(13) -> D(sum(1/(i+a), i=1..n), a)
n
--+ 1
(13) > - --------------
--+ 2 2
i= 1 i + 2a i + a
Type: Expression(Integer)
(14) -> sum(1/(i+a), i=1..n)::InputForm
(14) (%defsum (/ 1 (+ a %BB)) %BB i 1 n)
Type: InputForm
To get correct derivative with respect to a it is enough to
differentiate expression under sum. But directly this would not
work for derivative with respect to i, because i is not free there.
However, after we replace i by dummy variable simple works again.
Similar things happens for substitutions -- without dummies
substitition would be much more complicated than it is now.
--
Waldek Hebisch
heb...@math.uni.wroc.pl
I would rather wrote:
lin(z) == message(unparse(z::InputForm))$OutputForm
The above avoid creating useless symbols.
> should do the job also for other expressions than polynomials?
>
Many domains miss or have wrong coercion to InputForm and the output
may be some large, but it is the best of what we have just now.
--
Waldek Hebisch
heb...@math.uni.wroc.pl
AFAICS the main reason to have InputForm is a need allow
using interpreter to evaluate elements Expression domain.
InputForm is really a hack which exposes interface between
interpreter parser and evaluator. This interface uses
s-expressions and the output above reasonably well shows
structure of it.
Note that InputForm is not intended as input to FriCAS session.
In fact, FriCAS takes input from strings and InputForm is quite
different than string. Main use of InputForm is to pass it
to interpret function (to evaluate it), which in turn allows
producing interpreter functions from expressions (needed for
plotting).
We could easily print InputForm in unparsed form, but it
is not clear how useful that would be. If you want linear
output the lin function from other post should give you
all that you can get via InputForm. OTOH, I think that
main reason to print InputForm is debugging functions
which process it. When debugging current output is better
because it shows tree structure of form, while unparsed
form makes it less clear. So I definitly prefer accurate
output to pretty, but less accurate one.
Note: even with different default output we still should
be able to see structure via convertion to SExpression,
so the objection is a weak one. But given that gettig
linear printout via lin(z) is about as complicated as via
z::InputForm my motivation to use the later for linear
printout is also weak.
--
Waldek Hebisch
heb...@math.uni.wroc.pl
Thank you for your explanation.
I must say, I would be somehow happier if InputForm actually was called
ParsedForm.
I would rather like to reserve the name InputForm for a form that looks
like what one can really feed to the interpreter on the command line.
But since such a InputForm would actually be identical to String, it is
probably not reasonable to introduce another domain.
Anyway, I think that the 'lin' function, maybe named
linearForm: InputForm -> OutputForm
should be added to the current InputForm domain.
If some domain isn't convertible to InputForm, that's bad luck for me
anyway.
Maybe we could modify Gaby's patch to use linearForm instead of his
+ -- A displayed form of an InputForm should be suitable as
+ -- input to the interpreter parser.
+ coerce(x: %): OutputForm ==
+ inputForm2OutputForm(x)$Lisp
I guess that would look a bit better than just
lin(z) == message(unparse(z::InputForm))$OutputForm
Ralf