Giter Club home page Giter Club logo

fricas's Introduction

FriCAS

FriCAS is a general purpose computer algebra system (CAS).

For installation instructions see INSTALL. For general documentation consult https://fricas.github.io.

The basic goal of FriCAS is to create a free advanced world-class CAS. In 2007 FriCAS forked from Axiom. Currently the FriCAS algebra library is one of the largest and most advanced free general purpose computer algebra systems -- this gives a good foundation to build on. Additionally, the FriCAS algebra library is written in a high level strongly typed language (Spad), which allows natural expression of mathematical algorithms. This makes FriCAS easier to understand and extend.

FriCAS uses lightweight development methodology. Compared to Axiom, FriCAS is significantly restructured -- it is more portable and fixed several defects. FriCAS removed rather large unused parts (without removing functionality).

Current development goals:

  • continue structural improvements
  • add new mathematical algorithms
  • develop better user interface
  • develop improved Spad compiler
  • make it easier for external programs to interface with FriCAS
  • support for using external mathematical routines from Spad

fricas's People

Contributors

billpage avatar cahirwpz avatar dimpase avatar fchapoton avatar hebisch avatar hemmecke avatar nsajko avatar oldk1331 avatar rocky avatar s-kostyaev avatar stylewarning avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fricas's Issues

Keyword not supported, textspadexpr, in ug15.ht

The output :

(1) -> (HyperDoc) Keyword not currently supported: textspadexpr
(HyperDoc) While parsing releaseNotesPage on line 710
in the file /usr/local/lib/fricas/target/x86_64-linux-gnu/share/hypertex/pages/ug15.ht

Document the `make check` target

I only discovered the make check target by reading the CI/CD pipeline. It would be nice to document it for future contributors.

WebAssembly

It would be quite interesting to see if it's possible to compile Fricas to WebAssembly or similar. That would make it possible to use a high quality CAS in the browser!

[mailing list] infinite recursion with "typeOf"

original link: https://groups.google.com/g/fricas-devel/c/JfGE2qFDbtI/m/79fQScBZBQAJ

(1) -> typeOf(())
INFO: Control stack guard page unprotected
Control stack guard page temporarily disabled: proceed with caution
 
   >> System error:
   Control stack exhausted (no more space for function call frames).
This is probably due to heavily nested or infinitely recursive function
calls, or a tail call that SBCL cannot or has not optimized away.

PROCEED WITH CAUTION.

(1) -> typeOf ()
INFO: Control stack guard page reprotected
INFO: Control stack guard page unprotected
Control stack guard page temporarily disabled: proceed with caution
 
   >> System error:
   Control stack exhausted (no more space for function call frames).
This is probably due to heavily nested or infinitely recursive function
calls, or a tail call that SBCL cannot or has not optimized away.

PROCEED WITH CAUTION.

leadingTerm missing for series domains

(Sparse)UnivariateLaurentSeries is missing an implementation of leadingTerm.

S ==> UnivariateLaurentSeries(Integer, 'x, 0)
sx := x :: S
leadingTerm sx

(3) -> leadingTerm sx
   Internal Error
   The function leadingTerm with signature hashcode is missing from 
      domain UnivariateLaurentSeries(Integer)x0 

Regression in commit 2e4faf4b1ff681bd82fb086246fd19726ce0c729

The program

)abbrev pkg FOO Foo
Foo(): Exports == Implementation where
  F ==> Fraction Integer
  Exports ==> with extractNext!: List F -> F
  Implementation ==> add
    extractNext!(m: List F): F ==
        p: List F := empty()
        g := -1 -- dummy value
        if not empty? p then g: Integer := 42
        2/3

behaves differently in commit d6fc24f from the newer commit 2e4faf4 .

It's not clear whether this is an improvement or a bug.
replacing the "dummy value" line by
g: Integer := -1
let's everything work fine. Without type declaration the compiler obviously thinks that the type of g is Fraction(Integer) and then get's confused when g is declared to be Integer later.
Interestingly, p is empty in this example.

(1) -> extractNext!([1,2/5,-3/7])$Foo()
 
   >> System error:
   The value
  (-1 . 1)
is not of type
  INTEGER

renaming a variable seems to cause miscompilation

Let's call this m.spad:

)abbrev package FACPAK FactorizationPackage

FactorizationPackage(p): Exports == Implementation where

  p: PositiveInteger

  Exports == with

    display_factorizations: NonNegativeInteger -> Void

  Implementation == add

    FLD ==> (PrimeField p)
    POL ==> (Polynomial FLD)
    FAC ==> (Factored POL)

    my_pol(n: PositiveInteger): POL ==
      x: POL := ('x)::POL
      x^n - x^0

    make_factorizations(m: NonNegativeInteger): Matrix FAC ==
      mat: Matrix FAC := new(m, 2, 0$FAC)

      for n in 1..m repeat
        pol: POL := my_pol(n::PositiveInteger)
        mat(n, 2) := factor pol

      mat

    display_factorizations(max: NonNegativeInteger): Void ==
      display((make_factorizations max)::OutputForm::TexFormat)
      void()

and this can be max.spad:

)abbrev package FACPAK FactorizationPackage

FactorizationPackage(p): Exports == Implementation where

  p: PositiveInteger

  Exports == with

    display_factorizations: NonNegativeInteger -> Void

  Implementation == add

    FLD ==> (PrimeField p)
    POL ==> (Polynomial FLD)
    FAC ==> (Factored POL)

    my_pol(n: PositiveInteger): POL ==
      x: POL := ('x)::POL
      x^n - x^0

    make_factorizations(max: NonNegativeInteger): Matrix FAC ==
      mat: Matrix FAC := new(max, 2, 0$FAC)

      for n in 1..max repeat
        pol: POL := my_pol(n::PositiveInteger)
        mat(n, 2) := factor pol

      mat

    display_factorizations(max: NonNegativeInteger): Void ==
      display((make_factorizations max)::OutputForm::TexFormat)
      void()

The only difference between the two files is that a parameter in the make_factorizations function is renamed from m to max. This, however, seems to cause a miscompilation:

(1) -> )compile m.spad
   Compiling FriCAS source code from file /home/nsajko/fricas_factor/m.spad using old system compiler.
   FACPAK abbreviates package FactorizationPackage
------------------------------------------------------------------------
   initializing NRLIB FACPAK for FactorizationPackage
   compiling into NRLIB FACPAK
   processing macro definition FLD ==> PrimeField p
   processing macro definition POL ==> Polynomial PrimeField p
   processing macro definition FAC ==> Factored Polynomial PrimeField p
   compiling local my_pol : PositiveInteger -> Polynomial PrimeField p
Time: 0.04 SEC.

   compiling local make_factorizations : NonNegativeInteger -> Matrix Factored Polynomial PrimeField p
Time: 0.01 SEC.

   compiling exported display_factorizations : NonNegativeInteger -> Void
Time: 0.01 SEC.

(time taken in buildFunctor:  95)

;;;     ***       |FactorizationPackage| REDEFINED

;;;     ***       |FactorizationPackage| REDEFINED
Time: 0.00 SEC.


   Cumulative Statistics for Constructor FactorizationPackage
      Time: 0.06 seconds

   finalizing NRLIB FACPAK
   Processing FactorizationPackage for Browser database:
--->-->FactorizationPackage(constructor): Not documented!!!!
--->-->FactorizationPackage((display_factorizations ((Void) (NonNegativeInteger)))): Not documented!!!!
--->-->FactorizationPackage(): Missing Description
; compiling file "/home/nsajko/fricas_factor/FACPAK.NRLIB/FACPAK.lsp" (written 14 FEB 2022 02:31:24 PM):

; wrote /home/nsajko/fricas_factor/FACPAK.NRLIB/FACPAK.fasl
; compilation finished in 0:00:00.016
------------------------------------------------------------------------
   FactorizationPackage is now explicitly exposed in frame frame1
   FactorizationPackage will be automatically loaded when needed from /home/nsajko/fricas_factor/FACPAK.NRLIB/FACPAK

(1) -> (display_factorizations$FactorizationPackage(2)) 3
$$
\left[
\begin{array}{cc}
0 & {x+1} \\
0 & {{{\left( x+1
\right)}}
\sp {2}} \\
0 & {{\left( {{x} \sp {2}}+x+1
\right)}
\  {\left( x+1
\right)}}
\end{array}
\right]
$$
(1) -> )compile max.spad
   Compiling FriCAS source code from file /home/nsajko/fricas_factor/max.spad using old system compiler.
   FACPAK abbreviates package FactorizationPackage
------------------------------------------------------------------------
   initializing NRLIB FACPAK for FactorizationPackage
   compiling into NRLIB FACPAK
   processing macro definition FLD ==> PrimeField p
   processing macro definition POL ==> Polynomial PrimeField p
   processing macro definition FAC ==> Factored Polynomial PrimeField p
   compiling local my_pol : PositiveInteger -> Polynomial PrimeField p
Time: 0.02 SEC.

   compiling local make_factorizations : NonNegativeInteger -> Matrix Factored Polynomial PrimeField p
Time: 0.01 SEC.

   compiling exported display_factorizations : NonNegativeInteger -> Void
Time: 0.00 SEC.

(time taken in buildFunctor:  58)

;;;     ***       |FactorizationPackage| REDEFINED

;;;     ***       |FactorizationPackage| REDEFINED
Time: 0 SEC.


   Cumulative Statistics for Constructor FactorizationPackage
      Time: 0.04 seconds

   finalizing NRLIB FACPAK
   Processing FactorizationPackage for Browser database:
--->-->FactorizationPackage(constructor): Not documented!!!!
--->-->FactorizationPackage((display_factorizations ((Void) (NonNegativeInteger)))): Not documented!!!!
--->-->FactorizationPackage(): Missing Description
; compiling file "/home/nsajko/fricas_factor/FACPAK.NRLIB/FACPAK.lsp" (written 14 FEB 2022 02:33:40 PM):

; file: /home/nsajko/fricas_factor/FACPAK.NRLIB/FACPAK.lsp
; in: SDEFUN |FACPAK;make_factorizations|
;     (GO BOOT::G191)
;
; note: deleting unreachable code
;
; compilation unit finished
;   printed 1 note


; wrote /home/nsajko/fricas_factor/FACPAK.NRLIB/FACPAK.fasl
; compilation finished in 0:00:00.010
------------------------------------------------------------------------
   FactorizationPackage is now explicitly exposed in frame frame1
   FactorizationPackage will be automatically loaded when needed from /home/nsajko/fricas_factor/FACPAK.NRLIB/FACPAK

(1) -> (display_factorizations$FactorizationPackage(2)) 3

   >> Error detected within library code:
   setelt!: index out of range

It seems as if the loop for n in 1..max repeat is being replaced with for n in 1.. repeat or something like that.

BUG with parallel for-while-for

https://groups.google.com/g/fricas-devel/c/JHP5jg0dc2o/m/TqNF0Td1AAAJ

(13) -> [k for k in 4.. by -3 while k>0]

   (13)  [4, 1]
                                          Type: Stream(Integer)
(14) -> [k for k in 4.. by -3 while k>0 for m in 1..29]
   There are no library operations named swhile
      Use HyperDoc Browse or issue
                               )what op swhile
      to learn if there is any operation containing " swhile " in its
      name.

   Cannot find a definition or applicable library operation named
      swhile with argument type(s)
             (Record(part1: Integer,part2: Integer) -> Boolean)
            InfiniteTuple(Record(part1: Integer,part2: Integer))

      Perhaps you should use "@" to indicate the required return type,
      or "$" to specify which version of the function you need.

Confusing form for nonlinear differential equation "solution"

Consider solve(x * D(y(x), x) = y(x) + x * y(x)^2, y, x). It returns the following expression (it can be rendered with https://www.mathjax.org):

<math xmlns="http://www.w3.org/1998/Math/MathML" mathsize="big" display="block"> <mrow><mfrac><mrow><mrow><mo>-</mo><mrow><mrow><msup><mrow><mi>x</mi></mrow><mrow><mn>2</mn></mrow></msup></mrow><mo>&#x02062;</mo><mrow><mo><mi>y</mi></mo><mo>(</mo><mrow><mi>x</mi></mrow><mo>)</mo></mrow></mrow><mo>-</mo><mrow><mn>2</mn><mo>&#x02062;</mo><mi>x</mi></mrow></mrow></mrow><mrow><mrow><mn>2</mn><mo>&#x02062;</mo><mrow><mo><mi>y</mi></mo><mo>(</mo><mrow><mi>x</mi></mrow><mo>)</mo></mrow></mrow></mrow></mfrac></mrow> </math>

The solution to the given differential equation is acquired by setting the returned expression to equal an integrating constant, thus getting an equation. But the problem is that this is quite non-obvious to a new user! At least to an undergraduate CAS newbie like me. A related issue is that although the Fricas book [0] includes examples of such differential equation solutions, even by reading the book it is pretty hard to suss out what the result means.

Consider how Maxima (another CAS) solves the same problem (ode2(x * 'diff(y,x) = y + x * y^2, y, x);): they return basically the same result, but with "= %c" appended, thus making it clear what the result actually is. I propose for Fricas to do the same thing.

Additionally, there should probably be a way to (if feasible) give the function y(x) in terms of x and integrating constants (%c1, %c2, etc.), because this is what is usually considered the solution to a differential equation, and also this is how Wolfram Alpha, for example, does it.

[0] https://fricas.github.io/book.pdf

Failed to launch FriCAS 1.3.8 on macOS

Attempt 1

➜  ~ /Applications/FriCAS.app/Contents/MacOS/FriCAS
open: unrecognized option `--env'
Usage: open [-e] [-t] [-f] [-W] [-R] [-n] [-g] [-h] [-s <partial SDK name>][-b <bundle identifier>] [-a <application>] [filenames] [--args arguments]
Help: Open opens files from a shell.
      By default, opens each file using the default application for that file.
      If the file is in the form of a URL, the file will be opened as a URL.
Options:
      -a                Opens with the specified application.
      -b                Opens with the specified application bundle identifier.
      -e                Opens with TextEdit.
      -t                Opens with default text editor.
      -f                Reads input from standard input and opens with TextEdit.
      -F  --fresh       Launches the app fresh, that is, without restoring windows. Saved persistent state is lost, excluding Untitled documents.
      -R, --reveal      Selects in the Finder instead of opening.
      -W, --wait-apps   Blocks until the used applications are closed (even if they were already running).
          --args        All remaining arguments are passed in argv to the application's main() function instead of opened.
      -n, --new         Open a new instance of the application even if one is already running.
      -j, --hide        Launches the app hidden.
      -g, --background  Does not bring the application to the foreground.
      -h, --header      Searches header file locations for headers matching the given filenames, and opens them.
      -s                For -h, the SDK to use; if supplied, only SDKs whose names contain the argument value are searched.
                        Otherwise the highest versioned SDK in each platform is used.

Attempt 2

➜  ~ /Applications/FriCAS.app/Contents/Resources/usr/local/bin/fricas
The directory for FriCAS, /usr/local/lib/fricas/target/x86_64-apple-darwin19.6.0, does not exist.
Goodbye.

Fricas failed to compile on msys2?

Fricas is a good project and I like it very much!
I compile Fricas on msys2(MSYS2 MinGW 32/64-bit) following these steps:

Install autotools, automake,sbcl and so on;
git clone https://github.com/fricas/fricas.git
mkdir fricas-build
cd fricas-build
../fricas/configure --with-lisp=sbcl --prefix=/f/bin

not success! error as below:

../fricas/configure --with-lisp=sbcl --prefix=/f/bin

configure: loading site script /mingw32/etc/config.site
checking build system type... i686-w64-mingw32
checking host system type... i686-w64-mingw32
checking target system type... i686-w64-mingw32
checking for gmake... no
checking for make... make
GNU Make 4.3
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.exe
checking for suffix of executables... .exe
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for a BSD-compatible install... /usr/bin/install -c
checking for touch... touch
checking for mktemp... mktemp
checking for gawk... gawk
checking for gtar... no
checking for tar... tar
checking for ranlib... ranlib
checking for ar... ar
checking for latex... no
checking for makeindex... no
checking PREGENERATED... ""
checking Lisp implementation... This is SBCL 2.0.0, an implementation of ANSI Common Lisp.
More information about SBCL is available at http://www.sbcl.org/.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.

WARNING: the Windows port is fragile, particularly for multithreaded
code. Unfortunately, the development team currently lacks the time
and resources this platform demands.

  • sbcl
    checking how to run the C preprocessor... gcc -E
    checking for grep that handles long lines and -e... /usr/bin/grep
    checking for egrep... /usr/bin/grep -E
    checking for ANSI C header files... yes
    checking for sys/types.h... yes
    checking for sys/stat.h... yes
    checking for stdlib.h... yes
    checking for string.h... yes
    checking for memory.h... yes
    checking for strings.h... yes
    checking for inttypes.h... yes
    checking for stdint.h... yes
    checking for unistd.h... yes
    fasl
    checking dirent.h usability... yes
    checking dirent.h presence... yes
    checking for dirent.h... yes
    checking whether closedir is declared... yes
    checking whether opendir is declared... yes
    checking whether readdir is declared... yes
    checking whether dirfd is declared... no
    checking whether fchdir is declared... no
    checking signal.h usability... yes
    checking signal.h presence... yes
    checking for signal.h... yes
    checking whether sigaction is declared... no
    checking for sys/stat.h... (cached) yes
    checking for unistd.h... (cached) yes
    checking whether getuid is declared... no
    checking whether geteuid is declared... no
    checking whether getgid is declared... no
    checking whether getegid is declared... no
    checking whether kill is declared... no
    checking winsock2.h usability... yes
    checking winsock2.h presence... yes
    checking for winsock2.h... yes
    checking util.h usability... no
    checking util.h presence... no
    checking for util.h... no
    checking pty.h usability... no
    checking pty.h presence... no
    checking for pty.h... no
    checking whether openpty is declared... no
    checking for openpty in -lc... no
    checking for openpty in -lutil... no
    checking for openpty in -lbsd... no
    checking sys/wait.h usability... no
    checking sys/wait.h presence... no
    checking for sys/wait.h... no
    checking whether fork is declared... no
    configure: Superman component is disabled.
    checking for X... no
    configure: The Graphics and HyperDoc components are disabled.
    configure: WARNING: Aldor interface will not be built.
    configure: creating ./config.status
    config.status: creating src/hyper/Makefile
    config.status: creating src/doc/Makefile
    config.status: creating Makefile
    config.status: creating src/Makefile
    config.status: creating src/lib/Makefile
    config.status: creating src/lisp/Makefile
    config.status: creating src/boot/Makefile
    config.status: creating src/interp/Makefile
    config.status: creating src/algebra/Makefile
    config.status: creating src/input/Makefile
    config.status: creating src/etc/Makefile
    config.status: creating src/aldor/Makefile
    config.status: creating src/aldor/Makefile2
    config.status: creating src/aldor/Makefile3
    config.status: creating contrib/emacs/Makefile
    config.status: creating config/fricas_c_macros.h
    config.status: config/fricas_c_macros.h is unchanged
    extracting list of SPAD type definitions
    Type 'make' (without quotes) to build FriCAS
    Administrator@P0KCKVOC3HZFKEQ MINGW32 /f/fricas-build

make

make: *** No rule to make target '/f/fricas-build/config.status', needed by 'Makefile'. Stop.

Is there a wrong configuration?
Thank you in advance for your help!

use of uninitialized variable (should not compile)

I get the following error while running the (obviously incorrect program below).

foo(3)
   >> System error:
   The value
  NIL
is not of type
  REAL

The program is:

)abbrev package FOO Foo
Z ==> Integer
Foo: with
  foo: Z -> Z
 == add
  foo(n: Z): Z ==
    k: Z := (k exquo 3)::Z
    return k

It would be better if that program would not compile, because it refers to a variable k that is just about to be defined. Even ParadoxicalCombinatorsForStreams first initialized a record before it is going to modify it.

Build a "universal" macOS binary?

Would it be possible to have a universal binary build of FriCAS for recent macOS releases? This would run natively on both x86 and Apple silicon.

I'm not sure this is possible (yet) on Github CI, I'll look into it.

Open FriCAS in the same shell on macOS?

I may be missing something, but is it possible to have the FriCAS CLI open in the same shell that issues the ...FriCAS.app/Contents/MacOS/FriCAS command?

At the moment it opens a new mac terminal even if I open it from iTerm2 or Kitty etc.

doc: book: spadcommand missing OutputForm output

In section 6.19 of the book, above the text Being purists, we find there should be a Pascal's triangle which is instead missing.

Taking a look at line 2346 of src/doc/htex/ug06.htex points to a spadcommand Tex command as the likely culprit.

The section shows an example of OutputForm usage, which is related to the problem, I guess.

[meta] Small clean-ups welcome?

Hello, I hope this is an OK place to ask a meta-question about the project. I'm Robert and I work in quantum computing, and I am also a long-time, professional Common Lisp programmer (i.e., I use it for my job).

First, thanks to the FriCAS developers for keeping the project alive and well. I hope that one day FriCAS picks up even more steam and is continued to be built upon and developed. Computer algebra is hard, and building on existing systems seems like our best bet for building a better CAS.

I've been interested in contributing back to FriCAS for many years, and I would like to start now. I have a few newbie questions.

  1. Is it OK to use the issue tracker for questions, or do the maintainers highly prefer using a mailing list?
  2. Does this project accept non-breaking Lisp code cleanup? I'm afraid I can't contribute within the Spad language itself yet because I don't sufficiently understand it, but when I see files like this, I wonder if we can use modern Common Lisp features like inlined functions instead of macros everywhere.
  3. Does this project support deleting dead code or deprecated platforms? I don't think supporting GCL or Poplog is worth it; there are better, more portable, more performant, and more maintained Common Lisp systems. Deleting code is always scary, but it's better than letting it secretly bitrot.
  4. How does this project handle dependencies? Would project maintainers accept FriCAS being built through the idiomatic ASDF? If so, that would make depending on third-party Lisp code a lot easier.

Thank you!

Build error - Mac OS X, sbcl

fricas_fasl_type=fasl
fricas_lisp_flavor=sbcl
fricas_lisp_version=1.4.11.68-9456dfc60

...
Warnings:
[1] RetractableTo has no value

****** comp fails at level 2 with expression: ******
(|Join| (|GradedModule| |t#1| |t#2|) | << | (|RetractableTo| |t#1|) | >> |
(CATEGORY |domain| (SIGNATURE 1 ($) |constant|)
(SIGNATURE |product| ($ $ $))))
****** level 2 ******
$x:= (RetractableTo t#1)
$m:= (Category)
$f:=
((((|t#2| #) (|t#1| #) (E # #) (R # #) ...)))

Apparent user error:
cannot compile (RetractableTo t#1)

(1) -> mv: cannot stat 'category.daase': No such file or directory
mv: cannot stat 'compress.daase': No such file or directory
mv: cannot stat 'interp.daase': No such file or directory
mv: cannot stat 'operation.daase': No such file or directory
make[3]: *** [stamp-db] Error 1
make[2]: *** [all-ax] Error 2
make[1]: *** [all-algebra] Error 2
make: *** [all-src] Error 2

Non-Interactive Use

Hello,

How would one use FriCAS non-interactively from a terminal? I would like to be able to pass input (e.g. to integrate a function) to FriCAS from some text file, and save output (result of integration) to some text file -- as a way of batch solving stuff?

Thanks.

misleading compiler message for "is replaced by"

)abbrev package TESTPKG SomeTestPkg
SomeTestPkg(): Exports == Implementation where
    Exports ==> with
        f: () -> Integer
    Implementation ==> add
        f(): Integer == 123 - 456

The compilation itself is fine, but one of the compiler messages is very misleading:

(1) -> )compile s.spad
   Compiling FriCAS source code from file /tmp/spad/s.spad using old system compiler.
   TESTPKG abbreviates package SomeTestPkg
------------------------------------------------------------------------
   initializing NRLIB TESTPKG for SomeTestPkg
   compiling into NRLIB TESTPKG
   compiling exported f : () -> Integer
      TESTPKG;f;I;1 is replaced by -123456

Note the last line. It would be better if it said 123 - 456 or _-(123, 456) or (- 123 456) instead of -123456.

The best would probably be if it outright calculated -333.

Unable to build on MacOSX

MacOSX Catalina - 10.15.4, Darwin Kernel Version 19.4.0, SBCL 2.0.11

(doing (GradedAlgebra R E) ((Category) (CommutativeRing) (AbelianMonoid)))
Semantic Errors:
[1] cannot form Join of: ((GradedModule t#1 t#2) (RetractableTo t#1) (CATEGORY domain (SIGNATURE (One) ($) constant) (SIGNATURE product ($ $ $))))

Warnings:
[1] RetractableTo has no value

****** comp fails at level 2 with expression: ******
(|Join| (|GradedModule| |t#1| |t#2|) | << | (|RetractableTo| |t#1|) | >> |
(CATEGORY |domain| (SIGNATURE 1 ($) |constant|)
(SIGNATURE |product| ($ $ $))))
****** level 2 ******
$x:= (RetractableTo t#1)
$m:= (Category)
$f:=
((((|t#2| #) (|t#1| #) (E # #) (R # #) ...)))

Apparent user error:
cannot compile (RetractableTo t#1)

Permutation groups via CL-PERMUTATION?

I maintain a library called CL-PERMUTATION written in pure ANSI Common Lisp which has facilities for dealing with permutation groups. It's not state-of-the-art like GAP & co, but it does effectively work with permutations and perm groups, and is reasonably performant.

In my brief search I wasn't able to find any functionality in Axiom dealing with permutation groups, but I may not have looked hard enough.

Is this something that could be conceivably used with or integrated into FriCAS to give it perm group functionality, without gutting CL-PERMUTATION and sprinkling it inside of FriCAS?

Some additional output of integrate() function - what does it mean?

Hello.
Sometimes, when I call integrate(), it outputs some text in addition to the answer:

(2) -> integrate(cos(x^3), x)
   Gamma2
    1  3
   [─,x %i]
    3

                            ┌────────┐
                1  3 ┌───┐ 3│   ┌───┐    6┌───┐      1    3 ┌───┐
        - Gamma(─,x \│- 1 )\│- \│- 1   - \│- 1 Gamma(─,- x \│- 1 )
                3                                    3
   (2)  ──────────────────────────────────────────────────────────
                                    ┌────────┐
                             6┌───┐3│   ┌───┐
                            6\│- 1 \│- \│- 1
                                         Type: Union(Expression(Integer),...)

As far as I understand, the fraction marked with (2) is the answer itself; but what is

   Gamma2
    1  3
   [─,x %i]
    3

about ?

build on macOS with ecl fails due to strict C compiler

see https://trac.sagemath.org/ticket/31863
typical errors are

;;; End of Pass 1.
;;; Internal error:
;;;   ** Error code 1 when executing
;;; (EXT:RUN-PROGRAM "gcc" ("-I." "-I/Users/palmieri/Desktop/Sage/git/sage/local/include/" "-O2" "-g" "-march=native" "-fPIC" "-fno-common" "-Ddarwin" "-O2" "-c" "fricas-lisp.c" "-o" "fricas-lisp.o")):
;;; fricas-lisp.c:608:25: error: implicit declaration of function 'writeablep' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
;;;   value0 = ecl_make_int(writeablep(ecl_base_string_pointer_safe(v2)));
;;;                         ^
;;; /Users/palmieri/Desktop/Sage/git/sage/local/include/ecl/external.h:1107:23: note: expanded from macro 'ecl_make_int'
;;; # define ecl_make_int ecl_make_int32_t
;;;                       ^
;;; fricas-lisp.c:639:25: error: implicit declaration of function 'remove_directory' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
;;;   value0 = ecl_make_int(remove_directory(ecl_base_string_pointer_safe(v2)));
;;;                         ^
;;; /Users/palmieri/Desktop/Sage/git/sage/local/include/ecl/external.h:1107:23: note: expanded from macro 'ecl_make_int'
;;; # define ecl_make_int ecl_make_int32_t
;;;                       ^
;;; fricas-lisp.c:639:25: note: did you mean 'L25_remove_directory_'?
;;; /Users/palmieri/Desktop/Sage/git/sage/local/include/ecl/external.h:1107:23: note: expanded from macro 'ecl_make_int'
;;; # define ecl_make_int ecl_make_int32_t
;;;                       ^
;;; ./fricas-lisp.eclh:35:18: note: 'L25_remove_directory_' declared here
;;; static cl_object L25_remove_directory_(cl_object );
;;;                  ^
;;; fricas-lisp.c:670:25: error: implicit declaration of function 'open_server' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
;;;   value0 = ecl_make_int(open_server(ecl_base_string_pointer_safe(v2)));
;;;                         ^
;;; /Users/palmieri/Desktop/Sage/git/sage/local/include/ecl/external.h:1107:23: note: expanded from macro 'ecl_make_int'
;;; # define ecl_make_int ecl_make_int32_t
;;;                       ^
;;; fricas-lisp.c:698:24: error: implicit declaration of function 'sock_get_int' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
;;;  value0 = ecl_make_int(sock_get_int(ecl_fixnum(v1fricas_lisp__purpose)));
;;;                        ^
;;; /Users/palmieri/Desktop/Sage/git/sage/local/include/ecl/external.h:1107:23: note: expanded from macro 'ecl_make_int'
;;; # define ecl_make_int ecl_make_int32_t
;;;                       ^
;;; fricas-lisp.c:710:24: error: implicit declaration of function 'sock_send_int' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
;;;  value0 = ecl_make_int(sock_send_int(ecl_fixnum(v1fricas_lisp__purpose),ecl_fixnum(v2fricas_lisp__val)));
;;;                        ^

One can either set CFLAGS to make these errors back into warnings, or fix the root cause.

Calling a UnivariateTaylorSeries of mere integer value from Spad to the interpreter causes error

All the exported functions here that return an UnivariateTaylorSeries cause the errors when called from the interpreter:

)abbrev package BUGTEST BugTest
BugTest(): Exports == Implementation where

        SYM ==> Symbol
        I ==> Integer
        RAT ==> Fraction(I)
        EXPR ==> Expression(I)
        UP(R) ==> UnivariatePolynomial('eps::SYM, R)
        UP_EXPR ==> UP(EXPR)
        TAY ==> UnivariateTaylorSeries(EXPR, 'eps::SYM, 0::EXPR)
        EQ ==> Equation

        Exports ==> with

                expr: () -> EXPR
                tay_i: () -> TAY
                tay_rat: () -> TAY
                tay_up_expr: () -> TAY
                tay_expr: () -> TAY
                tay_taylor: () -> TAY

        Implementation ==> add

                i(): I ==
                        0     -- Also try changing this from 0 to, e.g., 1!

                rat(): RAT ==
                        i()::RAT

                up_expr(): UP_EXPR ==
                        i()::UP_EXPR

                expr(): EXPR ==
                        i()::EXPR

                eps(): SYM ==
                        'eps

                eps_e(): EXPR ==
                        eps()::EXPR

                eps_eq_zero(): EQ(EXPR) ==
                        eps_e() = 0

                taylor_eps(e: EXPR): TAY ==
                        retract(taylor(e, eps_eq_zero())$ExpressionToUnivariatePowerSeries(I, EXPR))$AnyFunctions1(TAY)

                tay_i(): TAY ==
                        i()::TAY

                tay_rat(): TAY ==
                        rat()::TAY

                tay_up_expr(): TAY ==
                        coerce(up_expr())$TAY

                tay_expr(): TAY ==
                        expr()::TAY

                tay_taylor(): TAY ==
                        taylor_eps(expr())

With i() returning a zero-valued Integer:

(9) -> tay_i()

   (9)  0

   >> Error detected within library code:
   index out of range

Notice that the interpreter tells us the value, but not the type.

With i() returning a non-zero Integer:

(9) -> tay_i()


   >> System error:
   The value
  |::|
is not of type
  CONS

Now we don't even get to know the value.

Internal Error: Unexpected error in call to system function compColon

Moving on from the mailing list, since now I stumbled upon an actual bug in Fricas. This is the diagnostic produced by )compile:

   compiling local trunc_taylor_integral : (Expression Integer,Expression Integer) -> Expression Integer
   Internal Error
   Unexpected error in call to system function compColon

This is the code:

)abbrev package GGLC GeographicLibCoefficients
GeographicLibCoefficients() : Exports == Implementation where

        SYM ==> Symbol

        L ==> List
        I ==> Integer
        P ==> PositiveInteger

        EXPR ==> Expression(I)

        RAT ==> Fraction(I)
        PLY ==> Polynomial(RAT)
        UPLY(var) ==> UnivariatePolynomial(var, RAT)
        RATFUNC ==> Fraction(PLY)
        TAY(var) ==> UnivariateTaylorSeries(EXPR, var, 0)

        Exports ==> with

                tau1_m_sigma: () -> EXPR

        Implementation ==> add

                maxpow(): P == 8

                trunc_taylor_integral(integrand: EXPR, factor: EXPR): EXPR ==
                        subs_eq: Equation(EXPR) := 'k2::SYM::EXPR = 4 * 'eps::SYM::EXPR /
                                                                     (1 - 'eps::SYM::EXPR)^2
                        inte: EXPR := subst(integrand, subs_eq) * factor
                        tay: TAY('eps::SYM) := taylor(inte, 'eps:SYM = 0)
                        Inte: TAY('eps::SYM) := integrate(tay, 'sigma::SYM)
                        reduce(_+, [coefficient(Inte, n) * ('eps::SYM::EXPR)^n for n in 0..maxpow()])

                del_sigma(e: EXPR): UPLY('eps::SYM) ==
                        simplify(subst(e, 'sigma::SYM = 2*%pi) / (2*%pi))

                tau1_m_sigma(): EXPR ==
                        integrand: EXPR := sqrt(1 + 'k2::SYM::EXPR * sin('sigma::SYM::EXPR)^2)
                        I1_truncated: EXPR := trunc_taylor_integral(integrand,
                                                                          1 - 'eps::SYM::EXPR)
                        A1: UPLY('eps::SYM) := del_sigma(I1_truncated)
                        tau1: EXPR := I1_truncated / A1::EXPR
                        tau1 - 'sigma::SYM::EXPR

EDIT: the error is the same with this change:

                trunc_taylor_integral(integrand: EXPR, factor: EXPR): EXPR ==
                        subs_eq: Equation(EXPR) := 'k2::SYM::EXPR = 4 * 'eps::SYM::EXPR /
                                                                     (1 - 'eps::SYM::EXPR)^2
                        inte: EXPR := subst(integrand, subs_eq) * factor
                        terms: L(EXPR) := [coefficient(taylor(inte, 'eps:SYM = 0), n) *
                                             ('eps::SYM::EXPR)^n for n in 0..maxpow()]
                        tay: EXPR := reduce(_+, terms)
                        integrate(tay, 'sigma::SYM)

Use of Unions in SPAD

I have a couple of questions about how it is supposed to be...

  1. Unions without selectors.
    I have a code like
myFunc : Union(Integer, String) -> ...
myFunc x ==
    x case Integer => ...

and here I want to use x knowing that it is actually Integer. If I try to write something like x + 1, the compiler complains that it can not perform addition with type Union(Integer, String). The only way I found to convince the compiler that x is Integer is x pretend Integer. But from my understanding of how pretend works, this should not be the preferred way: the compiler does not check that x is actually Integer, it just believes me; with same success I could write x pretend Group. As far as I understand, pretend is an analog of (type)var casting from C.
So, the question is: how do I say to compiler, that I have already checked, that x is an Integer and not String, without using hacks?

  1. Unions with selectors.
    This is the continuation of previous. I hoped that probably the answer is to use unions with selectors.
myFunc : Union(int : Integer, str : String) -> Integer
myFunc x ==
    x case int  => x.int + 1
    ...

Well, this does not cause errors. But how do I construct a value of such type?

mkUnion : Integer -> Union(int : Integer, str : String)
mkUnion n = n

causes

   compiling exported mkUnion : Integer -> Union(int: Integer,str: String)
****** comp fails at level 1 with expression: ******
error in function mkUnion 
(|n|)
****** level 1  ******
$x:= n
$m:= (Union (: int (Integer)) (: str (String)))
$f:=
((((|n| # #) (|mkUnion| #) (|myFunc| #) (|$DomainsInScope| # # #) ...)))
   >> Apparent user error:
   Cannot coerce n 
      of mode (Integer) 
      to mode (Union (: int (Integer)) (: str (String))) 

I looked up in "the FriCAS book", but there are no examples of constructing such unions, only an example of usage...

emacs (efricas) won't start fricas

When starting efricas, I've got an error message in emacs :
fricas-run: wrong number of arguments ( 3 . 3 ) , 4
My emacs version is 28.1 in Archlinux (Manjaro).
Fricas 1.3.7 is prebuilt in the distribution.

Regards,
Xavier

iterate keyword in .spad files

In section 5.4.6 "iterate in Loops" of the FriCAS User Guide I read about a keyword
iterate
which seemingly perfectly works in a FriCAS session, but does not compile in a .spad file.
Example attached.

Ralf

******** Spad syntax error detected ********
The prior line was:

    8>       for i in 1..9 repeat

The current line is:

    9>           odd? i => iterate


The number of valid tokens is 1.
The prior token was #S(TOKEN
                       :SYMBOL =>
                       :TYPE KEYWORD
                       :NONBLANK NIL
                       :LINE_NUM 8
                       :CHAR_NUM 17)
The current token is #S(TOKEN
                        :SYMBOL ITERATE
                        :TYPE KEYWORD
                        :NONBLANK NIL
                        :LINE_NUM 8
                        :CHAR_NUM 20)
-- foo.spad --
)abbrev package FOO Foo
Foo: with
  foo: () -> Integer
  bar: () -> Void()
 == add
  foo(): Integer ==
    z: Integer := 0
    for i in 1..9 repeat
      odd? i => iterate
      z := z+i
    z

  bar(): Void ==
    i: Integer := 0
    repeat
      i := i + 1
      if i > 5 then break
      if odd?( i ) then iterate
      output ( i )

multiple rules with the same LHS but with different predicates get merged nonsensically

Initially after reading the manual section on predicates in rules, I expected that I will be able to specify Rulesets so that rules in the Ruleset can match different patterns depending on their predicates. This is obviously wrong, however, there also seem to be some bugs.

Consider this:

(1) -> )read testreduce.input
sum_rule_1 := rule
  sin(X)^(Y | even?(Y)) == sum(cos(n * X), n = 1..Y)
  sin(X)^(Y | odd?(Y))  == sum(sin(n * X), n = 1..Y)


                      Y                           Y
               Y     --+                   Y     --+
   (1)  {sin(X)  ==  >     cos(X n), sin(X)  ==  >     sin(X n)}
                     --+                         --+
                    n = 1                       n = 1
                           Type: Ruleset(Integer,Integer,Expression(Integer))

sum_rule_2 := rule
  sin(X)^(Y | odd?(Y))  == sum(sin(n * X), n = 1..Y)
  sin(X)^(Y | even?(Y)) == sum(cos(n * X), n = 1..Y)


                      Y                           Y
               Y     --+                   Y     --+
   (2)  {sin(X)  ==  >     sin(X n), sin(X)  ==  >     cos(X n)}
                     --+                         --+
                    n = 1                       n = 1
                           Type: Ruleset(Integer,Integer,Expression(Integer))

sum_rule_3 := rule
  sin(X)^(Y | integer?(Y) and even?(integer(Y))) == sum(cos(n * X), n = 1..Y)
  sin(X)^(Y | integer?(Y) and odd?(integer(Y)))  == sum(sin(n * X), n = 1..Y)


                      Y                           Y
               Y     --+                   Y     --+
   (3)  {sin(X)  ==  >     cos(X n), sin(X)  ==  >     sin(X n)}
                     --+                         --+
                    n = 1                       n = 1
                           Type: Ruleset(Integer,Integer,Expression(Integer))
(4) -> sum_rule_1(sin(z)^2)

   (4)  sin(2 z) + sin(z)
                                                    Type: Expression(Integer)
(5) -> sum_rule_1(sin(z)^3)

              3
   (5)  sin(z)
                                                    Type: Expression(Integer)
(6) -> sum_rule_2(sin(z)^2)

   (6)  cos(2 z) + cos(z)
                                                    Type: Expression(Integer)
(7) -> sum_rule_2(sin(z)^3)

              3
   (7)  sin(z)
                                                    Type: Expression(Integer)
(8) -> sum_rule_3(sin(z)^2)

   (8)  sin(2 z) + sin(z)
                                                    Type: Expression(Integer)
(9) -> sum_rule_3(sin(z)^3)

              3
   (9)  sin(z)
                                                    Type: Expression(Integer)

Each of the three Rulesets has two rules whose left-hand sides are the same except for the predicates. It seems that what happens in each of the three cases is that Fricas merges the two rules in such a way that the predicate of the first rule and the right-hand side of the second rule are kept. This is unintuitive to such a degree that it seems impossible for someone to expect that behavior, so it should probably be considered a bug.

But there's more inconsistency:

(1) -> )read rules_predicates.input
my_rule := rule
  sin(X)^(Y | integer?(Y) and ((integer(Y) rem 3) = 0)@Boolean) == exp_mod_3_is_0
  sin(X)^(Y | integer?(Y) and ((integer(Y) rem 3) = 1)@Boolean) == exp_mod_3_is_1
  sin(X)^(Y | integer?(Y) and ((integer(Y) rem 3) = 2)@Boolean) == exp_mod_3_is_2


              Y
   (1)  sin(X)  == exp_mod_3_is_2
                       Type: RewriteRule(Integer,Integer,Expression(Integer))
(2) -> my_rule(sin(z)^2)

   (2)  exp_mod_3_is_2
                                                    Type: Expression(Integer)
(3) -> my_rule(sin(z)^3)

   (3)  exp_mod_3_is_2
                                                    Type: Expression(Integer)
(4) -> my_rule(sin(z)^4)

   (4)  exp_mod_3_is_2
                                                    Type: Expression(Integer)

In this case only the last RHS counts again, but the predicates are altogether eliminated.

There seem to be many possible approaches to fixing this:

  1. Add some clarifications to the manual.
  2. Disallow multiple rules with the same LHS in a Ruleset. This makes Rulesets less powerful than expected, but at least there will be no unexpected behavior.
  3. Make multiple rules with the same LHS but different predicates behave as expected. So my_rule(sin(z)^3) would equal exp_mod_3_is_0 and my_rule(sin(z)^4) would equal exp_mod_3_is_1.

BTW, I guess that a partial workaround for when rules with different predicates but same LHS are required is to put them in different Rulesets. But this would get messy fast and I think that it's less powerful altogether.

Update INSTALL instructions

The INSTALL instructions are rather stale and could use house cleaning. For instance, it refers to SVN, whereas development has moved to GitHub. In my personal optinion, the instructions could also be moved to Markdown for improved readability and nice sectioning.

RecurrenceOperator trouble: eval does not stick

Suppose we do:

l := [44, 178, 412, 746, 1168, 1669, 2260, 2941, 3712, 4573, 5524, 6565]
e := guess(l).1

Now we have a recurrence, with its 'n as its variable. Now if I do this:

e := eval(e, 'n, 'z)

The variable is seemingly changed to 'z. But, if I then do this:

e := getEq(e)$RecurrenceOperator(Integer, Expression Integer)

The variable is 'n again.

Proposal: decimal floating point

I prototyped a domain implementing "decimal floating point" with very basic arithmetics, which is similar to REXX's one and Java's BigDecimal class, and I've taken some advices from the paper http://www.speleotrove.com/decimal/IEEE-cowlishaw-arith16.pdf.

See also http://fricas-wiki.math.uni.wroc.pl/167InfiniteFloatsDomain

Many functions are just reused from the original Float domain, with base changed to decimal from binary accordingly.

One feature of decimal float over binary is the printed representation (is supposed to be) exactly matches the internal one. no more 1.2-1.1 ~= 0.1.

(1) -> a := float(12,-1)$Decimal

   (1)  12E-1
                                                                Type: Decimal
(2) -> b := float(11,-1)$Decimal

   (2)  11E-1
                                                                Type: Decimal
(3) -> c := float(1,-1)$Decimal 

   (3)  1E-1
                                                                Type: Decimal
(4) -> (a - b = c)@Boolean

   (4)  true
                                                                Type: Boolean
(5) -> (1.2 - 1.1 = 0.1)@Boolean

   (5)  false
                                                                Type: Boolean

It should be easy to port other subroutines from Float to this one. We can discuss about adding things like more rounding modes.

)abbrev domain DECIMAL Decimal

B ==> Boolean
I ==> Integer
S ==> String
PI ==> PositiveInteger
RN ==> Fraction Integer
SF ==> DoubleFloat
N ==> NonNegativeInteger

++ Author: LdBeth
++ Date Created: November 2021
++ Basic Operations:
++ Keywords: float, floating point, number, decimal
++ Description: \spadtype{Decimal} implements arbitrary precision floating
++ point arithmetic.
Decimal():
 Join(FloatingPointSystem,
      ConvertibleTo InputForm,
      arbitraryPrecision, arbitraryExponent)
  == add
   Rep := Record( mantissa : I, exponent : I )

   DIGS : PI := 20
   inc ==> increasePrecision
   dec ==> decreasePrecision
   LENGTH(n) ==> ilog10p1(n)

   -- local utility operations
   ilog10p1 : I -> I    -- integer log10 plus 1
   chop : (%, PI) -> %            -- chop x at p bits of precision
   power : (%, I) -> %            -- x ^ n with chopping
   plus : (%, %) -> %             -- addition with no rounding
   sub : (%, %) -> %              -- subtraction with no rounding
   negate : % -> %                -- negation with no rounding
   times : (%, %) -> %            -- multiply x and y with no rounding
   dvide : (%, %) -> %            -- divide x by y with special normalizing
   ceillog10base2 : PI -> PI      -- rational approximation

   ilog10p1(x) ==
      i : N := (4004 * ((length(x)$I)-1) quo 13301) :: N
      n : I := abs(x) quo (10^i)$I
      while n > 0 repeat
        n := n quo 10
        i := i + 1
      i

   chop(x, p) ==
      e : I := LENGTH x.mantissa - p
      if e > 0 then x := [(x.mantissa quo (10^e::N)), x.exponent+e]
      x
   float(m, e) == [m, e]
   float(m, e, b) ==
      m = 0 => 0
      inc 1; r := m * [b, 0] ^ e; dec 1
      round r
   order(a) == LENGTH(a.mantissa) + a.exponent - 1
   ceillog10base2 n == ((13301 * n + 4003) quo 4004) :: PI
   digits() == DIGS
   digits(n) == (t := DIGS; DIGS := n; t)
   precision() == digits()
   precision(n) == digits(n)
   bits() == 1 + ceillog10base2 digits()
   bits(n) == (t := bits(); digits (max(1, 4004 * (n-1) quo 13301)::PI); t)
   increasePrecision n == (b := digits(); digits((b + n)::PI); b)
   decreasePrecision n == (b := digits(); digits((b - n)::PI); b)
   round x ==
      m := x.mantissa
      m = 0 => 0
      e := LENGTH m - digits()
      if e > 0 then
         y := m quo 10^((e-1)::N) +5
         y := y quo 10
         if LENGTH y > digits() then
            y := y quo 10
            e := e+1
         x := [y, x.exponent+e]
      x


   0 == [0, 0]
   1 == [1, 0]
   base() == 10
   mantissa x == x.mantissa
   exponent x == x.exponent
   one? a == a = 1
   zero? a == zero?(a.mantissa)
   negative? a == negative?(a.mantissa)
   positive? a == positive?(a.mantissa)

   x = y ==
      x.exponent = y.exponent =>
          x.mantissa = y.mantissa
      order x = order y and sign x = sign y and zero? (x - y)
   x < y ==
      y.mantissa = 0 => x.mantissa < 0
      x.mantissa = 0 => y.mantissa > 0
      negative? x and positive? y => true
      negative? y and positive? x => false
      order x < order y => positive? x
      order x > order y => negative? x
      negative? (x-y)

   abs x == if negative? x then -x else round x
   sign x == sign x.mantissa

   - x == negate x
   negate x == [-x.mantissa, x.exponent]
   x + y == round plus(x, y)
   x - y == round plus(x, negate y)
   plus(x, y) ==
      mx := x.mantissa; my := y.mantissa
      mx = 0 => y
      my = 0 => x
      ex := x.exponent; ey := y.exponent
      ex = ey => [mx+my, ex]
      de := ex + LENGTH mx - ey - LENGTH my
      de > digits()+1 => x
      de < -(digits()+1) => y
      if ex < ey then (mx, my, ex, ey) := (my, mx, ey, ex)
      mw := my + mx * (10^(ex-ey)::N)
      [mw, ey]

   x : % * y : % == round times(x, y)
   x : I * y : % ==
      if LENGTH x > digits() then round [x, 0] * y
      else round [x * y.mantissa, y.exponent]
   x : % / y : % == dvide(x, y)
   x : % / y : I ==
      if LENGTH y > digits() then x / round [y, 0] else x / [y, 0]

   times(x : %, y : %) == [x.mantissa * y.mantissa, x.exponent + y.exponent]
   dvide(x, y) ==
      (q, r) := divide(x.mantissa, y.mantissa)
      if r = 0 then
         [q, x.exponent - y.exponent]
      else
         ew :I := digits() + 1
         mw := (r * 10^(ew::N)) quo y.mantissa
         -- possible to use binary search for optimization
         while (mw rem 10) = 0 repeat
            mw := mw quo 10
            ew := ew - 1
         [q, x.exponent - y.exponent] +
           [mw, x.exponent - y.exponent - ew]
   power(x, n) ==
      y : % := 1; z : % := x
      repeat
         if odd? n then y := chop( times(y, z), digits() )
         if (n := n quo 2) = 0 then return y
         z := chop( times(z, z), digits() )

   x : % ^ n : I ==
      x = 0 =>
         n = 0 => 1
         n < 0 => error "division by 0"
         0
      n = 0 => 1
      n = 1 => x
      x = 1 => 1
      p := LENGTH(n) + 2
      inc p
      y := power(x, abs n)
      if n < 0 then y := dvide(1, y)
      dec p
      round y

   --very basic formating
   convert(f) : S ==
     concat(concat(convert(mantissa f)@S, "E"), convert(exponent f)@S)

   coerce(f) : OutputForm ==
     message(convert(f)@S)

Polynomial ring QQ[x] not recognized as euclidean domain

(bear with me, I am not an expert in Fricas at all)

I am surprised by the following

fricas: Polynomial(Fraction(Integer)) has EUCDOM
false

Is there a way to let Fricas know that univariate polynomials over QQ form an euclidean domain ?

Motivation: I would like to apply smith() to matrices with such coefficients. This currently fails:

fricas: x:=x::Polynomial(Fraction(Integer))
x
fricas: m:=matrix([[4,3],[2,x]])
   +4  3+
   |    |
   +2  x+
fricas: smith(m)
There are 1 exposed and 1 unexposed library operations named smith 
      having 1 argument(s) but none was determined to be applicable. Use 
      HyperDoc Browse, or issue
                               )display op smith
      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 smith 
      with argument type(s) 
                     Matrix(Polynomial(Fraction(Integer)))
      
      Perhaps you should use "@" to indicate the required return type, or 
      "$" to specify which version of the function you need.

Move host Lisp config into separate file

We should move the configuration of the host Lisp into a separate file. Right now, there are random configurations of the host Lisp located in several files, like fricas-package.lisp and fricas-lisp.lisp.

PR #46 creates this file, and does some of the work to move configuration, but not all. There's remaining configuration at the top of fricas-lisp.lisp.

xvfb-run not working (cannot build remotely)

Hi. I am compiling from source, on Fedora GNU/Linux (F33, F34 beta), on a remote machine. The build is stuck at

...
unset DAASE; HTPATH=.; export HTPATH; \
  FRICAS_INITFILE='' xvfb-run -a -n 0 -s '-screen 0 1024x768x24' /home/waldmann/software/cas/fricas/target/x86_64-linux-gnu/bin/sman -noihere -paste coverex.ht
...
parsing: Menuexplot2d
writing:	draw(sin(tan(x)) - tan(sin(x)),x = 0..6)
Invalid MIT-MAGIC-COOKIE-1 keyCould not open the display.
viewman could not read from a 2D viewport window
code=-1
ack=0

I can fix that with

diff --git a/configure.ac b/configure.ac
index fc49c423..b4dccaa8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -731,7 +731,7 @@ if test x"$fricas_has_xpm" = xyes; then
                     AC_CHECK_PROGS([XVFB_RUN], [xvfb-run])
                     if test -n "$XVFB_RUN"; then
                         MAYBE_VIEWPORTS=viewports
-                        XVFB="xvfb-run -a -n 0 -s '-screen 0 1024x768x24'"
+                        XVFB="xvfb-run -a -s '-screen 0 1024x768x24'"
                     else
                         AC_MSG_NOTICE([HyperDoc graphics must be built separately.])
                     fi

Solution of polynomial equations in complex numbers in exponential notation?

Hello.
I'm trying to use solve or radicalSolve to obtain all solutions of polynomial equations:

(1) -> solve(x^5 + 1 = 0, x)

                 4    3    2
   (1)  [x= - 1,x  - x  + x  - x + 1= 0]
                          Type: List(Equation(Fraction(Polynomial(Integer))))

As far as I understand, what it says is that the only integer root is -1. Okay.

(2) -> radicalSolve(x^5 + 1 = 0, x)

   (2)
   [
     x =
           -
                2
             *
                ROOT
                                 ┌───────────────────┐2
                                 │     ┌─┐      ┌───┐
                                 │- 25\│3  + 45\│- 5
                           - 36  │───────────────────
                                3│          ┌─┐
                                \│       54\│3
                         + 
                                 ┌───────────────────┐
                                 │     ┌─┐      ┌───┐
                                 │- 25\│3  + 45\│- 5
                           - 30  │─────────────────── - 40
                                3│          ┌─┐
                                \│       54\│3
...

Oh, what is that? :) As far as I understand, this is how five roots of -1 are expressed in radicals in integer numbers. In hope of finding simpler answers, I also tried

(3) -> radicalSolve((x^5 + 1 = 0) :: Equation Polynomial Complex Fraction Integer, x)

   (3)
   [
     x =
           -
                2
             *
                ROOT
                                   ┌─────────────────┐2      ┌─────────────────┐
                                   │     ┌─┐      ┌─┐        │     ┌─┐      ┌─┐
                                   │45%i\│5  - 25\│3         │45%i\│5  - 25\│3
                             - 36  │─────────────────  - 30  │─────────────────
                                  3│         ┌─┐            3│         ┌─┐
                                  \│      54\│3             \│      54\│3
                           + 
                             - 40
                      *
                        ┌─────────────────────────────────────────────────────┐
                        │    ┌─────────────────┐2      ┌─────────────────┐
                        │    │     ┌─┐      ┌─┐        │     ┌─┐      ┌─┐
                        │    │45%i\│5  - 25\│3         │45%i\│5  - 25\│3
                        │36  │─────────────────  - 15  │───────────────── + 40
                        │   3│         ┌─┐            3│         ┌─┐
                        │   \│      54\│3             \│      54\│3
                        │─────────────────────────────────────────────────────
                        │                    ┌─────────────────┐
                        │                    │     ┌─┐      ┌─┐
                        │                    │45%i\│5  - 25\│3
                        │                36  │─────────────────
                        │                   3│         ┌─┐
                       \│                   \│      54\│3
                     + 
...

Now it uses %i, which is a bit nicer than sqrt(-1).

What I was hoping for was (as in Maxima):

(%i1) solve(x^5+1=0, x);
               2 %i %pi          4 %i %pi            4 %i %pi
               --------          --------          - --------
                  5                 5                   5
(%o1) [x = - %e        , x = - %e        , x = - %e          , 
                                                             2 %i %pi
                                                           - --------
                                                                5
                                                   x = - %e          , x = - 1]

So the question is: is there a special way of involving solve / radicalSolve to obtain solutions in such simple form? Or maybe there is a separate function for that?

debian packaging

maybe we can use this issue to coordinate the debian packaging?

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=570362
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=570366
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=890525 (merging)
are merged, but archived:

bts unarchive 570362
bts retitle 570362 "ITP: fricas -- an advanced computer algebra system"

need be run to let know others the one running these commands will do the packaging...

i have a building package in the 2019/ subdir at
http://phd-sid.ethz.ch/debian/fricas/
if someone can test it?

Proposal: Write Boot compiler in Lisp

I was reading through the Boot code and trying to understand it. According to the Makefile documentation and the source structure, it looks like the Boot compiler is written in Boot, and at some point it bootstrapped itself, and hence there's the boot/compiled/* files.

I propose that this initial Boot compiler just remains in Common Lisp so that it can continue to be easily bootstrapped. My specific qualm is that I wanted to fix a bug, namely that the Boot compiler generates

(EVAL-WHEN (EVAL LOAD) ...)

which ought to be replaced with

(EVAL-WHEN (:EXECUTE :LOAD-TOPLEVEL) ...)

(This change is one of the many culprits of voluminous and noisy warnings during build.)

To do this, I had to either:

  1. manually edit the compiled/* code by hand, or
  2. rewrite the requisite .boot file, figure out how to regenerate the compiled/* directory with an existing Boot compiler, then regenerate it again to make sure the new bootstrapped changes make it in.

The Makefile documentation suggests Boot is somehow better than Common Lisp because of the syntax. However, I think for specifically the bootstrapping of Boot, Common Lisp would be just fine.

Please note that I am not suggesting we replace all Boot code with Lisp. I am merely suggesting we port the relatively small amount of functionality as needed in boot/*.

Organize and document "portability functions"

There are lots of places in the source code where "portability functions" are defined. For instance, in nlib.lisp, the function COPY-LIB-DIRECTORY is defined for most supported Lisp compilers. I propose that these functions are collected and organized somewhere so that (1) non-portable code is segregated, (2) it's easier to port to a new lisp compiler.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.