Axiom/FriCAS Format Output

Proposal for a Change to The Way FriCAS Formats Output

The remainder of this page explains how FriCAS formats its output and proposes changes to the way that this works.

Why Change?

FriCAS can output mathematical expressions and structures in various formats such as text, TeX, mathML, html and so on. However it is hard to add new formats or change existing formats. There are lots of interesting possibilities for changes to interfaces but changes can be stifled due to the fragile state of existing code.

One of the main reasons for the existing difficulties is that the code is a mixture of 3 languages:

Swapping backward and forward between SPAD and Lisp is a problem because type information is lost and heavy use has to be made of the 'pretend' instruction which is considered bad practice. Bootcode is obscure and badly documented cross between Lisp and SPAD, for this reason it is very hard to work out what this code does.

There are plans to remove dependence on Lisp and bootcode in FriCAS and so the plan is to rewrite all of this purely in SPAD.

Introduction to Formatting Mathematical Output

There is a dilemma for the designers of a Computer Algebra Program (CAS) regarding the best way to specify the formatting of mathematical entities and expressions.

output formatters We want people to be able to specify new algebras by writing code using SPAD, of course this code will specify the mathematical structure but, how much code should be required to specify what the elements of this algebra will look like when they are displayed on some output device? Each algebra, such as matrix, complex numbers and so on, needs to be displayed in an appropriate way, but how to we specify that?

In computing, generally, many types of formatter consider it bad practice to mix formatting information in with content. For instance, when writing HTML documents, it is considered good practice to split out the formatting information into Cascading Style Sheets (CSS). This makes the content much more human readable and allows the formatting to be changed without danger of introducing errors.

I guess, in the case of CAS, there is no right or wrong answer. It just depends on what the designers want to optimise. Does the functionality go in each algebra domain, in which case the mathematics code is cluttered with boilerplate code for each output format, or does the functionality go in the drivers which gives less control over the output? Of course, this type of dilemma is not specific to CAS systems (see expression problem on Wiki).

intermediate form The compromise that the SPAD designers came up with is to have an 'intermediate format' for expressions to be output. This contains an expression with all the information semantic structure for doing the mathematical calculations removed and replaced with a presentation structure which specifies how it will be displayed. So,

All they both need to know about is the 'intermediate format', which reduces the number of interfaces considerably. But the intermediate format removes semantic structure and replaces it with presentation structure. This removal of semantic structure does put a lot of constraints, on things that it would be otherwise useful to do, as we will see below.

Current Implementation Details

implementation detail

Lets trace through how data gets from each algebra to the data formatters. This is all triggered when 'output' is called in i-output.boot, this then:

SPAD domains (algebras) typically have a coersion to OutputForm. Here is an example for complex numbers:
       coerce(x : %) : OutputForm ==
         re := (r := real x)::OutputForm
         ie := (i := imag x)::OutputForm
         zero? i => re
         outi := '%i::OutputForm
         ip :=
           (i = 1) => outi
           ((-i) = 1) => -outi
           ie * outi
         zero? r => ip
         re + ip

So when we want to output a representation of a complex number then, this code is run, to produce an instance of OutputForm.

Here we get to our first problem: OutputForm and SExpression (see yellow box on right) have a two-way link between them, that is:

Rep of OutputForm is 'SExpression'

and SExpression is

SExpressionOf(String, Symbol, Integer, DoubleFloat, OutputForm)

So, we can't change OutputForm without changing SExpression and visa-versa.

What OutputForm holds is a recursively defined structure which is effectively a tree of lisp types.

complex example

So here is an example of the OutputForm structure that might be created for a complex number.

What this holds is an intermediate form of an expression in a way that is not specific to any domain and can be understood by all the output formatters. This avoids cross-cut issues, that is, every domain does not need to know specifically about every output format.

This OutputForm structure then gets passed to the formatters that are active at the time.

These formatters need to do several things:

Waldek: Use of OutputForm in SExpression can be easily removed: related functions are only used in genufact.spad and fortran.spad. Deeper problem is that fortran.spad apparently assumes that OutputForm = SExpression and passes values to Boot code with little regard to types. Note that defining something like OutputForm2 will help only a little, because code in fortran.spad is supposed to work on OutputForm, so you would need to keep all current mess supporting OutputForm.

OutputForm

OutputForm is typically constructed in the domain coersions (is there anywhere else it is constructed?) .

The constructors for 'OutputForm' are all well typed, as we can see below, this is then stored in a more messy structure involving 'SExpression'. It also has a disadvantage that every operator symbol, like '+' needs its own constructor built in to Output form, this makes it difficult to add in potential new operators symbols such as:⊕. There are a lot of unicode symbols that would otherwise make the output more readable but are restricted by this mechanism.

Waldek: Concerning using more operators, note that all parts involved: coercion to OutputForm and formatters need to know about operators. To allow easy adding of new operators we would need a database storing operator properties, like priority, associativity, how to render it, etc. Currenty we have king of database using mixture of Lisp and Boot, but data is available only to Boot code and can not be used directly by Spad code. We probably also would need to generalize properties of operators, first, there are ordinary infix operators, but then big variants used in prefix form and frequently having some sorts of limits (like summation).

Here are the constructors for OutputForm, this effectively forms the interface between the domains and the output formatting code:

 -- OutputForm constructors
	
     --% Space manipulations
        hspace : Integer -> %  ++ hspace(n) creates white space of width n.
        vspace : Integer -> %  ++ vspace(n) creates white space of height n.
        rspace : (Integer, Integer) -> %
          ++ rspace(n, m) creates rectangular white space, n wide by m high.
        --% Area adjustments
        left : (%, Integer) -> %  ++ left(f, n) left-justifies form f within space of width n.
        right : (%, Integer) -> %  ++ right(f, n) right-justifies form f within space of width n.
        center : (%, Integer) -> % ++ center(f, n) centers form f within space of width n.
        left : % -> %  ++ left(f) left-justifies form f in total space.
        right : % -> %  ++ right(f) right-justifies form f in total space.
        center :   % -> %  ++ center(f) centers form f in total space.

        --% Area manipulations
        hconcat :  (%, %) -> %  ++ hconcat(f, g) horizontally concatenate forms f and g.
        vconcat :  (%, %) -> %  ++ vconcat(f, g) vertically concatenates forms f and g.
        hconcat :  List % -> %  ++ hconcat(u) horizontally concatenates all forms in list u.
        vconcat :  List % -> %  ++ vconcat(u) vertically concatenates all forms in list u.

        --% Application formers
        prefix :  (%, List %) -> %  ++ prefix(f, l) creates a form depicting the n-ary prefix
                                          ++ application of f to a tuple of arguments given by list l.
        infix :   (%, List %) -> % ++ infix(f, l) creates a form depicting the n-ary application
                                                        ++ of infix operation f to a tuple of arguments l.
        infix :   (%, %, %) -> % ++ infix(op, a, b) creates a form which prints as: a op b.
        postfix : (%, %)    -> % ++ postfix(op, a)  creates a form which prints as: a op.
        infix? : % -> Boolean  ++ infix?(op) returns true if op is an infix operator,
                                        ++ and false otherwise.
        elt :     (%, List %) -> %  ++ elt(op, l) creates a form for application of op
                                          ++ to list of arguments l.

        --% Special forms
        string :  % -> % ++ string(f) creates f with string quotes.
        label :   (%, %) -> %  ++ label(n, f) gives form f an equation label n.
        box :     % -> %  ++ box(f) encloses f in a box.
        matrix :  List List % -> % ++ matrix(llf) makes llf (a list of lists of forms) into
                                             ++ a form which displays as a matrix.
        zag :     (%, %) -> %   ++ zag(f, g) creates a form for the continued fraction form for f over g.
        root :    % -> %  ++ root(f) creates a form for the square root of form f.
        root :    (%, %) -> %  ++ root(f, n) creates a form for the nth root of form f.
        over :    (%, %) -> %  ++ over(f, g) creates a form for the vertical fraction of f over g.
        slash :   (%, %) -> %  ++ slash(f, g) creates a form for the horizontal fraction of f over g.
        assign :  (%, %) -> %  ++ assign(f, g) creates a form for the assignment \spad{f := g}.
        rarrow :  (%, %) -> % ++ rarrow(f, g) creates a form for the mapping \spad{f -> g}.
        differentiate : (%, NonNegativeInteger) -> %
                      ++ differentiate(f, n) creates a form for the nth derivative of f,
                      ++ e.g. \spad{f'}, \spad{f''}, \spad{f'''},
                      ++ "f super \spad{iv}".
        binomial : (%, %) -> %  ++ binomial(n, m) creates a form for the binomial coefficient of n and m.
        tensor :  (%, %) -> % ++ tensor(a, b) creates a form for a tensor b

        --% Scripts
        sub :     (%, %) -> % ++ sub(f, n) creates a form for f subscripted by n.
        super :   (%, %) -> %  ++ super(f, n) creates a form for f superscripted by n.
        presub :  (%, %) -> %  ++ presub(f, n) creates a form for f presubscripted by n.
        presuper : (%, %) -> %  ++ presuper(f, n) creates a form for f presuperscripted by n.
        scripts : (%, List %) -> %  ++ \spad{scripts(f, [sub, super, presuper, presub])}
                                              ++  creates a form for f with scripts on all 4 corners.
        supersub : (%, List %) -> %  ++ supersub(a, [sub1, super1, sub2, super2, ...])
                                            ++ creates a form with each subscript aligned
                                            ++ under each superscript.

        --% Diacritical marks
        quote :   % -> % ++ quote(f) creates the form f with a prefix quote.
        dot :     % -> % ++ dot(f) creates the form with a one dot overhead.
        dot :     (%, NonNegativeInteger) -> %  ++ dot(f, n) creates the form f with n dots overhead.
        prime :   % -> %  ++ prime(f) creates the form f followed by a suffix prime (single quote).
        prime :   (%, NonNegativeInteger) -> % ++ prime(f, n) creates the form f followed by n primes.
        overbar : % -> %  ++ overbar(f) creates the form f with an overbar.
        overlabel : (%, %) -> % ++ overlabel(x,f) creates the form f with "x overbar" over the top.

        --% Plexes
        sum :     (%)       -> %
          ++ sum(expr) creates the form prefixing expr by a capital sigma.
        sum :     (%, %)    -> %
          ++ sum(expr, lowerlimit) creates the form prefixing expr by
          ++ a capital sigma with a lowerlimit.
        sum :     (%, %, %) -> %
          ++ sum(expr, lowerlimit, upperlimit) creates the form prefixing expr by
          ++ a capital sigma with both a lowerlimit and upperlimit.
        prod :    (%)       -> %
          ++ prod(expr) creates the form prefixing expr by a capital pi.
        prod :    (%, %)    -> %
          ++ prod(expr, lowerlimit) creates the form prefixing expr by
          ++ a capital pi with a lowerlimit.
        prod :    (%, %, %) -> %
          ++ prod(expr, lowerlimit, upperlimit) creates the form prefixing expr by
          ++ a capital pi with both a lowerlimit and upperlimit.
        int :     (%)       -> %
          ++ int(expr) creates the form prefixing expr with an integral sign.
        int :     (%, %)    -> %
          ++ int(expr, lowerlimit) creates the form prefixing expr by an
          ++ integral sign with a lowerlimit.
        int :     (%, %, %) -> %
          ++ int(expr, lowerlimit, upperlimit) creates the form prefixing expr by
          ++ an integral sign with both a lowerlimit and upperlimit.

        --% Matchfix forms
        brace :   % -> %
          ++ brace(f) creates the form enclosing f in braces (curly brackets).
        brace :   List % -> %
          ++ brace(lf) creates the form separating the elements of lf
          ++ by commas and encloses the result in curly brackets.
        bracket : % -> %
          ++ bracket(f) creates the form enclosing f in square brackets.
        bracket : List % -> %
          ++ bracket(lf) creates the form separating the elements of lf
          ++ by commas and encloses the result in square brackets.
        paren :   % -> %
          ++ paren(f) creates the form enclosing f in parentheses.
        paren :   List % -> %
          ++ paren(lf) creates the form separating the elements of lf
          ++ by commas and encloses the result in parentheses.

        --% Separators for aggregates
        pile :     List % -> %
          ++ pile(l) creates the form consisting of the elements of l which
          ++ displays as a pile, i.e. the elements begin on a new line and
          ++ are indented right to the same margin.

        commaSeparate : List % -> %
          ++ commaSeparate(l) creates the form separating the elements of l
          ++ by commas.
        semicolonSeparate :  List % -> %
          ++ semicolonSeparate(l) creates the form separating the elements of l
          ++ by semicolons.
        blankSeparate : List % -> %
          ++ blankSeparate(l) creates the form separating the elements of l
          ++ by blanks.
        --% Specific applications
        "=":     (%, %) -> %  ++ f = g creates the equivalent infix form.
        "~=":    (%, %) -> %  ++ f ~= g creates the equivalent infix form.
        "<":     (%, %) -> %  ++ f < g creates the equivalent infix form.
        ">":     (%, %) -> %  ++ f > g creates the equivalent infix form.
        "<=":    (%, %) -> %  ++ f <= g creates the equivalent infix form.
        ">=":    (%, %) -> %  ++ f >= g creates the equivalent infix form.
        "+":     (%, %) -> %  ++ f + g creates the equivalent infix form.
        "-":     (%, %) -> %  ++ f - g creates the equivalent infix form.
        "-":     (%)    -> %  ++ - f creates the equivalent prefix form.
        "*":     (%, %) -> %  ++ f * g creates the equivalent infix form.
        "/":     (%, %) -> %  ++ f / g creates the equivalent infix form.
        "^":    (%, %) -> %  ++ f ^ g creates the equivalent infix form.
        "rem":   (%, %) -> % ++ f rem g creates the equivalent infix form.
        "quo":   (%, %) -> %  ++ f quo g creates the equivalent infix form.
        "exquo": (%, %) -> % ++ exquo(f, g) creates the equivalent infix form.
        "and":   (%, %) -> %  ++ f and g creates the equivalent infix form.
        "or":    (%, %) -> % ++ f or g creates the equivalent infix form.
        "not":   (%)    -> %  ++ not f creates the equivalent prefix form.
        SEGMENT : (%, %)  -> %  ++ SEGMENT(x, y) creates the infix form: \spad{x..y}.
        SEGMENT : (%)    -> % ++ SEGMENT(x) creates the prefix form: \spad{x..}.

Special support for LaTeX

Structures that extend SetCategory have a function specially for formatting them in LaTeX:

latex : % -> String       ++ latex(s) returns a LaTeX-printable output

This is the only output type that has special support on a per-domain basis.

As far as I can see this is rarely implemented in a useful way for most domains. This illustrates the problem of putting formatting code in every domain.

Formatters

There are formatters for:

algebra

mathprintWithNumber

(algebraFormat)

Monospace two-dimensional mathematical output. This is the default in the command line terminal.

At the moment this is implemented in boot code in 'i-output.boot'. I am working on an SPAD version of this on page here.

tex texFormat LaTeX
mathML mathmlFormat MathML exists in two forms : presentation and content. This implementation only has supports the presentation form. Because this package only has information from OutputForm/SExpression which has had semantic information removed.
html htmlFormat

Not all browsers support mathML so this gives output which can be cut and pasted directly into a web page.

The details of this are described on page here.

fortran   FORTRAN output
script formulaFormat

IBM Script Formula Format output

The people who have commented on this document (Ralf, Waldek and Andrey) are not aware of anybody using script formula output, so it probably can be safely scrapped.

TeXmacs

texmacsFormat

texmacs.spad.pamphlet

For information about TeXmacs see GNU TeXmacs home page

We can switch between the various formatters by using the ')set output' as follows:

)set output html on turn html output on. To command line terminal by default
)set output html off  
)set output html mypage This will redirect the html output to a file named mypage.html in the default directory or the directory set by )cd system
)set output html console Switch back to command line terminal (default value)

Multiple formatters can be active at any time.

As far as I can tell all these formatters are domains (but it looks like some were originally packages). In cases like HTMLFormat and MathMLFormat I cant see what the rep is?

Waldek: AFAICS HTMLFormat, MathMLFormat and TexmacsFormat really are packages. There are no way to create data of those type, so no need for Rep. ScriptFormulaFormat and TexFormat have represetation as records which are used to store prolog and epilog data. IIUC this is because those formats need to send some setup data at start and close data et the end. Trying to put such data around each separate piece of data would be problematic. However, it appears that this functionality is not used by FriCAS, so it seem to be just a little convenience for some users. AFAICS this could be removed from formatters, and if needed provided by generic wrapper.

Its hard to know what the minimum requirements are for a formatter. They only extend SetCategory so there is not much clue there. As usual with this stuff the documentation is inadequate.

The main thing the formatters need to export is: display : String -> Void
Although some formatters have: display : % -> Void
Most formatter also have: coerce : OutputForm -> String

It would be better if they all had a common interface. That is, it might be better if there were a common category for all formatters which defined their interface in a standard way. For some of these formatters I can't work out what % holds and where its $Rep is defined? (although they are all now domains) .

Comments about TeXmacs by Andrey G. Grozin

TeXmacs can be used as a GUI front end for FriCAS, maxima, reduce, sympy, sage, some othes CASs (Axiom, giac, macaulay2, cadabra, yacas, mathemagix, pari, maple, Mathematica, MuPAD, maybe more), as well as to octave, scilab, R, some plotting programs (asymptote, gnuplot) and others - the full list is lengthy. You can open sessions to these CASs from TeXmacs window. It provides high quality of typesetting mathematics (as high as TeX/LaTeX, but interactively). Input for CASs also can be written in a nice typeset 2D form (this requires some translation rules, say, how to send integrals or sums to each CAS; such rule sets are, of course, incomplete, and in many cases a user has to use syntax specific to a given CAS, maybe intermixed with 2D mathematical notation). It is easy to copy-paste, say, a matrix derived in a FriCAS session into an octave session for further numerical work.

At the moment, TeXmacs is the best free GUI to mathematical programs. One program should do one thing well; TeXmacs interactively typesets mathematics very well. It seems a waste of time to develop separate (and incompatible) GUI front ends for each CAS. Why not use TeXmacs as the main GUI? Currently, only mathemagix is doing so. It integrates with TeXmacs closely. For example, it has dynamic plots (and other dynamic objects). Say, I have a plot of a function depending on some auxilliary parameters somewhere in a TeXmacs window. I assign a new value to one of these parameters, and the plot immediately changes, without the need to re-run a plotting command. Such level of integration can be achieved in FriCAS, too, but this requires further work. ioHooks are invaluable for implementing interactions of FriCAS with external programs, such as TeXmacs and others.

I'd say that the TeXmacs format is one of the most useful ones, because it gives FriCAS an excellent GUI. Also the fortran format is useful for anybody who plans to use derived formulas for an intensive numerical work (it is still done in fortran in many cases). IBM script is, probably, not used anymore.

I'd say that making the user experience with TeXmacs (GUI) / FriCAS (engine) even better than it is today is very important. For example, TeXmacs can be an improved replacement for HyperDoc, with a modern and intuitive interface (HyperDoc definitely looks and feels old-fashioned). This can be achieved by doing only a moderate amount of work. This is especially important in today's world where programs without a nice and convenient GUI are considered old-fashioned, and are often not even considered by potential users.

Andrey

Adding in Brackets

When the expression is coded in tree form, no brackets are needed, but when this is linearised into text form then infix operators may need to be bracketed. Whether brackets are needed, or not, depends on operator precedence. For instance, to distinguish between expressions like these:

There is a need for variable precedence per given operator so, operator precedence needs to be stored in OutputForm for every infix, prefix and postfix operator. For example, '/\' operator for Clifford algebra could have a different precedence to '/\' operator for booleans. (I realise input would have to be done separately).

Displaying numbers to the correct number of decimal digits

FriCAS allows us to change the default output length of numbers, for example:

Other output formatting commands are,

There are various things that can be configured using the ')set' command, for example,

)set expose add constructor OutputForm  
)set output length The maximum width of the output line
)set fortran fortlength except fortran which uses this

Instead of getting access to these commands by $Lisp calls it would be better to have system calls available directly from SPAD.

interp/i-output.boot.pamphlet

This is where the coerce from the algebra to OutputForm and display$OutputForm functions actually get called. i-output also seems to contain lots of routines which can be called by the various formatters.

Note that, in some cases display(String) is used and in other cases display(%) is used:

What is 'ioHook' and what is the need for this different version of TeX?
texFormat expr ==
  ioHook("startTeXOutput")
  tf := '(TexFormat)
  formatFn :=
    getFunctionFromDomain("convert",tf,[$OutputForm,$Integer])
  displayFn := getFunctionFromDomain("display",tf,[tf])
  SPADCALL(SPADCALL(expr,$IOindex,formatFn),displayFn)
  TERPRI $texOutputStream
  FORCE_-OUTPUT $texOutputStream
  ioHook("endOfTeXOutput")
  NIL
 
texFormat1 expr ==
  tf := '(TexFormat)
  formatFn := getFunctionFromDomain("coerce",tf, [$OutputForm])
  displayFn := getFunctionFromDomain("display",tf,[tf])
  SPADCALL(SPADCALL(expr,formatFn),displayFn)
  TERPRI $texOutputStream
  FORCE_-OUTPUT $texOutputStream
  NIL

 

mathmlFormat expr ==
  mml := '(MathMLFormat)
  mmlrep := '(String)
  formatFn := getFunctionFromDomain("coerce",mml,[$OutputForm])
  displayFn := getFunctionFromDomain("display",mml,[mmlrep])
  SPADCALL(SPADCALL(expr,formatFn),displayFn)
  TERPRI $mathmlOutputStream
  FORCE_-OUTPUT $mathmlOutputStream
  NIL
 
texmacsFormat expr ==
  ioHook("startTeXmacsOutput")
  mml := '(TexmacsFormat)
  mmlrep := '(String)
  formatFn := getFunctionFromDomain("coerce",mml,[$OutputForm])
  displayFn := getFunctionFromDomain("display",mml,[mmlrep])
  SPADCALL(SPADCALL(expr,formatFn),displayFn)
  TERPRI $texmacsOutputStream
  FORCE_-OUTPUT $texmacsOutputStream
  ioHook("endOfTeXmacsOutput")
  NIL
 
htmlFormat expr ==
  htf := '(HTMLFormat)
  htrep := '(String)
  formatFn := getFunctionFromDomain("coerce", htf, [$OutputForm])
  displayFn := getFunctionFromDomain("display", htf, [htrep])
  SPADCALL(SPADCALL(expr,formatFn),displayFn)
  TERPRI $htmlOutputStream
  FORCE_-OUTPUT $htmlOutputStream
  NIL
 
output(expr,domain) ==
  if isWrapped expr then expr := unwrap expr
  isMapExpr expr =>
    if $formulaFormat then formulaFormat expr
    if $texFormat     then texFormat expr
    if $algebraFormat then mathprintWithNumber expr
    if $mathmlFormat  then mathmlFormat expr
    if $texmacsFormat then texmacsFormat expr
    if $htmlFormat    then htmlFormat expr
  categoryForm? domain or domain = ["Mode"] =>
    if $algebraFormat then
      mathprintWithNumber outputDomainConstructor expr
    if $texFormat     then
      texFormat outputDomainConstructor expr
  T := coerceInteractive(objNewWrap(expr,domain),$OutputForm) =>
    x := objValUnwrap T
    if $formulaFormat then formulaFormat x
    if $fortranFormat then
      dispfortexp x
      if not $collectOutput then TERPRI $fortranOutputStream
      FORCE_-OUTPUT $fortranOutputStream
    if $algebraFormat then
      mathprintWithNumber x
    if $texFormat     then texFormat x
    if $mathmlFormat  then mathmlFormat x
    if $texmacsFormat then texmacsFormat x
    if $htmlFormat    then htmlFormat x
  (FUNCTIONP(opOf domain)) and (not(SYMBOLP(opOf domain))) and
    (printfun := compiledLookup("<<",'(TextWriter TextWriter $), evalDomain domain))
       and (textwrit := compiledLookup("print", '($), TextWriter())) =>
     sayMSGNT [:bright '"AXIOM-XL",'"output:   "]
     SPADCALL(SPADCALL textwrit, expr, printfun)
     sayMSGNT '%l

  -- big hack for tuples for new compiler
  domain is ['Tuple, S] => output(asTupleAsList expr, ['List, S])

  sayALGEBRA [:bright '"LISP",'"output:",'%l,expr or '"NIL"]

FriCAS Infrastructure

In addition to the code discussed so far there is a certain amount of plumbing required to make this all happen.

setvart.boot

I have no idea what this file does?

It appears to provide various parameters for each output type such as its filename extension.

     (tex
      "create output in TeX style"
      interpreter
      FUNCTION
      setOutputTex
      (("create output in TeX format"
        LITERALS
        $texFormat
        (off on)
        off)
       (break $texFormat)
       ("where TeX output goes (enter {\em console} or a pathname)"
        FILENAME
        $texOutputFile
        chkOutputFileName
        "console"))
      NIL)
     (mathml
      "create output in MathML style"
      interpreter
      FUNCTION
      setOutputMathml
      (("create output in MathML format"
        LITERALS
        $mathmlFormat
        (off on)
        off)
       (break $mathmlFormat)
       ("where MathML output goes (enter {\em console} or a pathname)"
        FILENAME
        $mathmlOutputFile
        chkOutputFileName
        "console"))
      NIL)
     (texmacs
      "create output in Texmacs style"
      interpreter
      FUNCTION
      setOutputTexmacs
      (("create output in Texmacs format"
        LITERALS
        $texmacsFormat
        (off on)
        off)
       (break $texmacsFormat)
       ("where Texmacs output goes (enter {\em console} or a pathname)"
        FILENAME
        $texmacsOutputFile
        chkOutputFileName
        "console"))
      NIL)
     (html
      "create output in HTML style"
      interpreter
      FUNCTION
      setOutputHtml
      (("create output in HTML format"
        LITERALS
        $htmlFormat
        (off on)
        off)
       (break $htmlFormat)
       ("where HTML output goes (enter {\em console} or a pathname)"
        FILENAME
        $htmlOutputFile
        chkOutputFileName
        "console"))
      NIL)

 ))

How FriCAS Communicates with External Code

The default interface for FriCAS is the console command line interface. This is hooked up to the other stuff in this document by a messy set of 'C' code. This 'C' code glues this stuff together and does anything that requires multithreading. C code

There are two other ways to interface to FriCAS:

I don't know the details of how these interface to FriCAS (TeXmacs seems to have a specific formatter and efricas doesn't).

Ralf has said, as far as he knows, TeXmacs can embed FriCAS in its documents and when one calls fricas from TeXmacs, then fricas outputs in texmacs format and texmacs does the formatting.

This is where the ioHooks (mentioned elswhere in this document) come into play.

I would like to add a two way graphical interface, see 'Graphics Functionality' section below. That is a two way interface to a program written in a language that has rich graphics capabilites such as Java or Python.

Possible Synergy with Aldor?

At the moment the formatting capabilities in Aldor are limited so is there a possibility for FriCAS and Aldor to both use similar standards for their formatting capabilities?

There is a library, called SALLI, which provides Aldor programmers with a extensible computer algebra layer with many low-level functions. Part of this is a stream I/O model which contains an ExpressionTree, described on page here, this has a function very similar to FriCAS OutputForm described above.

I don't know much about Aldor but as far as I can make out (and I might be wrong) there appear to be significant differences:

Possible Enhancements to Functionality

I think it would be really good if this FriCAS code can be put into a state where changes can be made. Some of the changes that I would like are:

  1. Support in output expressions for operator precedence so, for example, '/\' operator for Clifford algebra could have a different precedence to '/\' operator for booleans. (I realise input would have to be done separately).
  2. Support in output expressions for graph theory so they know about nodes and edges.
  3. Make better use of Unicode

Graphics Functionality

FriCAS already has two graphics frameworks but these are for exporting to an output device/file only, they do not allow input as well as output.

I am very keen to have a two-way graphical interface for FriCAS. I would like to work with finite structures but using the command line terminal for this is horrible (Just look at graph theory on page here to see what I mean).

I would like OutputForm to have specific representations of nodes and edges. Of course, they could be coded as strings in the existing structure, but this would involve messy parsing of strings to retrieve the structure.

Eventually this interface needs to bipass the command line altogether. That is a two way interface to a program written in a language that has rich graphics capabilites such as Java or Python.

InputForm

It would be useful if the input to FriCAS could also be built on similar principles to this and even better if they used the same data structures.

Proposed New Rep of 'OutputForm'

I propose that outputForm has the following representation:

output form

This diagram is not complete, it needs to support all the OutputForm constructors shown above, but it does show the level of complexity of the recursively defined structure.

This is a recursively defined structure that no longer uses SExpression and is something less lisp-like, more type-safe and easier to traverse.

Don't forget, this structure is only intended to hold the presentation structure of an expression and semantic structure is only included where it directly affects the appearance. The word 'matrix' is used when perhaps '2D array' might be better, its elements don't have to be numbers and can be strings or anything else.

System Calls

In order to get rid of lisp calls from the proposed SPAD code it would be good if the following system calls were available directly from SPAD to:

Proposed Changes

The aim is to reduce the dependence on Lisp and boot code, reduce the need for 'pretends' and remove some of the issues mentioned above, so I therefore propose the following changes:

Ideally one might like to do these things one at a time. However I think that would be a very inefficient way to do it. I think the hardest part is working out what some undocumented, untyped code is doing and using 'pretends' and so on to get it in the form that is needed. This will be eliminated if we start with the replacement for 'output' in 'i-output.boot' and make the changes following the data path so the code we are working on always has input that is well documented and well typed.

This would be a lot of reworking of code but at the end of it you would have something properly type-safe and Lisp-independent.

Issues

  1. Need more detail about the ioHook mechanism for interfacing with teXmacs and efricas.
  2. I have put other issues on my 'wish list' on the page here.

metadata block
see also:
  • On this page I have put some information about computer algebra systems and in particular Axiom/FriCAS.
  • I have discussed my experiments with writing an interpreter in SPAD on this page here.
  • I have discussed my attempt at writing a monospaced formatter this page here.
Correspondence about this page

This site may have errors. Don't use for critical systems.

Copyright (c) 1998-2023 Martin John Baker - All rights reserved - privacy policy.